unfuck-my-git-state
Diagnose and recover broken Git state and worktree metadata with a staged, low-risk recovery flow. Use when Git reports detached HEAD, phantom worktree locks, orphaned entries, missing refs, or branch
SKILL.mdplugins/unfuck-my-git-state/skills/unfuck-my-git-state/SKILL.md
GitHubunfuck-my-git-state
Recover a repo without making the blast radius worse.
Core Rules
- Snapshot first. Do not "just try stuff."
- Prefer non-destructive fixes before force operations.
- Treat
.git/as production data until backup is taken. - Use
git symbolic-refbefore manually editing.git/HEAD. - After each fix, run verification before proceeding.
Playbook A: Orphaned Worktree Metadata
Symptoms: git worktree list shows a path that no longer exists; invalid or zero hashes.
git worktree list --porcelain
git worktree prune -v
git worktree list --porcelain
If stale entries remain, back up .git/ and remove the specific stale folder under .git/worktrees/<name>, then rerun prune.
Playbook B: Phantom Branch Lock
Symptoms: git branch -d fails with "already used by worktree".
git worktree list --porcelain
Find the worktree using that branch, switch that worktree to another branch or detach HEAD there, then retry.
Playbook C: Detached or Contradictory HEAD
Symptoms: git status says detached HEAD unexpectedly.
git symbolic-ref -q HEAD || true
git reflog --date=iso -n 20
git switch <known-good-branch>
# or create rescue branch:
git switch -c rescue/$(date +%Y%m%d-%H%M%S)
Playbook D: Missing or Broken Refs
Symptoms: unknown revision, not a valid object name, cannot lock ref.
git fetch --all --prune
git show-ref --verify refs/remotes/origin/<branch>
git branch -f <branch> origin/<branch>
git switch <branch>
Last Resort: Manual HEAD Repair
Only after backup of .git/.
git show-ref --verify refs/heads/<branch>
git symbolic-ref HEAD refs/heads/<branch>
# fallback:
echo "ref: refs/heads/<branch>" > .git/HEAD
Verification Gate (Must Pass)
git statusexits cleanly with no fatal errors.git symbolic-ref -q HEADmatches intended branch.git worktree list --porcelainhas no missing paths and no zero hashes.git fsck --no-reflogs --fullhas no new critical errors.
Escalation Path
tar -czf git-metadata-backup-$(date +%Y%m%d-%H%M%S).tar.gz .git
# Clone fresh from remote, recover with reflog + cherry-pick