如何在Git中压缩提交记录?

4

我正在尝试将我的提交压缩并将我的分支合并到主分支作为单个提交。这是我正在尝试的操作。我切换到主分支,然后执行如下命令:

git merge --squash <branch_name>

And I get

Automatic merge went well; stopped before committing as requested
Squash commit -- not updating HEAD

之后我提交了,但是却得到了以下结果。
$ git commit -m "Resolved"
On branch master
nothing to commit, working tree clean

由于某些原因,更改未被反映,并且我收到了没有提交的消息。我已经查看了stack上许多帖子和问题,但目前还没有发现有用的信息。


1
你说过 *我切换到主分支,然后运行 git merge --squash <branch_name>*,但是你展示的 git commit 失败输出状态为 On branch sample,而不是 master。这不匹配。如果你真的按照自己所说的做了,它应该显示 On branch master - torek
@torek 这是问题中的一个打字错误。我已经更正了。 - Ankur Bansal
可能是 使用Git将我的最后X个提交压缩在一起 的重复问题。 - Bamieh
2个回答

2
如果您想合并提交,请前往最新的提交(HEAD)并执行以下操作:
git reset --soft HEAD~2 && git commit

输入此命令后,您将被要求编写新提交的提交消息。
此命令将把您最近的两个提交合并为一个,并使用您编写的新提交消息。

然后按照此处所述合并您的分支。


2

我不是很清楚你正在压缩合并哪些提交,因此也不确定为什么会出现这种结果。你可以自己澄清第一个问题(对我来说并没有太大帮助,因为我没有这些提交),方法如下:

git log --decorate --oneline --graph --boundary master...<branch-name>

(note the three dots here)。这将显示您在master上拥有哪些提交,以及您将通过这两个分支的合并基础提交从<branch-name>中引入哪些提交。
无论如何,我可以做出一个很好的猜测,因为git merge的工作方式是比较此合并基础与两个分支的末端。以下是一个图形片段示例,在执行合并之前(此时,无论是常规合并还是压缩合并),这并不重要:
...--B--C--D   <-- master (HEAD)
      \
       E--F--G   <-- feature

每个大写字母代表一个提交(其真实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.txtmain.py。 因此,我们最终的更改集是保留我们在README中添加的行,保留我们的foo.py更改,并拾取doc.txtmain.py更改。 其效果是Git将所有这些应用于合并基础提交B的内容。 这为我们提供了一个新提交H的内容。(请注意H中的内容,因为它可能会回来困扰我们。)Git更新索引(下一次要进行的提交)和工作树(我们可以看到将要或已经提交的内容)以准备提交。
现在正常与压缩合并突然变得重要起来,因为如果Git要进行正常合并提交,则会执行以下操作:
...--B--C--D---H   <-- master (HEAD)
      \       /
       E--F--G   <-- feature

这个新的 合并提交 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,但这次它不再指向两个DG。这次,新的提交H仅指向D

...--B--C--D---H   <-- master (HEAD)
      \
       E--F--G   <-- feature

假设一切按照预期进行,我们确实提交了H。这将引起我认为最有可能的情况。

最有可能的情况

现在,让我们看看如果我们再次运行git merge --squash feature会发生什么。
Git从之前开始相同的步骤,找到合并基础:分支masterfeature相交的点。 这仍然是提交B
现在,Git对比两个分支的末端。这次,master的末端是H,所以两个差异是:
git diff B H
git diff B G

现在Git将合并这些更改。这一次,我们更改了READMEfoo.pydoc.txtmain.py。(记住,这些是我们通过合并得到的更改。)与此同时,他们(在feature中)以与我们相同的方式更改了foo.pydoc.txtmain.py

因此,Git接受我们所有的更改,而没有接受他们的任何更改。结果完全匹配提交H。Git现在以与之前相同的消息停止。

这次当我们运行:

git commit

为了完成任务,Git会将我们的索引(已准备提交的内容)与我们的HEAD提交进行比较,并发现它们完全、彻底、100%相同。我们已经完成了从feature分支中的所有工作。 Git会显示“没有要提交的内容”,并且“工作树干净”,因为没有可提交的内容,工作树与索引匹配。

不太可能的情况

另一种实现相同效果的方法是,如果提交系列E-F-G足够“撤消”自身,则不需要首先创建一个压缩提交H。例如,假设F是与foo.py相关的匹配更改(可能是提交C的副本),但提交G是提交E的还原。现在,除了触及doc.txtmain.py之外,从BG的变化总和包含在我们最初的B-to-D变化中。 git merge --squash有要合并的提交,但最终的源代码树没有任何影响。我们的索引和工作树将与提交G匹配,而git commit根本不会创建新的提交H
在“提交差异”方面,这与之前的情况相同:任何变化(如果有)在另一个分支上引入,我们已经拥有。但是这一次,我们没有通过压缩合并来实现它:我们只是已经拥有它了。

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