我不是很清楚你正在压缩合并哪些提交,因此也不确定为什么会出现这种结果。你可以自己澄清第一个问题(对我来说并没有太大帮助,因为我没有这些提交),方法如下:
git log --decorate --oneline --graph --boundary master...<branch-name>
(note the three dots here)。这将显示您在
master
上拥有哪些提交,以及您将通过这两个分支的合并基础提交从
<branch-name>
中引入哪些提交。
无论如何,我可以做出一个很好的猜测,因为
git merge
的工作方式是比较此合并基础与两个分支的末端。以下是一个图形片段示例,在执行合并之前(此时,无论是常规合并还是压缩合并),这并不重要:
...
\
E
每个大写字母代表一个提交(其真实ID是Git哈希ID,如a9f3c72或其他)。在这里,“合并基础”提交是提交B:它是从同时从master和feature开始向后(在此图表中向左)工作的提交链首次汇聚的地方。换句话说,提交B是既在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
进行了
相同的更改,则我们不需要他们的更改:它已被
我们的更改覆盖。
假设我们更改了
README
,我们和他们都在
foo.py
中修复了
相同的问题,但他们还更改了
doc.txt
和
main.py
。 因此,我们最终的更改集是保留我们在
README
中添加的行,保留我们的
foo.py
更改,并拾取
doc.txt
和
main.py
更改。 其效果是Git将所有这些应用于合并基础提交
B
的内容。
这为我们提供了一个新提交H
的内容。(请注意
H
中的内容,因为它可能会回来困扰我们。)Git更新索引(下一次要进行的提交)和工作树(我们可以看到将要或已经提交的内容)以准备提交。
现在正常与压缩合并突然变得重要起来,因为如果Git要进行
正常合并提交,则会执行以下操作:
...
\ /
E
这个新的 合并提交 H
结合了提交 C-D
和提交 E-F-G
中所做的所有工作,它会指向 两个 提交:先前的 master
分支的最新提交 D
和当前 feature
分支的最新提交 G
。
然而,如果 Git 要进行 squash 提交,那么在输出这些信息后就会停止:
Automatic merge went well; stopped before committing as requested
Squash commit -- not updating HEAD
$
它促使我们提交。一旦我们提交了这个,我们就得到了新的提交H
,但这次它不再指向两个D
和G
。这次,新的提交H
仅指向D
:
...
\
E
假设一切按照预期进行,我们确实提交了
H
。这将引起我认为最有可能的情况。
最有可能的情况
现在,让我们看看如果我们再次运行
git merge --squash feature
会发生什么。
Git从之前开始相同的步骤,找到合并基础:分支
master
和
feature
相交的点。 这仍然是提交
B
。
现在,Git对比两个分支的末端。这次,
master
的末端是
H
,所以两个差异是:
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会显示“没有要提交的内容”,并且“工作树干净”,因为没有可提交的内容,工作树与索引匹配。
不太可能的情况
另一种实现相同效果的方法是,如果提交系列
E-F-G
足够“撤消”自身,则不需要首先创建一个压缩提交
H
。例如,假设
F
是与
foo.py
相关的匹配更改(可能是提交
C
的副本),但提交
G
是提交
E
的还原。现在,除了触及
doc.txt
和
main.py
之外,从
B
到
G
的变化总和
包含在我们最初的B
-to-D
变化中。 git merge --squash
有要合并的提交,但最终的
源代码树没有任何影响。我们的索引和工作树将与提交
G
匹配,而
git commit
根本不会创建新的提交
H
。
在“提交差异”方面,这与之前的情况相同:任何变化(如果有)在另一个分支上引入,我们已经拥有。但是这一次,我们没有通过压缩合并来实现它:我们只是已经拥有它了。
git merge --squash <branch_name>
*,但是你展示的git commit
失败输出状态为On branch sample
,而不是master
。这不匹配。如果你真的按照自己所说的做了,它应该显示On branch master
。 - torek