cheat-sheets

Git Troubleshooting

Symptom-led fixes for “I did something wrong in Git, how do I get out?”. Find the error or situation, run the fix. Deeper versions of most fixes are in Git Recipes, and the basics are in Git. Inspired by Oh Shit, Git!?! by Katie Sylor-Miller.

Documentation: Git reference, Pro Git book

First Aid #

Before trying anything risky, make the situation recoverable.

COMMANDDESCRIPTION
git statusWhat state the repo is in, and what Git suggests doing next
git log --oneline --graph --all -20Where every branch points
git reflogEverything HEAD has done, newest first. Shows commits that no branch points to any more
git branch backup/<NAME>Bookmark the current commit so a later reset cannot lose it
git stash push -uPark uncommitted and untracked work (git stash pop brings it back)
git rebase --abort / git merge --abort / git cherry-pick --abortCancel a half-finished operation and return to how things were

Committed work is almost never lost, as the reflog keeps it for weeks. Uncommitted changes that were never staged or stashed are lost after reset --hard or git clean.

Time Machine (Reflog) #

Undo almost anything that was committed: a bad reset, rebase, merge or deleted branch.

bash
git reflog
# find the entry from before it went wrong, e.g. HEAD@{3}
git reset --hard HEAD@{3}

--hard discards uncommitted changes in tracked files. To keep the old state alongside the current one, make a branch instead: git branch rescue HEAD@{3}. More in Recover with the Reflog.

Fix the Last Commit #

SITUATIONFIX
Forgot a file or need one small changeMake the change, git add <FILE>, then git commit --amend --no-edit
Typo in the last commit messagegit commit --amend (or git commit --amend -m "<MESSAGE>")
Committed with the wrong author or emailgit commit --amend --reset-author
Want the commit undone but keep the workgit reset --soft HEAD~1 (changes stay staged) or git reset HEAD~1 (unstaged)
Want the commit and the work gonegit reset --hard HEAD~1 (destroys the changes)
Need to undo a commit from several commits agogit log --oneline, then git revert <COMMIT> (adds a new commit that undoes it)

--amend, reset and rebase rewrite history. Only use them on commits you have not pushed to a shared branch. After pushing, prefer git revert. If you rewrote a pushed commit on your own branch, use git push --force-with-lease, which refuses if someone else pushed in the meantime (plain --force does not).

Wrong Branch #

SITUATIONFIX
Committed to main, meant a new branch (not pushed)See below
Committed to the wrong existing branchgit switch <RIGHT_BRANCH>, git cherry-pick <COMMIT>, then remove it from the wrong branch with git switch <WRONG_BRANCH> and git reset --hard HEAD~1
Edited files on the wrong branch (uncommitted)git stash, git switch <RIGHT_BRANCH>, git stash pop

Commit on main that belongs on a new branch:

bash
git branch feature            # new branch at the current commit
git reset --hard origin/main  # put main back (drops the commit from main only)
git switch feature

This does not work once the commit is pushed to a shared branch. If you already tried other things first, check git reflog for the right commit to reset to instead of origin/main. More in Committed on the Wrong Branch.

Undo Changes to Files #

COMMANDDESCRIPTION
git restore <FILE>Discard unstaged edits to a file (cannot be undone)
git restore --staged <FILE>Unstage a file, keep the edits
git restore --source=<COMMIT> -- <FILE>Put the file back as it was in an older commit (unstaged edit)
git restore --source=<COMMIT> --staged --worktree -- <FILE>Same, and stage it ready to commit
git checkout <COMMIT> -- <FILE>Older equivalent of the above, stages the old version
git rm --cached <FILE>Stop tracking a file but keep it on disk
git clean -n -dDry run: list untracked files that git clean -f -d would delete

Nothing Happened #

SYMPTOMCAUSE AND FIX
git diff shows nothing but files changedThe changes are already staged. Use git diff --staged (also --cached)
git diff shows nothing for a new fileUntracked files are not diffed. git add -N <FILE> (intent to add) makes them appear
Edited .gitignore but a file is still trackedIgnoring only affects untracked files. git rm --cached <FILE> (or git rm -r --cached <DIR>), then commit
git status shows a file that is in .gitignoreSame cause. Check what matches with git check-ignore -v <FILE>
Renamed a file by case only and Git did not notice (macOS, Windows)git mv <old> <new> (on a case-insensitive disk, go via a temporary name)
Whole file shows as changedLine endings changed. Check git config core.autocrlf and use a .gitattributes file such as * text=auto
File mode changes everywheregit config core.fileMode false (common on shared Windows or WSL mounts)
Commit works but the author is wrongSet git config user.name "<NAME>" and git config user.email "<EMAIL>" for the repo, then amend

Detached HEAD #

HEAD points at a commit, not a branch, so new commits are not on any branch and are easy to lose. This happens after git checkout <COMMIT>, <TAG> or origin/<BRANCH>.

SITUATIONFIX
Just looking aroundgit switch - returns you to the previous branch
Made commits you want to keepgit switch -c <NEW_BRANCH> right now, they come with you
Already switched away and lost themgit reflog, find the commit, git branch rescue <SHA>
Rebase is stuck in a detached stategit rebase --abort, or fix the conflict and git rebase --continue

Push and Pull Errors #

ERRORFIX
! [rejected] ... (non-fast-forward) or fetch firstThe remote has commits you do not. git pull --rebase (or git pull), then push again
Push rejected after you amended or rebasedYou rewrote history. If the branch is yours: git push --force-with-lease. Never force-push a shared branch
fatal: The current branch <BRANCH> has no upstream branchgit push -u origin <BRANCH> (or git push --set-upstream origin HEAD)
fatal: refusing to merge unrelated historiesThe two histories share no commit. Only if that is intended: git pull --allow-unrelated-histories
fatal: Need to specify how to reconcile divergent branchesPick once: git config --global pull.rebase true (or pull.ff only, or false to merge)
error: Your local changes ... would be overwritten by merge/checkoutCommit or git stash first, then retry, then git stash pop
remote: error: File ... is larger than ... or pre-receive hook declinedA large file is in a commit. Remove it from history before pushing: git rm --cached <FILE> and git commit --amend if it is the last commit, otherwise see Remove a Committed Secret (same git filter-repo approach)
remote: Permission denied / Authentication failedWrong credentials or token expired. Check git remote -v, then see SSH
Pushed to the wrong remote or URLgit remote set-url origin <URL>, then git remote -v to check
remote rejected ... protected branchThe server forbids direct or force pushes to that branch. Open a PR with a new commit that reverts instead

Merge and Rebase Trouble #

SITUATIONFIX
Merge conflictgit status lists the files. Edit out the <<<<<<<, ======= and >>>>>>> markers, git add <FILE>, then git commit (merge) or git rebase --continue (rebase)
Take one side for a whole filegit checkout --ours -- <FILE> or git checkout --theirs -- <FILE>, then git add <FILE>. In a rebase the meaning swaps: --ours is the branch you are rebasing onto, --theirs is your own commit
Merge went wrong, not committed yetgit merge --abort
Merge went wrong and is already committed (not pushed)git reset --hard ORIG_HEAD, or pick a point from git reflog
Merge already pushedgit revert -m 1 <MERGE_COMMIT> (see the warning on re-merging in Undo and Fix Commits)
Same conflict again and again during a rebasegit config --global rerere.enabled true records and replays your resolutions
Rebase went wrong and is finishedgit reflog, find the entry before rebase (start), git reset --hard <ENTRY>
Lost track of which files conflictgit diff --name-only --diff-filter=U

Stash Trouble #

SITUATIONFIX
git stash pop had conflictsThe stash is kept, not dropped. Resolve the conflicts, then git stash drop
Dropped a stash by accidentgit fsck --no-reflogs --unreachable | grep commit, then git stash apply <SHA> or git branch rescue <SHA>
Forgot what is stashedgit stash list, then git stash show -p stash@{0}

Reset to Match the Remote #

Last resort when a local branch is beyond repair and you do not need its local work. These steps are destructive and unrecoverable for anything uncommitted or untracked.

bash
git fetch origin
git switch main
git branch backup/main-before-reset   # safety net: keeps your old commits reachable
git reset --hard origin/main
git clean -n -d                       # dry run first
git clean -f -d                       # delete untracked files and folders

Repeat for each broken branch. If it is still a mess, clone a fresh copy next to the old one and copy over only the files you need, rather than deleting the old directory straight away.

SSH and Authentication #

COMMANDDESCRIPTION
ssh -T git@github.comTest SSH access to GitHub (replace the host for other servers)
ssh -vT git@github.comSame, verbose, to see which key is offered
git remote -vCheck whether the remote uses HTTPS or SSH
git remote set-url origin git@github.com:<OWNER>/<REPO>.gitSwitch a remote from HTTPS to SSH
gh auth status / gh auth loginCheck or redo GitHub CLI authentication, see GitHub and the gh CLI
GIT_TRACE=1 GIT_CURL_VERBOSE=1 git <COMMAND>Show what Git is doing (may print tokens, redact before sharing)

More in OpenSSH Cheat-Sheet.

Repository Damage #

SYMPTOMFIX
fatal: not a git repositoryYou are outside a repo, or .git was removed. Check with git rev-parse --show-toplevel
fatal: bad object / error: object file ... is emptyCorrupt object. Run git fsck. If the remote has the data, the safest fix is a fresh git clone and copy over unpushed work
fatal: Unable to create '.git/index.lock': File existsA Git process crashed. Make sure no Git is running, then delete the lock: rm .git/index.lock
warning: refname 'X' is ambiguousA branch and a tag share a name. Delete or rename one
Repo is huge or slowgit count-objects -vH, git gc. See Sparse and Shallow Clones

See Also #

Search all sheets

Tip: / or Ctrl/Cmd+K to open, Esc to close.