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

时间:2016-11-24 07:02:29

标签: 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

要在新目录中重现

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"

现在我看到此功能适用于1.1版。所以我这样做了:

git rebase --preserve-merges -i master~3

将其作为git-rebase-todo

pick 6eec273 added file1
pick 83e3254 version 1.1
pick 784ba31 awesome change
pick 34188af merge of feature into master

得到了这个:

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

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

2 个答案:

答案 0 :(得分:5)

这可能与rebase机制的不完整性有关。来自git rebase文档:

-p
--preserve-merges
     

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

     

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

-i--interactive选项是同义词。

让我们看看BUGS部分:

  

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

     

例如,尝试重新排列

1 --- 2 --- 3 --- 4 --- 5
     

1 --- 2 --- 4 --- 3 --- 5
     

移动"选择4" line将产生以下历史记录:

        3
       /
1 --- 2 --- 4 --- 5

答案 1 :(得分:4)

Melebius' answer是正确的(并且被赞成);它与交互式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"

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

git rebase -p“重播”合并时,它会在没有 --no-commit的情况下执行,然后自动在上移动到下一个线性化提交。因此,即使您保留提交顺序并因此获得其他正确的重新历史记录,任何故意引入的更改都将丢失。

记录在案 - 请参阅引用的文字,其中写着:

  

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

- 但在我看来,这句话需要用粗体闪烁的72磅字体或其他东西。 : - )

1 这根本不是什么秘密:只需查看交互式rebase代码即可。使用文件查看器或编辑器,查看$(git --exec-path)/git-rebase--interactive。搜索字符串“preserv”(如保留或保留)并观察函数pick_one_preserving_mergespick_one中的代码,如果存在名为$rewritten的目录,则调用它。 $rewritten目录的使用相当复杂(它适用于保留合并和非合并保留的交互式rebase,并依赖于 {{1}的事实}或--preserve选项,初始“todo”列表不包含实际的合并,因此只是将它们展平。)