0

Normal merge:

$ git merge feature01
$ git merge feature02

Everything works fine.

squash merge:

$ git merge --squash feature01 # OK
$ git merge --squash feature02
Auto-merging src/aaa.js
CONFLICT (content): Merge conflict in src/XXX.js
....

Why is that? How to make merge --squash work(subsequent merge works find)?

vego
  • 889
  • 1
  • 8
  • 20

3 Answers3

0

Well.... my hunch is that there is common history of feature01 and feature02 that is outside of the branch you are working on.... when you do normal merges, git can see that and it is part of the merge calculation... but if you merge with squash, that common history is then gone from gits sight and it might cause conflicts.... for example, on the second branch that you merge you modify a change that was introduced on the first merged branch.... if you tried merging it, to git there's no historical context to figure out that you started from the change on the first branch.... so you would get a conflict.

eftshift0
  • 26,375
  • 3
  • 36
  • 60
0

The situation that you describe requires that the history looks something like this:

--X--Y             <-- your master
   \
    A--B--C--D     <-- feature01
     \
      R--S--T      <-- feature02

(Whether your master has a commit Y or is still at X is irrelevant for the following.)

Why is that?

Notice that the two features have commits in common, A in this example. When you do regular merges, Git knows about this fact and can deal with it without generating conflicts. In particular, in the second merge it will not pull in the changes made in A again.

But when you do a squash merge of feature01, you are generating this history:

--X--Y--F1         <-- your master
   \
    A--R--S--T     <-- feature02

I truncated feature01 from the picture because it does not play a role anymore.

When you do a merge of feature02 now (squash or regular does not matter), Git attempts to apply commit A again, because it does not have enough information to know that it has already merged it. The conflicts arise when one of the commits B, C, D have made changes in the vicinity of the changes that A did.

How to make merge --squash work (subsequent merge works fine)?

You cannot. Do not use merge --squash.

Of course, you can jump through some hoops by grafting history to pretend that A was actually merged into F1; but it is just a work-around, a band-aid for emergency cases, but that is too tedious for a regular workflow. And if you do that, why didn't you use a regular merge in the first place?

j6t
  • 9,150
  • 1
  • 15
  • 35
0

(as @eftshift0 mentioned in his comment : )

If, before merge, the history of your two branches look like this :

# featureA and featureB have some common history :
--*--*--x--a <- master
         \
          *--*--y--b <- featureA
                 \
                  *--*--*--c <- featureB
  • When running git merge featureA, git uses the existing commits :

    --*--*--x--a---------b' <- master
             \          /
              *--*--y--b <- featureA
                     \
                      *--*--*--c <- featureB
    

    and it has enough information to know that it should use y as a merge base for featureB,

  • When running git merge --squash featureB on the other hand :

    --*--*--x--a--b' <- master
             \
              *--*--y--b <- featureA
                     \
                      *--*--*--c <- featureB
    

    It creates a new commit, which is not related to branch featureB anymore, and it will try to re-apply the changes x..y when merging featureB.


You can look at the history of your branches :

  • from the command line : git log --graph featureA featureB master
  • or using a gui client : git gui, git-kraken, git-extensions, ...
LeGEC
  • 46,477
  • 5
  • 57
  • 104