gitmergesquash

Commit history mess after squashing into master


I have two branches in a repo: master and dev.

State of dev is

- A - S1 - S2 - ... - SN - B - C

State of master is

- A - S

Where S commit is the result of "squash and merge" of S1, ..., SN from dev to master.

Now, when I compare the branches, git shows a lot of changes, but actually they are B and C.

  1. What the best way to sync the branches?
  2. What the proper workflow to avoid such situations?

Solution

  • Ok.... your comments explain what's going on. So, github will use triple dots when doing a diff. So, if you tried git diff master..dev, you would only see what B and C introduced. But github will use master...dev (or viceversa, does not matter). Try with git with triple dot and you will see that it will also include the changes introduces by S, and that is because when you do master...dev, git won't just compare master and dev. It will first find the last common ancestor between them (A) and then git diff A..dev, which will include the changes introduced by S1..SN... same thing if you tried dev...master. It would end up doing git diff A..master (which would include changes from S). And that is because when you squashed/merge, there was no real merge.

    The way to kind of get this working again would be to set dev to have B and C on top of current master:

    git rebase --onto master SN dev
    

    That should get you what you want, but you lose the history of S1~..SN. Another way would be to get this properly merged..... but hacking a little bit so that you won't have to redo yourself (say, did you have to solve conflicts and stuff? I don't know.... so), you could try this:

    git commit-tree -p A -p SN -m "Merging S" S^{tree}
    # this will create a new _merge_ revision having A and SN as parents
    # the content of the files will be the same as S
    # the command will print the ID of a revision
    # take that revision ID and let's call it X
    # branch dev can live on the way it is.... we just need to put master where X is
    git checkout master # if you are not in master already
    # make sure you have no changes uncommitted as the next command will destroy those changes
    git reset --hard X 
    # now master is on top of X, the way it should have been
    

    Now, do not ever try squashing/merging ever again unless you know what you are doing.