← All Articles

Git Error Messages Explained: What Git Is Actually Telling You

At a Glance
! [rejected] failed to pushYou are in 'detached HEAD' statefatal: not a git repository

Git errors name the state and the next command usually appears verbatim in the output. Read the second half of the message — that's where the instruction is.

Push Rejected: "failed to push some refs"

! [rejected]        main -> main (fetch first)
error: failed to push some refs to 'github.com:you/repo.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally.

The situation: someone (or you, from another machine) pushed commits you don't have. Git refuses to overwrite them.

Fixes by intent: (1) normal case — integrate their work first: git pull --rebase then push; (2) you have nothing local worth keeping: git pull and push; (3) you deliberately want your version to replace theirs (solo branch, force is acceptable): git push --force-with-lease — the --with-lease variant refuses if the remote moved since your last fetch, which is what makes it safe-ish versus plain --force. Never force-push a shared branch (main, release) without team agreement — it deletes other people's commits from history, and they will notice at the worst time.

Diverged Branches: "have diverged"

hint: Your branch and 'origin/main' have diverged,
hint: and have 2 and 3 different commits each, respectively.

Both sides have unique commits. Choose a history shape: git pull --rebase (your commits replayed on top — linear history, the usual choice) or git pull (merge commit records the integration). The rebase option can hit conflicts commit-by-commit; the merge option hits them once. Either is correct; the anti-pattern is copy-pasting your files over theirs to make it stop.

Detached HEAD

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make...

What happened: you checked out a commit hash, a tag, or a remote branch directly — HEAD points at a commit, not a branch, so new commits belong to no branch.

Fixes: (1) just looking? git switch - returns to your previous branch; (2) made commits you want to keep: git switch -c rescue-branch creates a branch at the current commit — nothing is lost; (3) made commits you don't want: switch away and they become unreachable (recoverable via reflog for ~30 days). The rule: in detached HEAD, create a branch before doing real work.

Merge Conflicts

CONFLICT (content): Merge conflict in src/app.js
Automatic merge failed; fix conflicts and then commit the result.

The procedure: git status lists conflicted files (both modified); open each, resolve the markers (<<<<<<<, =======, >>>>>>>), keep the correct content, git add each resolved file, then git commit (or git rebase --continue if rebasing). Escape hatches: git merge --abort restores the pre-merge state — use it without shame when the conflict is bigger than expected; resolve from a clean state instead of mid-panic.

The habit that prevents most conflicts: pull/rebase at the start of work, keep branches short-lived, and never leave a feature branch unmerged for weeks.

"fatal: not a git repository"

You're outside a repo (or in a subdirectory of a repo whose .git was removed/broken). git status in the right directory confirms. The nested-repo variant: running git in a subdirectory that is its own repo, expecting the parent — git rev-parse --show-toplevel tells you which repo actually applies.

Other Frequent Messages

MessageMeaningFix
Please tell me who you areuser.name/user.email unsetgit config --global user.name "X" + email
nothing to commit, working tree cleanNot an error — no changes stagedStage with git add; check git status if you expected changes
Changes not staged for commitInformationalStage what you intend; review diff before committing
fatal: refusing to merge unrelated historiesTwo repos with no common ancestorgit pull --allow-unrelated-histories (know why before doing it)
error: Your local changes would be overwrittenCheckout/pull would clobber uncommitted workCommit, stash, or discard deliberately — never blindly
fatal: Authentication failedBad credentials / expired tokenUpdate PAT or SSH key; check the remote URL scheme
ssh: Permission denied (publickey)SSH key not offered/acceptedssh -T [email protected] to test; add key to agent
index.lock existsA git process died mid-operationConfirm no git process runs, then remove .git/index.lock

The Reflog: Your Safety Net

Almost every "I destroyed my work" story in Git ends with the reflog. git reflog lists every position HEAD has held — find the commit before the mistake and git reset --hard <hash> (or git cherry-pick specific commits from it). This works for: bad rebases, force-pull losses, deleted branches, reset --hard regret. The exceptions where it can't help: uncommitted changes that were never staged (they were never in git at all) — which is the honest argument for committing early, even messily.

Related Errors

Permission denied · Systematic debugging workflow