如何在 Git 中压缩提交?

Posted

技术标签:

【中文标题】如何在 Git 中压缩提交?【英文标题】:How to squash commits in Git? 【发布时间】:2017-10-16 16:40:28 【问题描述】:

我正在尝试压缩我的提交并将我的分支合并到 master 作为一个单一的提交。这就是我正在尝试的。我切换到 master 分支,然后我做

git merge --squash <branch_name>

我明白了

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

由于某种原因,这些更改没有反映出来,我收到的消息没有提交。我已经在堆栈上浏览了许多帖子和问题,但直到现在都没有任何帮助。

【问题讨论】:

您说 我切换到 master 分支,然后 [运行 git merge --squash &lt;branch_name&gt;] 但随后您将 git commit 故障输出状态显示为 On branch sample。那不是master。有些东西不匹配。如果你正在做你告诉我们你正在做的事情,它会说On branch master @torek 这是问题中的错字。我已经更正了。 Squash my last X commits together using Git的可能重复 【参考方案1】:

我并不完全清楚你正在合并什么提交,因此你为什么会得到这个结果。您可以通过以下方式向自己澄清第一个问题(它对没有太大帮助,因为我没有提交):

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

(注意这里的三个点)。这将显示您现在在 master 上的提交,以及您将从 &lt;branch-name&gt; 通过这两个分支的合并基础提交引入的提交。

不过,无论如何,我可以做出一个很好的猜测,因为git merge 的工作方式是将这个合并基础与两个分支提示进行比较。这是在进行合并之前的示例图片段(此时,这是常规合并还是壁球合并都没有关系):

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

每个大写字母代表一个提交(其真实 ID 是 Git 哈希 ID,例如 a9f3c72 或其他)。 merge base 这里的提交是提交B:它是提交链的位置,同时从masterfeature 开始并向后工作(在此图中向左),首先走到一起。换句话说,提交Bboth 分支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.txtmain.py。所以我们的最后一组更改是保留我们在README 中添加的行,保留我们的foo.py 更改,并选择doc.txtmain.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> 提交Dmaster 的前一个提示,并提交Gfeature 的前一个也是当前的提示。

如果 Git 要进行 squash 提交,但是,它会在说完之后停止:

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

它让我们做出提交。一旦我们做出这个提交,我们就会得到新的提交 H,但是这一次它没有指向 both D G。这一次,新的提交 H 指向 onlyD

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

假设这一切都按照它应该的方式工作,我们确实实际上是提交H。这就产生了我认为最有可能的情况。

可能的情况

让我们看看如果我们再次运行git merge --squash feature会发生什么。

Git 和以前一样开始,通过找到合并基础:分支 masterfeature 的连接点。再次提交 B

现在 Git 区分两个分支提示。这次master的tip是H,所以两个diff是:

git diff B H
git diff B G

Git 现在会合并这些更改。这一次,我们更改了READMEfoo.pydoc.txtmain.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 的恢复。现在,从 BG 的更改总和不再涉及 doc.txtmain.py 包含在我们原来的 B-to-D 更改中。 git merge --squash 已提交合并,但同样对最终的源树没有影响。我们的索引和工作树将匹配提交 Ggit commit 根本不会做出新的提交 H

就“提交差异”而言,这与以前的情况相同:在另一个分支上引入的任何更改(如果有),我们已经有了。但这次我们没有通过 squash-merging 获得它:反正我们已经拥有它了。

【讨论】:

【参考方案2】:

如果您想压缩提交,请转到 HEAD(last) 提交,然后:

git reset --soft HEAD~2 && git commit

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

然后合并你的分支,它是如何描述的here。

【讨论】:

以上是关于如何在 Git 中压缩提交?的主要内容,如果未能解决你的问题,请参考以下文章

如何在拉取请求中压缩提交

如何在 C# 中压缩(和解压缩)字节 []?

如何在 Android 中压缩字符串

如何使用 postcss 在顺风中压缩文件大小?

在 python 中压缩文件时如何保留目录?

如何在 laravel 5 中压缩 HTML