6

As a developer on php-src I recently find myself in the following situation:

A   B   C
o---o---o         version1
         \
o---o-----o---o   master
x   y     D   E

o---o---o         upstream/master
x   y   z

So when I do git push --dry-run upstream master version1 I get the typical:

! [rejected]        master -> master (fetch first)

My natural response is to rebase the affected branch and preserve merge commits:

git fetch upstream
git rebase -p upstream/master

It's important to note that the original merge commit wasn't trivial, because there are so many changes between the version branch and the master; it takes an effort to resolve such a merge.

Doing the above rebase operation causes a merge conflict and I have to resolve it again; this is almost exactly the same job that I had already done.

Is there a better way to do this? Or did I forget an obvious rebase option?

Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
  • Do you *have* to rebase? I usually rebase as well but I have also been in your situation where it just wasn't feasible and went with a standard merge then. – musiKk Sep 02 '14 at 07:55
  • Sure, I can just push `D, E, M(z)` instead of `D', E'` but I prefer to keep the history as clean as I can :) – Ja͢ck Sep 02 '14 at 08:20
  • 1
    I hear you. It depends on your case. I worked on merges that took hours. My love for a clean history only goes so far. :) – musiKk Sep 02 '14 at 08:23

1 Answers1

4

Ideally you would "reuse the recorded resolution" with rerere:

In a workflow employing relatively long lived topic branches, the developer sometimes needs to resolve the same conflicts over and over again until the topic branches are done either merged to the "release" branch, or sent out and accepted upstream).

This command assists the developer in this process by recording conflicted automerge results and corresponding hand resolve results on the initial manual merge, and applying previously recorded hand resolutions to their corresponding automerge results.

Unfortunately, this feature must be enabled before you first do the merge:

Note: You need to set the configuration variable rerere.enabled in order to enable this command.

As far as I know, there is no shortcut to do something like this after the fact. I recommend enabling rerere globally and then redoing the merge:

git config --global rerere.enabled true

In the future, this setting could save you lots of time!

Community
  • 1
  • 1
ChrisGPT was on strike
  • 127,765
  • 105
  • 273
  • 257
  • 2
    The shortcut to retroactively enable rerere here should be simply `git config rerere.enabled true; git checkout y; git merge -s ours --no-commit C; git read-tree -um HEAD D; git commit; git checkout master`. – jthill Sep 02 '14 at 04:52
  • @jthill that doesn't look simple to me, but if it works, it would be a nice addition to either this answer or a separate one :) – Ja͢ck Sep 02 '14 at 09:00
  • Wow, I didn't know about `rerere` or I did and forgot. Looks interesting. Do you know if there are any negative effects when setting `rerere.enabled` to `true` just in case? – musiKk Sep 02 '14 at 10:05
  • 1
    @musiKk Not much downside IMO. There's a small cache directory (`.git/rr-cache`) which can be intelligently managed with `git rerere gc`. There is the possibility of [repeating a bad merge](http://stackoverflow.com/a/5521483/354577), but I think it's worth it. Just be aware that you've got a merge resolution cache now :-). – ChrisGPT was on strike Sep 02 '14 at 10:31
  • 1
    Yeh. Not an answer because I haven't really tested it. It's substantially correct but may need a little beatin' on. edit: It's worth screwing up a scratch clone for. – jthill Sep 02 '14 at 16:55