The confusing world of Git merge options

The default git merge is usually all you need, but if you have to deep deeper, you’ll find that git merge command has very weird looking and confusing options.

I created https://github.com/ikriv/merges repository that shows the result of applying different variants of git merge command.

For starters, git merge -s ours xyz is not the same as git merge -X ours xyz. The first uses merge strategy called “ours”, and the second uses default ‘recursive’ merge strategy, but with “ours” option. Creating two entities named “ours” that do similar, but subtly different things is the epitome of  bad interface design.

The “-s” variant creates a commit that merges current branch and “xyz”, but ignores all changes from xyz, so the resulting content would be identical to the current branch. This is useful for getting rid of unwanted branches when force-pushes and deletes are disabled. The “-X” variant only ignores changes from xyz that cause a conflict. Changes from xyz that do not cause a conflict will be included in the end result.

Similarly, git has git merge -X theirs xyz, which will merge current branch and xyz, but will ignore changes from the current branch that cause a conflict and will takes those from xyz instead.

Git annoyingly lacks git merge -s theirs xyz, which would merge current branch with xyz and make the result identical to xyz. This would be very useful to simulate force pushes, but alas. I naively tried to use git merge -X theirs xyz instead and got into hot water.

“Theirs” merge strategy that ignores the current branch can be simulated by creating a temporary branch and using “ours” strategy on it, but why do we need to jump through those hoops?

 

4 Comments


  1. What you are describing is a technical issue for sure, but in most cases it should be easily avoided by carefully picking people who are accurate enough and have proper management. Under good process, in very rare cases two good developers would try to modify the same portions of class files, where this issue is only relevant. All other cases will be easily handled by default merge options, right?

    Reply

    1. The real use case was as follows:
      – I wanted to move a branch from a bad solution to a good solution.
      – Our central git repository does not allow force-pushes.
      – So I decided that I will just merge good solution into the branch ignoring the current solution.
      – I was looking for the way to “accept theirs”
      – I googled and found the (wrong) advice on StackOverflow to use git merge -X theirs
      – I used it and to my astonishment the result was different from the target branch
      – I decided to investigate
      – Hence the article.

      Reply

      1. I got it. Ironically, just today I was asked about “moving branch” and I advised not to. I noticed that only standard, often-used options in Git work fine. The rest – really hit or miss. So, it corporate environment, would just abandon bad solution branch 🙂

        Reply

      2. And then it would be stuck there as a sore foot forever. Coming to think of it, though, I could have achieved the desired result with some clever branch renaming. Or merge the bad branch into a special branch named “graveyard”.

        As for the hit-or-miss, I have not yet seen actual bugs in git. Everything works as advertised, only the advertisement may be a little confusing.

        Reply

Leave a Reply to Dmitry Duginov Cancel reply

Your email address will not be published. Required fields are marked *