我今天有一个奇怪的git行为,我想问一下这是否正常。现在,情况是这样的(新的提交被添加到底部):
br1 br2
A
B
C
D
现在,当我制作
git checkout br1
git merge --no-ff br2
它变成这样(请从上到下阅读;最新的提交是"E")
br1 br2
A
|
| B
| C
| D
| /
E
还行。。现在,奇怪的是;现在我称之为"git 状态";它说我在远程分支之前提交 4 次。这是怎么回事?难道我不应该只做一个承诺吗?
奇怪的是,当我从 Stash(基本上是 Git Web UI)检查时,它确认了这个"4 个提交"状态,并且我在"br1"和"br2"下看到了相同的提交(B C 和 D)两个......
我假设当我使用"--no-ff"参数时,"br2"(B C D)的提交不会被复制到"br1",而只会创建合并提交。我弄错了吗?
更新:在我写完这个答案后,海报改变了问题。此更新回答了答案其余部分未涵盖的问题之一。
还行。。现在,奇怪的是;现在我称之为"git 状态";它说我在远程分支之前提交 4 次。这是怎么回事?难道我不应该只做一个承诺吗?
将提交合并(--no-ff
)后A
并D
E
,本地分支比远程分支早 4 次提交(我想远程分支仍然指向 A
)。这是正确的。
让我们计算一下本地分支(现在指向 E
)和不在远程分支(指向 A
)上的提交。 E
显然是其中之一。 E
作为合并提交,有两个父级:A
(存在于远程分支上)和D
(不存在于远程分支上)。当git
将E
推送到远程服务器时,它需要推送其父级(否则E
在远程服务器上无效)。
D
需要需要B
C
(其父级)需要A
。 A
已经存在于远程服务器上,链到此结束。 远程服务器上不存在B
、C
、D
和E
。必须推送所有这些数据,以保持远程服务器上数据的一致性。
答复的其余部分处理了定义不是很明确的原始问题。海报提到了git log --graph
和(可能)Atlassian Stash。这两个工具(以及我知道的所有其他git
接口)都首先呈现提交历史记录中的最新提交。此答案使用相同的约定。
git merge --no-ff
在您描述的情况下没有任何影响。
br1
作为当前分支,git merge br2
br1
提交引入的更改,这些更改可从br2
访问,而无法从br1
访问。根据br1
在br2
上的相对位置,git merge
可以创建一个新的提交(其中包含从br1
无法访问的提交引入的所有更改),或者它可以只是将br1
分支头移动到新位置(并且不创建任何新提交)。
在您的情况下,br2
落后于 br1
1 次提交,并且由于A
是合并提交,因此也可以从 br1
访问从 br2
访问的所有提交。
无论如何,git merge --no-ff
用于不同情况。
假设我们有这个图:
B <-- br2
|
C
|
D
|
E <-- br1
|
...
分支br2
是从分支br1
创建的(当时两者都在提交E
),然后br2
被签出并添加了三个新的提交(D
、C
和B
)。
在此情况下,命令:
git checkout br1
git merge br2
不要创建新分支。分支br1
被移动到提交B
(br2
所在的位置),仅此而已。现在,可以从br2
访问的所有提交也可以从br1
访问。 br2
成功合并为br1
。
这是图形的外观:
br1 --> B <-- br2
|
C
|
D
|
E
|
...
这种合并称为fast-forward
,因为分支br1
从其先前的位置"快进"移动到新位置(可能与一次从E
移动到B
一次提交分支b2
相反)。只有当br2
是br1
的唯一子路径时,才有可能(从E
开始,每个提交都有一个子提交,路径到达B
)。
--no-ff
就在这里发挥作用了。如果您希望此合并创建一个合并提交,其中包含提交D
、C
和 B
引入的所有更改,请运行:
git checkout br1
git merge --no-ff br2
--no-ff
选项的存在禁止分支b1
的快速转发,并强制创建新的合并提交。图形将如下所示:
A <-- br1
|
| B <-- br2
| |
| C
| |
| D
|/
E
|
...
我认为你误解了分支在 Git 中的工作方式。分支是轻量级的,这意味着当您创建新分支或将一个分支合并到另一个分支时,不会复制任何内容。
分支是指向提交的引用。由于每个提交都链接到其以前的提交,因此当您指向一个提交时,您实际上是指向该提交的历史记录。
在您的示例中,E
是一个合并提交,它将两个分支组合在一起,从而创建单个历史记录。这意味着在将br2
合并到br1
后,br1
(现在是对E
的引用)将了解br2
的历史(仍然是对D
的引用),因为D
、C
和B
是E
历史的一部分。
您的本地br1
是对E
的引用,而您的远程br1
仍然是对A
的引用。因此,有四个提交(B
、C
、D
和E
)是br1
历史的新提交。
从技术上讲,这 4 个提交实际上是 br1
的一部分。如果删除br2
,提交仍将是br1
的一部分。当您重置合并提交时,差异就出现了。如果您进行硬重置,您将在合并提交之前返回提交,即 E
.当您想要回滚时,这尤其有用。所以是的,你领先四次提交,但只要你不重置br1
,你应该没问题。
另外-no-ff
不要阻止 git 复制提交。这是为了使提交与br1
树分开。这样,您就可以维护分支的历史记录和提交上下文,而不是与不同功能相关的大量提交