Git's error messages are long but usually accurate. Three of them account for most panic.
1. "You are in 'detached HEAD' state"
What happened. HEAD normally points at a branch, and the branch points at a commit. When you check out a commit directly (an old hash, a tag, origin/main), HEAD points at the commit itself. Git tells you so:
Note: switching to '1deec24'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
Looking around is harmless. The risk is committing here and then leaving: those commits belong to no branch and can be lost. Git warns you when you switch away:
Warning: you are leaving 1 commit behind, not connected to
any of your branches:
55d8594 Work done while detached
To keep the work, give it a branch, now or at the warning:
git switch -c rescue-work # while still detached
git branch rescue-work 55d8594 # or later, using the hash from the warning
To discard it, just go back: git switch main. If you only wanted to look, that is all there is to it.
2. "! [rejected] main -> main (fetch first)"
What happened. Someone pushed to main after you last updated, so your history and the remote's have diverged. Git refuses to overwrite theirs:
! [rejected] main -> main (fetch first)
error: failed to push some refs to '<remote>'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. This is usually caused by another repository pushing to
hint: the same ref. If you want to integrate the remote changes, use
hint: 'git pull' before pushing again.
The fix is to bring their work in, then push:
git pull # merges their commits into yours
git push
If you prefer a straight history, git pull --rebase replays your commits on top of theirs instead of adding a merge commit. Either way you may meet a conflict, which is the next problem. Resist git push --force. It would make the push succeed by deleting the other person's commits from the remote.
3. "CONFLICT (content): Merge conflict"
What happened. You and someone else changed the same lines. Git merged everything it could and stopped on the rest:
Auto-merging app.txt
CONFLICT (content): Merge conflict in app.txt
Automatic merge failed; fix conflicts and then commit the result.
git status lists the file as UU (both modified), and the file now contains both versions between markers:
line 1
<<<<<<< HEAD
alice change
=======
bob change
>>>>>>> 05975ba9f2cb700b9f5012a04531e0d11c296e36
Between <<<<<<< HEAD and ======= is your version. Between ======= and >>>>>>> is theirs.
To resolve it:
- Open the file and decide what the lines should be: yours, theirs, both or something new.
- Delete the three marker lines. A file that still contains
<<<<<<<is not resolved. - Mark the file resolved and finish the merge:
git add app.txt
git commit
To give up and return to how things were before the pull, run git merge --abort.
Tips that prevent repeats: pull often so differences stay small, keep commits focused, and agree who edits generated or shared files.
Two more you will meet
- "Your local changes would be overwritten by checkout." Git is protecting uncommitted work. Commit it, or
git stashit, switch, andgit stash popto bring it back. - "Refusing to merge unrelated histories." The two histories have no common ancestor, usually because each side ran
git initseparately. Only if you are sure they belong together, add--allow-unrelated-histories.
A habit that helps
Before anything risky (a hard reset, a rebase, a big merge) run git branch backup. It is a bookmark of where you were, it costs nothing, and you can delete it later.
Troubleshooting
| Problem | Likely cause | Fix |
|---|---|---|
| You are in 'detached HEAD' state | You checked out a commit, tag or remote branch directly instead of a branch, so new commits belong to no branch. | To keep any work you did, run git switch -c <new-branch-name>. To discard it and go back, run git switch main (or git switch -). |
| ! [rejected] main -> main (fetch first) | The remote has commits you do not have locally, so your push would not be a simple fast-forward. | Run git pull (or git pull --rebase), resolve any conflicts, then push again. Do not force-push to a shared branch. |
| CONFLICT (content): Merge conflict in <file> | You and someone else changed the same lines, and Git cannot choose. | Open the file, edit between the <<<<<<< and >>>>>>> markers to what you want, remove the markers, git add the file and finish with git commit. |
| error: Your local changes to the following files would be overwritten by checkout | You have uncommitted changes in a file that differs on the branch you are switching to. | Commit the changes, or put them aside with git stash, switch, then git stash pop. |
| fatal: refusing to merge unrelated histories | The two branches share no common commit, often after an init in two places. | If you are sure they should be joined, use git pull --allow-unrelated-histories and resolve the result. |
Frequently asked questions
Is it safe to use git push --force?
On a branch only you use, yes, with care. On a shared branch it overwrites other people's work. If you must, use git push --force-with-lease, which refuses if the remote has changed since you last looked.
Merge or rebase when pulling?
Merging keeps the exact history and adds a merge commit. Rebasing replays your commits on top for a straighter line. Pick one per team and write it down.
References
From Grokem: https://www.grokem.com/programming/version-control/git-detached-head-and-rejected-push





