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

4
我有以下情况:
$ 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个回答

5

Melebius' answer是正确的(并获得了赞同);这与交互式变基尝试将提交作为一系列cherry-pick重播的方式有关。由于合并实际上不是一个cherry-pick,因此保留合并模式使用秘密侧通道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这并不是什么秘密:只需查看交互式变基代码。使用您的文件查看器或编辑器,查看$(git --exec-path)/git-rebase--interactive。搜索字符串“preserv”(如保留或保护),并观察函数pick_one_preserving_merges以及在目录$rewritten存在时调用它的pick_one中的代码。然而,$rewritten目录的使用相当复杂(它适用于保留合并和非保留合并的交互式变基,并依赖于一个事实,即没有 --preserve-p选项,初始的“todo”列表不包含任何实际的合并,因此只是将它们展平)。


很棒的答案 +1,我的新规则是:避免恶意合并,在此之前没有考虑过后果。 - schoetbi

5

这可能与重新定位机制的不完善有关。来自git rebase文档:

-p
--preserve-merges

Recreate merge commits instead of flattening the history by replaying commits a merge commit introduces. Merge conflict resolutions or manual amendments to merge commits are not preserved.

This uses the --interactive machinery internally, but combining it with the --interactive option explicitly is generally not a good idea unless you know what you are doing (see BUGS below).

-i--interactive 选项是同义词。
让我们看一下 BUGS 部分:

The todo list presented by --preserve-merges --interactive does not represent the topology of the revision graph. Editing commits and rewording their commit messages should work fine, but attempts to reorder commits tend to produce counterintuitive results.

For example, an attempt to rearrange

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

to

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

by moving the "pick 4" line will result in the following history:

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

很高兴知道这是一个已知的问题。但是如果在挑选列表中的rebase之后缺少提交,我真的希望能够收到警告甚至错误提示。谢谢。 类似的SO链接:http://stackoverflow.com/questions/23262224/git-rebase-interactive-edit-for-merged-feature-branches - schoetbi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接