12

I'm using git and I'm getting to this state:

      X --- Y --------- M1 -------- M2 (my-feature)
     /                 /           /
    /                 /           /
   a --- b --- c --- d --- e --- f (stable)

This happen when we work on 'my-feature' branch for more than a day. M1 and M2 are merged done from the stable branch to the feature branch. M1 and M2 may had merged conflicts which have been resolved. The whole idea of merging the stable branch into the feature branch is to handle the conflicts sooner rather than later.

Once the feature is complete we want to rebase the feature branch into one or two commits.

The problem is when we do interactive rebase git show us the same merge conflicts we already solve during M1 and M2 merges.

Is there way to make git reuse the merge decision we already done in M1 and M2 ?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Ido Ran
  • 10,584
  • 17
  • 80
  • 143

4 Answers4

13

If the merge conflicts are identical, this is a perfect use case for git rerere, one of the most useful (albeit lesser-known) commands in git. From the man pages:

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.

git rerere keeps a record of your conflict resolutions and applies them automatically when encountering the same conflict in git merge, git rebase, or git commit (when committing a merge). Scott Chacon posted some great examples here, and the man page is also worth a read.

You can enable git rerere in merge and rebase by issuing this command:

git config --global rerere.enabled true

Remove the --global flag if you'd like the option enabled for just a single repository.

Elias Zamaria
  • 96,623
  • 33
  • 114
  • 148
Christopher
  • 42,720
  • 11
  • 81
  • 99
  • Thank You. I've read about rerere but it didn't use it until now. – Ido Ran Jul 08 '12 at 19:12
  • I actually have one question about this: we work on a team, when someone else is doing the merge conflict the rr-cache directory will be on their machine. Does it get copy to the main repository? Or can I share the rr-cache data between the team? – Ido Ran Jul 08 '12 at 19:15
  • 1
    The rr-cache isn't shared via the remote, but if you share the actual `rr-cache` directory between repos by another means, it should work. Here's a nice answer about making the `rr-cache` itself a symlinked repository: http://stackoverflow.com/a/5410923/877115. – Christopher Jul 09 '12 at 03:25
8
git rebase --interactive --preserve-merges
forvaidya
  • 3,041
  • 3
  • 26
  • 33
  • I've already try preserve-merges but my mistake seem to be that I mark the merge commit to squash. Now I've did it again and mark only the commit after M2 to be squash – Ido Ran Jul 08 '12 at 12:53
  • 1
    Careful about this combination of flags on rebase. It can generate counterintuitive results: http://article.gmane.org/gmane.comp.version-control.git/148059 – Christopher Jul 08 '12 at 15:36
  • Yes, I've read what using -i and -p together can be dangerous. I'm never reordering the commits, only choose which to pick and which to squash. I've notice that if I squash the commit right after the merge it fore git to recreate the merged commit and "straight" the commit line history – Ido Ran Jul 08 '12 at 19:20
  • 2
    Is there a workaround for editing an old commit while still preserving merges? – lkraav Feb 26 '13 at 18:27
  • I don't think this solves the OP's problem, and I can't be sure because there's no explanation. – hmijail Jun 23 '16 at 14:31
4

An explicit way of making a feature branch feature into a new branch feature-one-commit with a single commit:

git checkout -b feature-one-commit \
"$(git commit-tree HEAD^{tree} -m "Commit message" -p master)"    
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • 2
    This was the easiest solution for me, and it also made me aware of [`git-commit-tree`](https://git-scm.com/docs/git-commit-tree). _Git_ is truly a deep rabbit hole, heh. – Ainar-G Dec 30 '20 at 12:45
0

You could always force it using the -f flag

chrisbulmer
  • 1,237
  • 8
  • 15