TT Lab
Get started
Learn Learning paths Courses

Git in Practice

Solving the Same Conflict for the Fourth Time

Continue in TT Lab

Goal

You see the common ancestor in the conflict markers, make git remember a resolution once solved, and check by content how -X ours and -s ours make the result file differ.

Why it matters

Resolving a conflict is not a technique but a judgment. But the default conflict marking leaves out one piece of information needed for the judgment — what it originally was. If you do not know that, you cannot distinguish "one side deleted it" from "both sides changed it differently", and if you choose wrongly, someone else's fix silently disappears. zdiff3 fills in that column. And in situations where you must repeat the same judgment — continuing to rebase a long-lived branch or regularly merging a release back — rerere lets you make that judgment only once. The last two steps separate two knobs whose similar names often get them swapped. If you use -s ours with the intention of bringing in content, the history says it was merged but nothing comes into the code.

Steps

  1. Create at /root/gitx8/repo branches that modified the same line differently.
  2. Leave the default conflict marking and the zdiff3 marking side by side in notes/zdiff3.txt.
  3. Turn on rerere, resolve the conflict once and finish the merge.
  4. Undo that merge and merge again, and leave in notes/replay.txt that git applies the same resolution by itself.
  5. Merge sidefix with -X ours and leave the result in notes/xours.txt.
  6. Merge legacy with -s ours and leave the result in notes/sours.txt.
  7. Summarize the difference between the two knobs in notes/strategies.txt.
  8. Summarize in notes/report.md how to reduce repeated conflicts.

Notes

Branches that modified the same line differently

Create at /root/gitx8/repo branches that modified the same line differently.

Make handler.txt seven lines, a through g, and branch off the three branches topic, sidefix and legacy from the first commit. topic and main modify the second line differently, and sidefix modifies the second line and the sixth line. Only if the sixth line is far away can you see a separate non-conflicting change in step 5.

The column that shows what it originally was

Leave the default conflict marking and the zdiff3 marking side by side in notes/zdiff3.txt.

After producing a conflict with git merge topic, copy handler.txt as it is and then git merge --abort. Then if you produce the same conflict again with git -c merge.conflictStyle=zdiff3 merge topic, one more column appears. Add one line saying what that column is.

Have the resolution recorded once

Turn on rerere, resolve the conflict once and finish the merge.

After turning it on with git config rerere.enabled true, run git merge topic. Fix the second line of the conflicting handler.txt to b by main and topic, which keeps both sides, then git add and commit. See what git says it recorded when you commit, and what was created in .git/rr-cache.

From the second time, git resolves it for you

Undo that merge and merge again, and leave in notes/replay.txt that git applies the same resolution by itself.

Delete the merge commit with git reset --hard HEAD~1 and run git merge topic again. One more line is added to the output, and handler.txt is already in a resolved state. But if you look at git status, it is still UU — because it only applies and does not stage. Run git add and commit to finish.

Ours only at the conflicting spot

Merge sidefix with -X ours and leave the result in notes/xours.txt.

Run git merge -X ours -m '<메시지>' sidefix. The second line conflicted, so ours remains, and the sixth line did not conflict, so the change from sidefix comes in as it is. sidefix-only.txt comes in too. Copy the result file as it is and add one line on what remained and what came in.

Only write that it was merged and bring in nothing

Merge legacy with -s ours and leave the result in notes/sours.txt.

Run git merge -s ours -m '<메시지>' legacy. When you finish and look for legacy.txt, it is not there. Also check that git diff --name-only HEAD^1 HEAD outputs nothing — it means the result tree is not one character different from before the merge. Yet git merge-base --is-ancestor legacy main is true.

Two knobs that only look alike in name

Summarize the difference between the two knobs in notes/strategies.txt.

Write it as a table. Four rows are enough: what it is (option versus strategy), what happens to the other side's non-conflicting changes, what happens to new files the other side added, and when to use it. You must cite as evidence the file names you saw for yourself in steps 5 and 6.

How to reduce repeated conflicts

Summarize in notes/report.md how to reduce repeated conflicts.

Write why the two configuration lines (rerere.enabled, merge.conflictStyle) are worth turning on by default, what rerere remembers and does not remember, how to erase a wrongly resolved resolution, and even the habits that create fewer conflicts in the first place.