Resolving rename and delete conflicts Jump to heading
Content conflicts are the familiar kind: both sides edited the same lines. Tree conflicts are stranger. One side deleted a file the other side edited. Both sides renamed the same file to different names. One side moved a directory while the other added a file inside it. Git reports these with terse labels — CONFLICT (modify/delete), CONFLICT (rename/rename) — and leaves the working tree in a state that looks like nothing is wrong, because there may be no conflict markers at all. Resolving them means deciding which structural change wins and making sure the other side’s edits are not silently dropped. This page goes through each kind, within 3-way merge fundamentals.
When to use this approach Jump to heading
- A merge, rebase or cherry-pick reports
modify/delete,rename/delete,rename/renameorrename/add. git statusshows files as “deleted by us”, “deleted by them”, “both added” or “added by them”.- A refactor moved files while other branches were still editing them, as in coordinating a large refactor without conflict storms.
- Edits seem to have disappeared after a merge that involved renames.
Step 1 — Read the status codes, not just the message Jump to heading
git status --short gives a two-letter code per conflicted path. The letters tell you what each side did.
git status --short | grep -E '^(DD|AU|UD|UA|DU|AA|UU)' Two details trip people up. In a rebase, “us” is the branch you are rebasing onto and “them” is your commit, so the letters read backwards from what you expect. And Git’s rename detection decides whether something is reported as rename/delete or as a separate delete and add, which depends on how similar the files are.
Step 2 — Resolve modify/delete: decide whether the file should exist Jump to heading
One side deleted the file; the other changed it. Git keeps the modified version in the working tree so nothing is lost, and waits for you to choose.
# See what the modifying side changed, relative to the base
git log --oneline -3 MERGE_HEAD -- src/legacy/importer.py
git diff "$(git merge-base HEAD MERGE_HEAD)" MERGE_HEAD -- src/legacy/importer.py
# Option A: the deletion wins — confirm the edit is not needed elsewhere first
git rm src/legacy/importer.py
# Option B: the file survives with the edit
git add src/legacy/importer.py The dangerous outcome is Option A without reading the diff: the other side’s edit may have been a bug fix that needs to be carried to wherever the functionality moved. If the file was deleted because its code moved, apply the edit to the new location before removing the old file.
# Verification: no paths remain in a conflicted state
git diff --name-only --diff-filter=U Step 3 — Resolve rename/delete and rename/modify Jump to heading
When one side renamed a file and the other edited it, Git usually handles it automatically: rename detection matches the old and new paths and applies the edit to the new name. When one side renamed and the other deleted, Git reports a conflict and leaves the renamed file in place.
# Rename detection threshold: lower it when files were renamed and heavily edited together
git merge -X find-renames=40% feature/reorg
# Inspect how Git paired paths
git diff --name-status -M40% "$(git merge-base HEAD MERGE_HEAD)" MERGE_HEAD | grep '^R' A rename that Git failed to detect looks like one side deleting a file and adding an unrelated one. Lowering the similarity threshold lets Git pair them, which turns a confusing delete/add into a rename it can merge edits through.
Step 4 — Resolve rename/rename: one file, two new names Jump to heading
Both sides renamed the same file to different paths. Git keeps both new paths in the working tree with the merged content and asks you to pick.
git status --short
# AU src/core/parser.py (ours renamed old_parser.py here)
# UA src/parsing/parser.py (theirs renamed it here)
# Keep one location, remove the other, and make sure imports match
git rm --cached src/parsing/parser.py && rm src/parsing/parser.py
git add src/core/parser.py
git grep -n 'parsing.parser' -- '*.py' # fix references that assumed the other location Rename/rename conflicts almost always mean two people reorganised the same area independently. The code choice is easy; the conversation about which layout the project wants is the real resolution.
Step 5 — Recover an edit lost in a structural resolution Jump to heading
If you suspect an edit vanished because a file was resolved as deleted, the edit still exists in the commit that made it. Find it and reapply it to the surviving location.
# Commits on the merged branch that touched the old path
git log --oneline "$(git merge-base HEAD^1 HEAD^2)..HEAD^2" -- src/legacy/importer.py
# Re-apply a specific change to the new location with a path-rewritten patch
git format-patch -1 <sha> --stdout -- src/legacy/importer.py |
sed 's#src/legacy/importer.py#src/ingest/importer.py#g' | git apply -3 Validation checklist Jump to heading
Frequently Asked Questions Jump to heading
Why are there no conflict markers in a modify/delete conflict? Jump to heading
There is nothing to mark: one side has no content at all. Git leaves the surviving version in the working tree and records the conflict in the index. git status is the only clear signal.
Can I tell Git to always prefer deletions or always keep files? Jump to heading
git checkout --ours or --theirs works per path once you know which side you want, but there is no safe global rule. A blanket preference for deletions loses bug fixes; a blanket preference for keeping files resurrects code that was removed on purpose.
How does rename detection decide a file was renamed? Jump to heading
It compares deleted and added files and pairs those whose content is at least the threshold similar — fifty percent by default. Files renamed and heavily rewritten in the same commit fall below it, which is why committing a rename separately from its edits makes later merges far smoother.
Related Jump to heading
- 3-Way Merge Fundamentals — the parent topic.
- Ours and Theirs During Merge vs Rebase — reading the status letters correctly in a rebase.
- Structuring a Codebase to Reduce Merge Conflicts — avoiding reorganisation collisions.
- Choosing Between the ORT and Recursive Strategies — the strategy whose rename handling decides these cases.