mhagger / git-imerge

Incremental merge for git
GNU General Public License v2.0
2.7k stars 126 forks source link

Merging a branch that has merge commits #186

Open OliverJAsh opened 3 years ago

OliverJAsh commented 3 years ago

Sorry if this has already been asked, I tried to search for existing issues but couldn't find anything!

In this example I want to merge master into feature-3:

* 502ea6a (feature-3) Amend b
| *   9d988ea (master) Merge branch 'feature-2'
| |\
|/ /
| * 7e5dce8 Amend a
| * 638c8ca New file
|/
*   8cdd583 Merge branch 'feature'
|\
| * a2dc21b Feature
|/
* 91bf661 Init

When I do so using git-imerge merge master, if there's a conflict I see something like this:

Attempting automerge of 1-1...failure.
Attempting automerge of 1-1...failure.
Switched to branch 'imerge/master'
Auto-merging test
CONFLICT (content): Merge conflict in test
Recorded preimage for 'test'
Automatic merge failed; fix conflicts and then commit the result.

Original first commit:
commit 502ea6ac3ff9ac782a04f9af7a5a366923e1e9ae (HEAD -> imerge/master, refs/imerge/master/manual/1-0, feature-3)
Author: Oliver Joseph Ash <oliverjash@gmail.com>
Date:   Wed May 26 10:53:43 2021 +0100

    Amend b

Original second commit:
commit 9d988eaec4e576406156a96b68a8bddeed699c52 (refs/imerge/master/manual/0-1, master)
Merge: 8cdd583 7e5dce8
Author: Oliver Joseph Ash <oliverjash@gmail.com>
Date:   Wed May 26 10:53:17 2021 +0100

    Merge branch 'feature-2'

There was a conflict merging commit 1-1, shown above.
Please resolve the conflict, commit the result, then type

    git-imerge continue

It's difficult to deal with this conflict because the merge commit on master contains many different changes.

Is there a way I can use git-imerge so that it allows me to deal with conflicts between the original commits rather than between merge commits? In my example above the underlying merge conflict arises between 7e5dce8 Amend a and 502ea6a Amend b—I would like git-imerge to tell me this.

mhagger commented 3 years ago

In this particular case, you could try

git imerge 7e5dce8

which would merge the individual commits 638c8ca and 7e5dce8 into feature-3. Assuming that 9d988ea is not an evil merge, the resulting tree would be the same as merging 9d988ea into feature-3 directly. You'd probably then want to merge 9d988ea into that merge commit to get the right history graph, or fiddle around to make the history only include a single merge.

This could be automated for a history that looks like your master history: each branch diverges from master then is merged back to master (possibly with conflicts), one at a time, without the branches overlapping in time, like this:

o-------o-----------o-------o          ← master
 \       \         / \     /
  \       o---o---o   o---o
   \
    o-------o-------o-------o          ← branch

This is not very difficult, because the commits on master can be put into a linear order.

But as soon as the history gets more complicated, it's hard to generalize. For example, what would one do in the following case?:

  A---B
 /     \
o---X---C         ← master
 \ / \
  o   o---o       ← branch

It's not hard to imerge commits A and B into branch, but when you get to C things aren't so clear, because C already contains the changes from commit X, which are already in branch. (Technically, the problem is that the merge of C into branch has two "merge bases", B and X.)