Search code examples
gitgit-rebase

Git rebase unexpected merge result


Assume the following commit structure:

A ---- B(HEAD)
 \ 
   C

File contents in these revisoins.

A:

1

B:

1
2

C:

0
1

I want to merge B to C. If I do it via git merge C I get an expected conflict. But If I do a git rebase C then git do it silently without any conflicts, but the result is unexpected:

0
12

Can anyone please explain to me why does it happen? Can I even rely on rebase? Documentation says that rebase reapplies commits on the tip of another commit. So how comes that commit adding "2" to the second line does not cause any conflicts and "eats" a line break? You can test it on this repo https://gitlab.com/timofei.davydik/rebase_problem.git

git checkout test
git rebase master

Solution

  • It looks like the problems are caused by the missing newline on the last line of your file in each case, and possibly a bug with rebase when faced with that missing newline. Technically, a text file is not "valid" when its final newline is missing, which I suspect means that that case is rarely tested.

    I reproduced the behaviour on your sample repo - thanks for prividing it! - and then created a different sandbox with the same files but with a newline on the last line at each state.

    With the file-final newlines, both the merge and the rebase produced:

    0
    1
    2
    

    as you would expect.

    I think git merge is seeing a conflict in your example because it's not recognizing 1 and 1\n as the same, whereas git rebase sees "insert 0 ahead of 1" goes ahead because it finds the 1 on the first line, even though the newline is missing from the 1.

    The fact that git rebase produced 0\n12 suggests it took the 0\n and 1 from C and then 2 from B, with the newline missing from 1 and 2 because they are missing in your file.

    I would say it's a bug for rebase to have considered 1 == 1\n, but otherwise the output is reasonable based on the input.