Search code examples
gitgithubgit-merge

How can I forcefully merge one git branch into another


I have a git repository "ui" which has two branches - master and tip.

Over time master and tip drifted apart, so what I did is - on branch master

git reset --hard tip

After this when I did git diff tip no differences were shown by git.

Now, I changed one file in master branch - pom.xml which is a maven file. I changed the version in the pom.xml on master.

Now, when I do a git diff tip I see the difference in master and tip.

I committed this and pushed to master.

Now, I checked out tip git checkout tip I did a git diff master and the difference between the pom.xml on master and tip was visible.

I changed a controller (source code) file on tip, committed it and pushed to tip. When I did a git diff two changes were visible - 1. pom.xml 2. code change.

Now, I checked out master and executed the following command - git merge -X theirs tip This merged the controller file but not the pom.xml and when I do a git diff tip this again shows the diff in the pom.xml file.

What is the behavior of the merge command? How can I force git to merge the pom.xml as well?


Solution

  • Everything that happened here is perfectly logical if you understand what git is trying to achieve.

    Rather than switching back and forward between branches with abstract names, imagine you have two developers, Alice and Bob, each working on a branch with their name.

    Over time Alice's code had drifted from Bob's, so on branch Alice she ran:

    git reset --hard Bob
    

    After this when she ran git diff Bob no differences were shown by git, because the two branches pointed at exactly the same commit. Let's imagine theirs a third branch pointing at this, called "agreed-base".

    Now, Alice changed one file in her branch - pom.xml

    Now, when she runs git diff Bob she will see the change she has made, which has not been made on Bob's branch. If Bob, with his branch checked out, runs git diff Alice, he will also see this change - regardless of whose change it was, it is currently a difference between the two branches.

    If instead both developers ran git diff agreed-base, Alice would see her change, but Bob would see no changes, because his branch is still identical to that base.

    Next, Bob changed some code (let's say IndexController.java) and committed the change on his branch. Now both pom.xml and IndexController.java are different between the two branches, so both Alice and Bob will see that if they use git diff.

    Now if Bob runs git diff agreed-base, he'll see his change to IndexConteoller.java, but not Alice's; and if Alice runs that, she'll still see only her change to pom.xml.

    Finally, the part that seemed to confuse you: Alice runs git merge -X theirs Bob. This looks for all the changes that Bob has made, and applies them on top of Alice's code. One way to look at this is that the merge command is looking at the difference between agreed-base and Bob.

    Bob hasn't changed pom.xml, so nothing happens to that file; he has changed IndexController.java, so that file gets merged. If Alice had also changed that file, the -X theirs option would discard her changes, but since she hasn't, it has no effect.

    Now when Alice runs git diff Bob, she sees the change to pom.xml, which she made and Bob doesn't have; she no longer sees the change to IndexController.java, because that is the same in both branches. If she runs git diff agreed-base, she will see both changes, because her branch now contains new versions of both pom.xml and IndexController.java