3

When I pull master into a branch, it may succeed, or it may conflict, depending on activity on both branches since they separated.

When it conflicts, I will go through and manually resolve the conflict, eg using git mergetool, and then I'll commit the merge (eg git commit -m "Merge in latest master"). That gives a commit, merging two different commits which conflicted. I've got this so far. However this can be a lot of work to resolve that.

Shortly after on another feature branch, pulling master into that feature branch, I'll get the exact same conflict. Exact same files, exact same changes on both branches. How can I re-use the effort expanded to merge those two commits again?

Eg, I'd like a "git apply-existing-merge" option, as used below:

git checkout JOB-12345
git pull origin master
CONFLICT (content): file1
CONFLICT (content): file2
CONFLICT (content): file3
(does much work to fix it)
git commit -m "Massive complex merge of upstream code"
[JOB-12345 93697088ad0] Massive complex merge of upstream code

... Later that day

git checkout JOB-12346
git pull origin master
CONFLICT (content): file1
CONFLICT (content): file2
CONFLICT (content): file3
git apply-existing-merge 93697088ad0
[JOB-12346 93697088ad0] Merge in the latest upstream changes.

Attempting to graph it

Master   :   X-----1--X----X
              \        \    \
Feature 1:     X-2-X-4--X-A  \
                    \         \
Feature 2:           X-3-------X-B

1 and 2 conflict. So pulling 1 into (2,4) creates the exact same conflict that pulling 1 into (2, 3)

How can I merge 1 and 2 in such a way that I can do it once, but apply it twice. (And without corrupting the feature branches, I need to ensure A only contains (1, 2, 4), and B only contains (1, 2, 3)?

I've tried messing around with cherry-pick and creating and applying patches, however I can't get anythiing working. I expect it must be possible.

User12321313
  • 141
  • 2
  • You should read about rerere : [Git Doc - Rerere](https://git-scm.com/docs/git-rerere) [An article about rerere on Medium](https://medium.com/@porteneuve/fix-conflicts-only-once-with-git-rerere-7d116b2cec67) – Jona Aug 08 '19 at 09:17
  • Typically you would merge master into dev and then branch off of dev for features (or something similar). Then you wouldn't have to resolve the same conflicts twice, just merge dev into your features – Joe Phillips Aug 08 '19 at 11:16

2 Answers2

4

You want to use git rerere for this. When you have a conflict and you add the resolution and commit it, git rerere remembers it. When another conflict comes up that's the same, git rerere will automatically fix the conflict in the same way.

To enable it, run git config --global rerere.enabled true; it will take effect automatically and save future conflict resolutions.

Note that there are some limitations: if the conflicts for a file are similar, but not exactly the same, then git rerere won't work on that file. It will still work on other files which are identical, however.

bk2204
  • 64,793
  • 6
  • 84
  • 100
  • 1
    Another caveat: `rerere` can only work on files that have textual conflicts. If a change was made in a file that had no textual conflicts (such a change may be necessary due to a logical conflict between the branches), then that change will not be recorded and has to be repeated manually. – j6t Nov 27 '19 at 11:47
0

I would do this:

  1. create the merge commit with parents 1 and 3, but don't actually resolve the conflict (since we already did so before). Instead, just add the conflicted files, and commit the conflict markers!

  2. create a new branch on the merge commit you already made earlier on master, cherry-picking the commit you want to add, and reverting the commit you want to remove. This establishes the working directory you want, but it doesn't have the right parent commits.

  3. Then reset --mixed to the sloppy merge commit with the conflict markers, and amend that commit.


I made an example repository which conflicts as in your question. You can clone it from github:

git clone https://github.com/TamaHobbit/mergeredo_example

If you follow my steps in GitExtensions it should look like the following when you get to step 3:

gitextensions screenshot after step 2


On the commandline, it would be:

git merge 1
git add .
git commit -m "Merge 1 into B"
git checkout origin/master
git revert --no-commit 4
git cherry-pick --no-commit 3
git reset --mixed B
git commit -a --amend --no-edit
git branch -D B
git checkout -b B

That leaves you with 1 merged into B in the same way as into A, while not including 4 in branch B.

TamaMcGlinn
  • 2,840
  • 23
  • 34