git/list[1] front-page[2] threads[3] people[4] search[5] about
 

rebase preserve-merges: incorrect merge commits

From
Matwey V. Kornilov <matwey.kornilov@gmail.com>
Date
Jan 8, 2018, 10:24 UTC
Message-ID
<CAJs94Eas59UxZ+490AUSOuB37i+JBEvbCnGBMVpKi1G469OTbw@mail.gmail.com>
Hello,

I think that rebase preserve-merges algorithm needs further improvements. Probably, you already know it.

I was playing with rebasing linux kernel tree and found that rebase preserve-merges works in counterintuitive way while handling merge-commits. I don't want to discuss arising merge conflicts which can be illuminated with help of rerere trained at original branch. An major issue here with silently auto-merging, some merge commits were silently rebased with different content and it breaks the build :)

I crafted toy example to demonstrate an issue: https://github.com/matwey/example-git-rebase-pm Here I have commit range v0.1..v0.2, then I return to v0.1 and introduce new commit abc-0.1 with new file on v0.1. Then I want to rebase v0.1..v0.2 onto new abc-0.1. It is obvious that as soon as I introduced single new file the difference between old v0.2 and new v0.2 should have only this new file. However it actually contains other changes.

Reproduce as the following:

git checkout v0.2 git branch abc-0.2 git checkout v0.1 git branch abc-0.1 git checkout abc-0.1 vim LICENSE git add LICENSE git commit -a git rebase --preserve-merges --onto abc-0.1 v0.1 abc-0.2

Actual result:
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 297edb3..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,2 +0,0 @@
-Hello, world!
-
diff --git a/mod.c b/mod.c
index e6fa107..e339597 100644
--- a/mod.c
+++ b/mod.c
@@ -2,5 +2,5 @@
 #include "mod.h"

 int mod_fun(char* buf, int len) {
-       return -calc_fun(buf, len);
+       return -calc_fun(buf, len, 0);
 }

Expected result:

diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 297edb3..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,2 +0,0 @@
-Hello, world!
-


As far as I understand the root cause of this that when new merge
commit is created by rebase it is done simply by git merge
$new_parents without taking into account any actual state of the
initial merge commit. This is why all manually introduced changes in
merge-commits are lost at rebase stage. I think that the following
improvement of merge-commit recreating stage would be possible:

1) Let we have merge commit in the source tree

-- A --\
        M--
-- B --/

And we want to rebase M to the new tree where new parents A' and B'
already existing.

-- A'

-- B'

2) Then I suggest to perform it in three steps. First, lets take all
possible differences between A and M, B and M and so on... and then
try to cherry-pick the diffs on A' and B' respectively. Here AM' and
BM' are temporary commits which is very close in their states (in
ideal case, equal).

-- A' -- (AM)'

-- B' -- (BM)'

3) Then we do git merge (AM)' (BM)' and ask user to resolve the
conflicts if any. Here we obtain the following tree. Where M" is
produced by git merge.

-- A' -- (AM)' --\
                  M"
-- B' -- (BM)' --/

4) Then we do merge between A' and B' but reset the state to be the
same as in M" before new merge commit is created:

-- A' -- (AM)' --\
     \            \
       M' (==M")    M"
     /            /
-- B' -- (BM)' --/

5) Then (AM)' (BM)' and M" are discarded from the tree.


Probably, I missed something important or incorrectly read
git-rebase--interactive.sh
-- 
With best regards,
Matwey V. Kornilov
Next: Johannes Schindelin
Message 1 of 11 in “rebase preserve-merges: incorrect merge commits”
  1. Matwey V. KornilovJan 8, 2018
  2. Johannes SchindelinJan 8, 2018
  3. Matwey V. KornilovJan 8, 2018
  4. Matwey V. KornilovJan 8, 2018
  5. Johannes SchindelinJan 8, 2018
  6. Matwey V. KornilovJan 8, 2018
  7. Johannes SchindelinJan 8, 2018
  8. Matwey V. KornilovJan 9, 2018
  9. Johannes SchindelinJan 9, 2018
  10. Matwey V. KornilovJan 9, 2018
  11. Johannes SchindelinJan 9, 2018

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.