Search code examples
gitgithubmergetool

git mergetool output is wrong


I am new to git and trying to get my hands dirty with it.

I cloned my testing repo with single text file at two different folders. Then i created two branches B1 in folder1 and B2 in folder2

In B1 i added a line, now test.txt has following content

It is line from dev branch.
It is line from B1.

Commited changes in B1, merged with master and pushed changes back to remote

Now in B2 also added a different line, it's test.txt has following content

It is line from dev branch.
It is line from branch 'B2'.

When i tried to sync B2 with upstream master, it got merge conflict

git pull --rebase origin master

First, rewinding head to replay your work on top of it...
Applying: Modified test.txt from B2
Using index info to reconstruct a base tree...
M       test.txt
Falling back to patching base and 3-way merge...
Auto-merging test.txt
CONFLICT (content): Merge conflict in test.txt
error: Failed to merge in the changes.

I opened mergetool

git mergetool

It opens meld, but here Local and Remote files are interchanged. Local is showing content from master branch Remote is showing content from local B2 branch. Here is snapshot

https://postimg.org/image/njtivi32d/

Am i looking it wrong or it is actually wrong ? Can anyone help with it?

Here is mergetool config from .gitconfig

[merge]
    tool = meld
[mergetool "meld"]
    cmd = meld "$LOCAL" "$BASE" "$REMOTE" --output "$MERGED"

Solution

  • The way a rebase works is by rolling back the target branch until reaching the most common ancestor commit between B2 and master, then playing the commits from master since that point. Then, the commits from B2 occurring after that common ancestor commit on the B2 branch are replayed on top of the master commits.

    This explains why the local version resembles master. It resembles master because this is what the local branch looks like at this point in the rebase. And the remote looks like B2 because these commits are being replayed.

    It might be easier to understand this with a diagram. Consider a situation where both master and B2 have diverged by one commit. This means that since the most recent common ancestor, one commit has been to each branch, respectively:

    master: ... A -- B -- C
                      \
    B2:                D
    

    The first step in a rebase is to rewind the B2 branch and apply the commits in master since the commit B. This leaves us with the following:

    master: ... A -- B -- C
                      \
    B2:                C         [D commit not yet reapplied]
    

    The last step in the rebase is to reapply the D commit to B2:

    master: ... A -- B -- C
                      \
    B2:                C -- D'
    

    This is the point where the merge conflict you saw happened. At the point, the "local" code you already have is associated with the C commit, from master, and the "remote" code is actually coming from the original B2 branch, before the rebase.