我并不完全清楚你正在合并什么提交,因此你为什么会得到这个结果。您可以通过以下方式向自己澄清第一个问题(它对我没有太大帮助,因为我没有提交):
git log --decorate --oneline --graph --boundary master...<branch-name>
(注意这里的三个点)。这将显示您现在在 master 上的提交,以及您将从 <branch-name> 通过这两个分支的合并基础提交引入的提交。
不过,无论如何,我可以做出一个很好的猜测,因为git merge 的工作方式是将这个合并基础与两个分支提示进行比较。这是在进行合并之前的示例图片段(此时,这是常规合并还是壁球合并都没有关系):
...--B--C--D <-- master (HEAD)
\
E--F--G <-- feature
每个大写字母代表一个提交(其真实 ID 是 Git 哈希 ID,例如 a9f3c72 或其他)。 merge base 这里的提交是提交B:它是提交链的位置,同时从master 和feature 开始并向后工作(在此图中向左),首先走到一起。换句话说,提交B 是both 分支master 和 分支feature 上的最新提交。这就是使它成为合并基础提交的原因。
Git 现在实际上将运行:
git diff B D # see what "we" did on branch master
git diff B G # see what "they" did on branch feature
然后,Git 必须合并这些更改:如果我们更改 README 以在末尾添加一行,Git 应该将这个额外的行添加到末尾。如果他们以某种方式更改了foo.py(可能是添加了一行并删除了另一行),Git 应该将他们的更改更改为foo.py。但是,如果我们都做完全相同的事情,Git 应该只获取该更改的一个副本。例如,如果我们将master 上的相同更改为foo.py,我们毕竟不需要他们的更改:它已被我们的更改所涵盖。 p>
假设我们更改了README,我们和他们都修复了foo.py 中的相同内容,但他们也更改了doc.txt 和main.py。所以我们的最后一组更改是保留我们在README 中添加的行,保留我们的foo.py 更改,并选择doc.txt 和main.py 更改。效果是 Git 将所有这些应用到合并基础提交 B 的内容。 这为我们提供了新提交 H 的内容。(请注意 H 中的内容,因为它可能会再次困扰我们。)Git 更新索引(下一次提交的位置make go) 和工作树(我们可以在其中看到将要提交或已提交的内容)到此新内容,准备提交。
现在常规 vs 壁球合并突然变得很重要,因为如果 Git 要进行 常规 合并提交,它会这样做:
...--B--C--D---H <-- master (HEAD)
\ /
E--F--G <-- feature
这个新的merge commit H 结合了所有在提交C-D 中完成的工作和所有在提交E-F-G 中完成的工作,将指向both em> 提交D,master 的前一个提示,并提交G,feature 的前一个也是当前的提示。
如果 Git 要进行 squash 提交,但是,它会在说完之后停止:
Automatic merge went well; stopped before committing as requested
Squash commit -- not updating HEAD
$
它让我们做出提交。一旦我们做出这个提交,我们就会得到新的提交 H,但是这一次它没有指向 both D 和 G。这一次,新的提交 H 指向 only 到 D:
...--B--C--D---H <-- master (HEAD)
\
E--F--G <-- feature
假设这一切都按照它应该的方式工作,我们确实实际上是提交H。这就产生了我认为最有可能的情况。
可能的情况
让我们看看如果我们再次运行git merge --squash feature会发生什么。
Git 和以前一样开始,通过找到合并基础:分支 master 和 feature 的连接点。再次提交 B。
现在 Git 区分两个分支提示。这次master的tip是H,所以两个diff是:
git diff B H
git diff B G
Git 现在会合并这些更改。这一次,我们更改了README、foo.py、doc.txt 和main.py。 (请记住,这些是我们所说的通过合并所有内容而得到的更改。)同时它们(在feature 中)以与我们相同的方式更改了foo.py,以与我们相同的方式更改了doc.txt,并更改了main.py和我们一样。
因此,Git 接受了我们所有的更改,而不是他们的。结果完全匹配提交H。 Git 现在停止并显示与以前相同的消息。
这一次,当我们运行时:
git commit
为了完成任务,Git 将我们的索引(我们为提交暂存的内容)与我们的HEAD 提交进行比较,发现它们完全、完全、100% 相同。 我们已经完成了来自feature 的所有工作。Git 说“没有什么要提交”和“工作树干净”,因为没有什么要提交并且工作树与索引匹配。
可能性较小的可能性
我们可以在这里获得相同效果的另一种方法是,如果不首先进行壁球提交H,则提交系列E-F-G“撤消自身”足以使其无关紧要。例如,假设F 是对foo.py 的匹配更改(它可能是提交C 的副本),但提交G 是提交E 的恢复。现在,从 B 到 G 的更改总和不再涉及 doc.txt 和 main.py, 包含在我们原来的 B-to-D 更改中。 git merge --squash 已提交合并,但同样对最终的源树没有影响。我们的索引和工作树将匹配提交 G 和 git commit 根本不会做出新的提交 H。
就“提交差异”而言,这与以前的情况相同:在另一个分支上引入的任何更改(如果有),我们已经有了。但这次我们没有通过 squash-merging 获得它:反正我们已经拥有它了。