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
的引用),因为D
、C
和B
是一部分E
.
的历史
您的本地 br1
是对 E
的引用,而您的远程 br1
仍然是对 A
的引用。因此,有四个提交(B
、C
、D
和 E
)对 [=] 的历史是 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?
将 A
和 D
提交合并 (--no-ff
) 到 E
后,本地分支比远程分支提前 4 次提交(我想远程分支仍然指向 A
)。这是正确的。
让我们计算在本地分支(现在指向 E
)而不在远程分支(指向 A
)上的提交。 E
显然是其中之一。 E
,作为合并提交,有两个父项:A
(存在于远程分支上)和 D
(不存在于远程分支上)。当 git
将 E
推送到远程服务器时,它需要同时推送其父服务器(否则 E
在远程服务器上无效)。
D
需要 C
(其父级)需要 B
,需要 A
。 A
已存在于远程服务器上,链到此结束。 B
、C
、D
和 E
在远程服务器上不存在。为了保持远程服务器上数据的一致性,必须全部推送。
其余的回答处理了不是很清楚定义的原始问题。张贴者提到了 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=、C
和 B
)。
在这种情况下,命令:
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
一次提交)。只有当 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行为,我想问一下这是否正常。现在,情况是这样的(新提交添加到底部):
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
的引用),因为D
、C
和B
是一部分E
.
您的本地 br1
是对 E
的引用,而您的远程 br1
仍然是对 A
的引用。因此,有四个提交(B
、C
、D
和 E
)对 [=] 的历史是 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?
将 A
和 D
提交合并 (--no-ff
) 到 E
后,本地分支比远程分支提前 4 次提交(我想远程分支仍然指向 A
)。这是正确的。
让我们计算在本地分支(现在指向 E
)而不在远程分支(指向 A
)上的提交。 E
显然是其中之一。 E
,作为合并提交,有两个父项:A
(存在于远程分支上)和 D
(不存在于远程分支上)。当 git
将 E
推送到远程服务器时,它需要同时推送其父服务器(否则 E
在远程服务器上无效)。
D
需要 C
(其父级)需要 B
,需要 A
。 A
已存在于远程服务器上,链到此结束。 B
、C
、D
和 E
在远程服务器上不存在。为了保持远程服务器上数据的一致性,必须全部推送。
其余的回答处理了不是很清楚定义的原始问题。张贴者提到了 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=、C
和 B
)。
在这种情况下,命令:
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
一次提交)。只有当 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
|
...