Git merge --squash和--no-commit的区别

70

正如标题所示,我对git merge --squashgit merge --no-commit之间的区别不是很清楚。

据我理解,在git merge帮助页面中,这两个命令都会让我处于更新后的工作树状态,仍然可以进行编辑,最终提交(或多次提交)。

有人可以澄清一下这两个选项的区别吗?我应该在何时使用其中一个而不是另一个?

3个回答

85
git merge --no-commit

这就像普通的合并一样,但不会创建合并提交。此提交将成为合并提交:当您查看历史记录时,您的提交将显示为普通合并。
git merge --squash

这将把更改合并到您的工作树中,而不创建merge commit。当您提交合并后的更改时,它将看起来像是分支上的新“正常”提交:在历史记录中没有合并提交。这几乎就像您对所有合并的更改进行了cherry-pick。

3
合并提交并不是一种特殊的提交,唯一的区别在于它有多个父节点。你可以使用 git log --parents 命令查看一个提交的父节点(使用 git log --merges 则只显示这种合并提交)。 - Philipp Wendler
6
所以基本上:如果使用合并提交,我可以通过查看历史记录知道这个提交是合并的结果(也保留了哪些分支贡献了此次合并的信息吗?)。而如果使用 --squash,就无法知道这个提交是合并的结果。我的理解正确吗? - quaylar
5
@quaylar,是的,你理解得没错。然而,并不保证您可以看到被合并的分支,因为分支可能会被删除、重命名等。 - ralphtheninja
4
我建议你尝试使用命令,亲自查看它在历史记录中的效果。请记住,在 git 中你可以随时撤销操作,只需执行 "git reset --hard HEAD" 命令即可。请注意不要改变原意,使翻译通俗易懂。 - ralphtheninja
22
这就像是一个普通合并,但不会创建一个合并提交。而这个提交将是一个合并提交:在查看历史时,你的提交将显示为一个普通的合并。"我是不是唯一一个觉得这个解释完全没有意义?而且"压缩"是把所有更改都放入一个提交中(这与挑选多个提交非常不同)? - Simon East
显示剩余7条评论

0

基本上,在最后没有这样的区别,但是看下面的草图,一旦你checkout master分支

          A---B---C topic
         /         \
    D---E---F---G---H master        (from the documentation https://git-scm.com/docs/git-merge)
  • git merge topic:将指定分支(自从与当前分支有所不同的历史分歧点开始)中的更改合并/重演到当前分支,并在一个新提交 H 中记录结果,同时记录两个父提交的名称和用户描述更改的日志消息。然后像往常一样将其推送到上游。
$ git log --all --decorate --oneline --graph

*   72e576d (HEAD -> master) H Merge branch 'topic'
|\
| * dda0d97 (topic) C
| * 3471c39 B
| * cfb8410 A
* | a1c7e23 G
* | 5c0b97b F
|/
* c463d89 E
* 2312a5b D

$ git show HEAD -m

commit 72e576d (from a1c7e23) (HEAD -> master)
Merge: a1c7e23 dda0d97

    H Merge branch 'topic'

diff --git a/A b/A
diff --git a/B b/B
diff --git a/C b/C

commit 72e576d (from dda0d97) (HEAD -> master)
Merge: a1c7e23 dda0d97

    H Merge branch 'topic'

diff --git a/F b/F
diff --git a/G b/G

  • git merge --no-commit :与上面相同,但是在创建新提交之前停止,让用户有机会检查和进一步调整合并结果。然后由您决定提交已添加到索引中的内容并像往常一样将其推送到上游。
$ git log --all --decorate --oneline --graph

*   f576f37 (HEAD -> master) H
|\
| * dda0d97 (topic) C
| * 3471c39 B
| * cfb8410 A
* | a1c7e23 G
* | 5c0b97b F
|/
* c463d89 E
* 2312a5b D

$ git show HEAD -m

commit f576f37 (from a1c7e23 ) (HEAD -> master)
Merge: a1c7e23 dda0d97

    H

diff --git a/A b/A
diff --git a/B b/B
diff --git a/C b/C

commit f576f37 (from dda0d97) (HEAD -> master)
Merge: a1c7e23 dda0d97

    H

diff --git a/F b/F
diff --git a/G b/G

  • git merge --squash :工作区和索引状态就像进行了真正的合并一样(除了合并信息),但不进行提交,从而允许在当前分支的顶部创建单个提交。同样,像以前一样,由您来提交和推送到上游。
$ git log --all --decorate --oneline --graph

* 118019a (HEAD -> master) H
* a1c7e23 G
* 5c0b97b F
| * dda0d97 (topic) C
| * 3471c39 B
| * cfb8410 A
|/
* c463d89 E
* 2312a5b D

$ git show HEAD -m

commit 118019a (HEAD -> master)

    H

diff --git a/A b/A
diff --git a/B b/B
diff --git a/C b/C

注意: 快进式更新不会创建合并提交,因此,为确保您的分支不被更改/更新,请使用--no-ff选项与--no-commit选项。


0
git merge --no-commitgit merge --squash之间的区别在于,在第二种情况下,下一个提交将只有一个父提交。
例如,在这种情况下:

enter image description here

命令

git merge dev --no-commit
git commit -m "msg"

或者简单地使用git merge dev -m "msg"将会产生。

enter image description here

另一方面
git merge dev --squash
git commit -m "msg"

给你

enter image description here

提交 E 和 E' 将给你完全相同的工作目录。区别在于它们的父节点数量。
(个人而言,我不会将此操作称为“压缩”。)

嘿,你是怎么生成这些酷炫的图表的? - undefined
@Kashif 我用Inkscape制作了它们。 - undefined

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