Git Merge --no-ff 复制提交

Git Merge --no-ff makes copy of commits

我今天有一个奇怪的git行为,我想问一下这是否正常。现在,情况是这样的(新提交添加到底部):

br1  br2
  A
    \ 
     B
     C
     D

现在,当我

git checkout br1
git merge --no-ff br2

变成这样(请自上而下阅读;最新提交是'E')

br1  br2
  A
  | \ 
  |  B
  |  C
  |  D
  | /
  E

好的..现在,奇怪的是;现在我打电话给 "git status";它说我在远程分支之前有 4 个提交。这是怎么回事?我不应该只提前一个提交吗?

奇怪的是,当我从 Stash(基本上是 Git Web UI 检查时,它确认了这个“4 次提交”状态,我看到了相同的提交(BC 和D) 在 "br1" 和 "br2" 下...

我假设当我使用“--no-ff”参数时,"br2" (B C D) 处的提交不会被复制到 "br1" 并且只会创建合并提交。我是不是看错了?

从技术上讲,4 次提交实际上是 br1 的一部分。如果删除 br2,提交仍将是 br1 的一部分。当您重置合并提交时,区别就来了。如果您进行硬重置,您将返回到合并提交之前的提交,即 E。当您想要回滚时,这尤其有用。所以是的,你提前四次提交,但只要你不重置 br1,你应该没问题。

另外 -no-ff 并不是要阻止 git 复制提交。这是为了将提交与 br1 的树分开。这样你就可以维护分支的历史记录和提交的上下文,而不是大量的提交都与不同的功能相关

我认为您误解了分支在 Git 中的工作方式。 Branches are lightweight,这意味着当您创建新分支或将一个分支合并到另一个分支时,不会复制任何内容。

分支是 指向 提交的引用。由于每个提交都与其之前的提交相关联,因此当您指向一个提交时,您实际上是在指向该提交的 历史

在您的示例中,E 是一个合并提交,它 将两个分支 组合在一起,创建了一个历史记录。这意味着在将 br2 合并到 br1 之后,br1(即 现在 E 的引用)将了解历史br2仍然是D的引用),因为DCB是一部分E.

的历史

您的本地 br1 是对 E 的引用,而您的远程 br1 仍然是对 A 的引用。因此,有四个提交(BCDE)对 [=] 的历史是 new 12=].

更新: 在我写完这个答案后,发帖者更改了问题。此更新回答了其余答案未涵盖的问题之一。

OK.. Now, weird thing is; now I call "git status"; it says I'm 4 commits ahead of the remote branch. How is this happening? Shouldn't I be only one commit ahead?

AD 提交合并 (--no-ff) 到 E 后,本地分支比远程分支提前 4 次提交(我想远程分支仍然指向 A)。这是正确的。

让我们计算在本地分支(现在指向 E)而不在远程分支(指向 A)上的提交。 E显然是其中之一。 E,作为合并提交,有两个父项:A(存在于远程分支上)和 D(不存在于远程分支上)。当 gitE 推送到远程服务器时,它需要同时推送其父服务器(否则 E 在远程服务器上无效)。

D 需要 C(其父级)需要 B,需要 AA 已存在于远程服务器上,链到此结束。 BCDE 在远程服务器上不存在。为了保持远程服务器上数据的一致性,必须全部推送。


其余的回答处理了不是很清楚定义的原始问题。张贴者提到了 git log --graph 和(可能)Atlassian Stash。这两个工具(以及我知道的所有其他 git 接口)都在提交历史记录中首先显示最近的提交。这个答案使用相同的约定。

git merge --no-ff对你描述的情况没有任何影响。

br1 作为当前分支,git merge br2 将提交引入的更改引入 br1,这些更改可从 br2 访问并且无法从 [=41] 访问=].根据 br1 关于 br2 的相对位置,git merge 可以创建一个新的提交(包含无法从 br1 访问的提交引入的所有更改)或者它可以只是将 br1 分支头移动到一个新位置(并且不创建任何新提交)。

在您的情况下,br2 落后于 br1 1 次提交,并且因为 A 是合并提交,所以也可以达到从 br2 访问的所有提交来自 br1.


反正git merge --no-ff是在不同的情况下使用的

假设我们有这张图:

 B <-- br2
 |
 C
 |
 D
 |
 E <-- br1
 |
...

分支 br2 是从分支 br1 创建的(当时都在提交 E)然后 br2 被检出并且三个新的提交([添加了 =17=、CB)。

在这种情况下,命令:

git checkout br1
git merge br2

不创建新分支。分支 br1 被移动到提交 B (其中 br2 是),仅此而已。现在所有可以从 br2 访问的提交也可以从 br1 访问。 br2 已成功合并到 br1

图表是这样的:

br1 --> B <-- br2
        |
        C
        |
        D
        |
        E
        |
       ...

这种合并被称为fast-forward,因为分支br1从它之前的位置"fast forward"移动到一个新的位置(可能与分支b2相反从 E 移动到 B 一次提交)。只有当 br2br1 的唯一一个子路径时才有可能(从 E 开始,每个提交都有一个子提交并且路径到达 B)。

--no-ff 发挥作用了。如果您希望此合并创建一个合并提交,其中包含提交 DCB 引入的所有更改,那么您 运行:

git checkout br1
git merge --no-ff br2

--no-ff 选项的存在禁止快进分支 b1 并强制创建新的合并提交。该图将如下所示:

 A <-- br1
 |\
 | B <-- br2
 | |
 | C
 | |
 | D
 |/
 E
 |
...