Solving the Same Conflict for the Fourth Time
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
- Create at
/root/gitx8/repobranches that modified the same line differently. - Leave the default conflict marking and the
zdiff3marking side by side innotes/zdiff3.txt. - Turn on
rerere, resolve the conflict once and finish the merge. - Undo that merge and merge again, and leave in
notes/replay.txtthat git applies the same resolution by itself. - Merge
sidefixwith-X oursand leave the result innotes/xours.txt. - Merge
legacywith-s oursand leave the result innotes/sours.txt. - Summarize the difference between the two knobs in
notes/strategies.txt. - Summarize in
notes/report.mdhow to reduce repeated conflicts.
Notes
- You must specify
git config user.emailanduser.namefor each repository for commits to work. Fix the commit times withGIT_AUTHOR_DATEandGIT_COMMITTER_DATE. - After seeing a conflict, you can cleanly back out with
git merge --abort. - Common mistake: seeing that rerere has fixed the file in step 4 and thinking it was committed too. rerere only applies and does not stage.
- Common mistake: seeing that
legacy.txtis missing after step 6 and treating it as a failure. That is what-s oursdoes, and it is the point of this step.
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.