Simeon Schaub
Simeon Schaub

Reputation: 775

Update previous merge commit without resolving conflicts twice

I have a repo with two branches, main and feature. The output of git log --graph --format='%s %d' --all looks like the following:

* e  (main)
| * d  (HEAD -> feature)
| *   Merge branch 'main' into feature 
| |\  
| |/  
|/|   
* | c 
| * b 
|/  
* a

I now want to include the commit e on my main branch in the merge commit on the feature branch, so that I have the latest changes on main, but don't have to force push if commit b on the feature branch is already pushed. I also don't want to have another merge commit in my history. I want my final graph to look like this:

| * d  (HEAD -> feature)
| *   Merge branch 'main' into feature 
| |\  
| |/  
|/|   
* | e  (main)
* | c 
| * b 
|/  
* a

I can achieve that with git rebase -i main --onto :/a --rebase-merges and change the instructions for the interactive rebase to:

label onto

reset 9870d06 # a
pick 579c27a b
merge -C d4caa73 main # Merge branch 'main' into feature
pick f672b7f d

The problem with that though is that in the previous merge commit, I had to resolve a conflict between b and c, and with this approach, I would have to resolve this conflict again. Therefore, what I would really like to do is pick up the merge commit where I left off at commit c on main and just continue with merging e into feature on top of b. Is there a way to achieve this? Perhaps there is also a way to introduce another merge commit temporarily and then squash these two merge commits afterwards?

Upvotes: 0

Views: 524

Answers (1)

torek
torek

Reputation: 488183

Git does include something designed for this kind of work-flow. There's a hitch: you must turn it on before you do your first merge.

Fortunately, there's a third-party solution to the hitch, called git rerere-train, which is included with Git distributions now (but still not installed directly). See, e.g., the accepted answer to Smarter rebase avoiding redundant work?

While this question (from eight years ago!) is about rebase, the same concept works with the git merge performed by --rebase-merges. In fact, the conflicts that occur during rebase are merge conflicts. You don't need the full training the script can do; you could use this method (from ten years ago!) to teach Git the resolutions you used earlier.

Do note that once you turn on rerere.enabled, Git will keep checking for previous resolutions and re-using them, even if you don't want that to happen (e.g., if you realize you resolved something incorrectly and want to do it over again). You can turn it off with the same kind of git config operation you used to turn it on, though. Note also that even with the re-use recoreded resolutions (rerere) option turned on, Git will stop after a conflicted merge that does take these recorded resolutions. This gives you an opportunity to check the result.

Upvotes: 2

Related Questions