【发布时间】:2014-06-30 06:26:48
【问题描述】:
谁能告诉我这两个命令有什么区别:
git merge --squash
和
git merge --no-ff
【问题讨论】:
-
我更正了您问题的论证顺序,因为它似乎不是问题的重点,处理它会在答案中增加不必要的噪音。
谁能告诉我这两个命令有什么区别:
git merge --squash
和
git merge --no-ff
【问题讨论】:
我认为你的问题表明了一些误解。 --no-ff 和 --squash 不是对立的,而是微妙不同的操作。阅读时请记住这一点。
help page for merge 对--squash 说如下:
--squash和--no-squash生成工作树和索引状态,就好像发生了真正的合并(合并信息除外),但实际上并没有 提交或移动 HEAD,也不记录 $GIT_DIR/MERGE_HEAD 到 导致下一个 git commit 命令创建一个合并提交。这 允许您在当前分支之上创建单个提交 其效果与合并另一个分支相同(或更多的情况下 章鱼)。
使用 --no-squash 执行合并并提交结果。这个选项 可用于覆盖 --squash。
这有点令人困惑,需要了解git 的内部结构。首先,我们需要了解常规提交和合并提交之间的区别。常规提交有一个父级,并且只是应用于之前提交的变更集:
A --> B --> C
一个合并提交有多个父级,它是树中的一个位置,您将两个或多个谱系放在一起:
A --> B --> F
/
C --> D - /
看看A、B、C 和D 是常规提交,但F 是合并提交,因为它有多个父级(B 和D)?这就是git merge --no-ff 会产生的结果。它强制 Git 创建一个合并提交以将两个历史记录放在一起。
git merge --squash 会做一些不同的事情。它会阻止 Git 创建合并提交,但仍会引入 C 和 D 所做的更改,因此您的树看起来像这样:
A --> B --> F'
C --> D
F' 包含对 C 和 D 所做的更改,但没有迹象表明您在存储库中合并了两棵树。
--no-ff 是一个稍微不同的操作。即使它不是真的必要,它也会强制 Git 创建一个合并提交。作为参考,以下是手册中关于 --no-ff 的内容,与 --ff-only 正好相反:
--no-ff即使合并解析为快进,也要创建合并提交。
--ff-only拒绝合并并以非零状态退出,除非当前 HEAD 已经是最新的,或者合并可以解决为 快进。
要理解,最好看个例子:
A --> B --> C --> D --> E
| |
'master' 'topic'
如果你有这棵树,在 master 分支上并运行 git merge,Git 将执行所谓的“快进”合并。由于这两个历史之间没有分歧,Git 可以将master 分支移动到topic 所在的位置,而无需做任何有趣的事情。它看起来像这样:
A --> B --> C --> D --> E
|
'topic'
'master'
topic 和 master 都指向同一个分支。现在,某些工作流程策略要求您在每次合并回master 时创建一个合并提交。这样可以保留分支的历史。无论哪种方式,您都会就应该如何完成而争论不休,但我不会在这里讨论这些。
如果你在同一棵树上使用 git merge --no-ff,它会强制 git 创建一个合并提交,给你一个像这样的树:
'master'
|
A --> B -------------> F
\ /
C --> D --> E
|
'topic'
其中F 是新的合并提交--no-ff 强制Git 创建。
【讨论】: