Overview
When Git says “error: You have unmerged files,” a merge or rebase created conflicts that must be resolved before Git can proceed. The fix is always: inspect conflicts, choose the correct content per file, stage the resolutions, then complete or abort the operation.
Quickstart (90 seconds)
- See what’s conflicted:
- git status
- git ls-files -u # detailed unmerged entries
- Open each conflicted file, resolve the <<<<<<<, =======, >>>>>>> markers.
- For each resolved file: git add <file>
- If you were merging: git commit
- If you were rebasing: git rebase --continue
- If you want to bail out:
- Merge: git merge --abort
- Rebase: git rebase --abort
Symptoms
- During merge: error: You have unmerged files; fix conflicts and then commit the result.
- During rebase: error: could not apply <commit>; resolve all conflicts manually, mark them as resolved with "git add <file>" and run "git rebase --continue".
- git status shows “both modified,” “both added,” “deleted by them/us,” or rename conflicts.
Why it happens
- Two branches changed the same lines or file operations (modify/rename/delete) in incompatible ways.
- Rebase replays commits atop a new base; conflicts arise where history diverges.
Minimal working example
This creates a conflict and resolves it both for merge and rebase.
# Start clean
mkdir demo-merge-rebase && cd demo-merge-rebase
git init -b main
echo "v1" > app.txt
git add app.txt && git commit -m "init app.txt v1"
# Branch and change the same line
git checkout -b feature
printf "v2-feature\n" > app.txt
git commit -am "feature: change app.txt"
git checkout main
printf "v2-main\n" > app.txt
git commit -am "main: change app.txt"
# 1) Merge path (conflict)
git merge feature || true # expect conflict
# Inspect
git status
# Resolve by choosing main’s version (ours) or feature’s (theirs)
# Option A: keep main version
git checkout --ours app.txt
# Option B: keep feature version (comment Option A and uncomment next line)
# git checkout --theirs app.txt
git add app.txt
git commit -m "merge: resolve conflict in app.txt"
# Reset repo to show rebase path
cd ..; rm -rf demo-merge-rebase
mkdir demo-merge-rebase && cd demo-merge-rebase
git init -b main
echo "v1" > app.txt
git add app.txt && git commit -m "init app.txt v1"
git checkout -b feature
printf "v2-feature\n" > app.txt
git commit -am "feature: change app.txt"
git checkout main
printf "v2-main\n" > app.txt
git commit -am "main: change app.txt"
# 2) Rebase path (conflict)
git checkout feature
git rebase main || true # expect conflict
# Resolve, then continue
git checkout --theirs app.txt # or --ours
git add app.txt
git rebase --continue
Example conflict markers you might see inside a file:
<<<<<<< HEAD
v2-main
=======
v2-feature
>>>>>>> feature
Edit the file to the intended content (remove the markers), then stage and continue.
Standard resolution workflow
- Identify conflicts
- git status
- git diff --name-only --diff-filter=U
- git ls-files -u
- Decide per file
- Keep one side entirely: git checkout --ours <path> or git checkout --theirs <path>
- Or merge manually: edit, remove markers, ensure code compiles/tests pass.
- Stage resolutions
- git add <path> for resolved files
- git rm <path> if you intentionally delete
- Complete the operation
- Merge: git commit
- Rebase: git rebase --continue
- Abort if needed
- Merge: git merge --abort
- Rebase: git rebase --abort
Tip: Prefer resolving file-by-file rather than git add -A to avoid accidental staging.
Handling common conflict types
- Both modified (same file): edit or choose ours/theirs, then git add.
- Delete/modify:
- Keep deletion: git rm <file>
- Keep modification: git checkout --theirs <file> (or --ours) && git add <file>
- Both added (same path): rename one file or combine contents, then git add.
- Rename/rename: choose the final name, git mv as needed, resolve contents, git add.
- Binary file conflict: choose one side entirely: git checkout --ours <bin> or --theirs <bin>; then git add.
Rebase-specific notes
- To skip the problematic commit (rarely recommended): git rebase --skip
- View rebase todo: git rebase --edit-todo
- If you’re unsure, abort safely: git rebase --abort
Useful configuration
# Show base context in conflicts (helps manual merges)
git config --global merge.conflictStyle diff3
# Remember and auto-apply past resolutions
git config --global rerere.enabled true
# Prefer rebase on pull for linear history (optional)
git config --global pull.rebase true
Pitfalls and how to avoid them
- Using reset or checkout to discard without thinking
- git reset --hard will drop uncommitted work. Only use when you’re certain.
- Staging unresolved markers
- Always search for <<<<<<< and >>>>>>> after editing.
- Accidental mass “theirs”/“ours”
- Review changes with git diff before git add.
- Conflicts hidden by CRLF differences
- Set consistent line endings: git config core.autocrlf input (or true on Windows) and use .gitattributes.
- Submodule conflicts
- Resolve by checking out the desired submodule commit, then git add <submodule-path>.
Performance notes (large repos/monorepos)
- Limit scope while resolving
- Use git status -uno to skip untracked scanning.
- Resolve a subset: git add <dir>/ to stage directory-by-directory.
- Sparse checkout for focused work
- git sparse-checkout init --cone && git sparse-checkout set <dirs>
- Speed up repeated merges
- Enable rerere to auto-apply known resolutions.
- Avoid expensive tools on each file change
- Temporarily disable heavy pre-commit hooks; re-enable after merge.
Verification checklist
- git status shows no unmerged paths.
- Tests build/run successfully.
- For rebase, log is linear and expected: git log --oneline --graph --decorate.
- No leftover conflict markers: git grep -nE '^(<<<<<<<|=======|>>>>>>>)' || true
Tiny FAQ
Q: Can I resolve everything by taking one side globally?
- A: Sometimes. For merge: git checkout --theirs . (or --ours .) then review diffs, run tests, commit. Use with caution.
Q: I resolved conflicts but Git still complains.
- A: Ensure all conflicted paths are staged (git add). Check with git diff --name-only --diff-filter=U.
Q: How do I see which commits caused the conflict during rebase?
- A: git status shows the commit; use git log -p --merge or review the commit in the rebase todo.
Q: Can I use a GUI merge tool?
- A: Yes. Configure one (e.g., meld, kdiff3) via git mergetool; it will mark resolved files for you.
Q: Is --ours/--theirs inverted during rebase?
- A: During merge, ours = current branch, theirs = merging branch. During rebase, ours = the rebased commit, theirs = the upstream/base you’re rebasing onto.