Git rebase -i --preserve-merges会丢失更改

sch*_*tbi 4 git

我有以下情况:

$ git --version
git version 2.7.3.windows.1

$ git log --graph --oneline
* 83e3254 version 1.1
*   34188af merge of feature into master
|\
| * 784ba31 awesome change
|/
* 6eec273 added file1
* 84d80a5 added version file
Run Code Online (Sandbox Code Playgroud)

在新目录中重现此问题

rm -rf .git
git init
echo version 1.0 > version.txt
git add version.txt
git commit -m "added version file"

echo file1 > file1
git add file1
git commit -m "added file1"

git checkout -b feature
echo awesome change >> file1 && git commit -am "awesome change"

git checkout master
git merge --no-ff --no-commit feature
echo "small fixup" >> file1
git commit -am "merge of feature into master"

echo version 1.1 > version.txt
git commit -am "version 1.1"
Run Code Online (Sandbox Code Playgroud)

现在我看到这个功能适用于1.1版本.所以我这样做了:

git rebase --preserve-merges -i master~3
Run Code Online (Sandbox Code Playgroud)

用这个作为git-rebase-todo

pick 6eec273 added file1
pick 83e3254 version 1.1
pick 784ba31 awesome change
pick 34188af merge of feature into master
Run Code Online (Sandbox Code Playgroud)

得到了这个:

$ git log --graph --oneline
*   34188af merge of feature into master
|\
| * 784ba31 awesome change
|/
* 6eec273 added file1
* 84d80a5 added version file
Run Code Online (Sandbox Code Playgroud)

83e3254发生了什么?我错过了什么吗?当我需要保留合并时,我应该在todofile中使用34188af吗?

Mel*_*ius 5

这可能与变形机制的记录不完善有关.从git rebase文档:

-p
--preserve-merges
Run Code Online (Sandbox Code Playgroud)

通过重放合并提交引入的提交来重新创建合并提交,而不是展平历史记录.不保留合并冲突解决方案或手动修改合并提交.

这在--interactive内部使用机器,但明确地将它与--interactive选项结合起来通常不是一个好主意, 除非你知道你在做什么(见下面的BUGS).

-i--interactive选项是同义的.

我们来看看BUGS部分:

显示的待办事项列表--preserve-merges --interactive不代表修订图的拓扑.编辑提交和重写他们的提交消息应该可以正常工作,但尝试重新提交提交往往会产生违反直觉的结果.

例如,尝试重新排列

1 --- 2 --- 3 --- 4 --- 5
Run Code Online (Sandbox Code Playgroud)

1 --- 2 --- 4 --- 3 --- 5
Run Code Online (Sandbox Code Playgroud)

通过移动"选择4"线将导致以下历史记录:

        3
       /
1 --- 2 --- 4 --- 5
Run Code Online (Sandbox Code Playgroud)


tor*_*rek 5

Melebius的答案是正确的(并且被否决);它与交互式rebase尝试将提交重播为一系列樱桃小贴士的方式有关。由于合并实际上并不是挑剔的,因此保留合并模式使用秘密辅助通道1来确定如何重新执行合并,并且该辅助通道取决于提交顺序。

但是,重新执行合并还有另一个问题。通过运行重做合并git merge。这是您的原始合并:

git checkout master
git merge --no-ff --no-commit feature
echo "small fixup" >> file1             # DANGER WILL ROBINSON
git commit -am "merge of feature into master"
Run Code Online (Sandbox Code Playgroud)

(请注意我的补充说明)。此“小修正”不是两个输入的一部分:它是通过--no-commit功能手动添加的,并且是通过手动操作添加的。有时称为“邪恶合并”:

git rebase -p“重播”的合并,它这样做没有 --no-commit,然后自动移动上到下一个线性化的承诺。因此,即使您保留提交顺序并因此获得了正确的重新建立历史记录,像这样故意引入的任何更改都将丢失。

是有文档记录的,请参见引用的文本,其中指出:

合并冲突解决方案或手动修订以合并提交不会保留。

-但我认为该句子必须使用粗体闪烁的72点字体或类似内容。:-)


1这并不是真的很秘密:只需查看交互式rebase代码即可。使用文件查看器或编辑器,查看$(git --exec-path)/git-rebase--interactive。搜索字符串“ preserv”(在保留或保留中),并观察该函数pick_one_preserving_merges以及pick_one如果$rewritten存在命名目录的情况下调用该函数的代码。的的使用$rewritten目录是相当复杂的,虽然(它适用于合并保留和非合并保留互动底垫,并依赖于一个事实,即没有--preserve-p选项,最初的“待办事项”列表中没有实际的合并,因此简单地使它们变平)。