如何解释 git 中的合并提交?
How to interpret a merge commit in git?
这是提交历史的示例,其中添加了一些文件(a
、b
和 c
):
* 51c3dd7 (HEAD -> master) add c
| * ded49bb (my_branch) add b
|/
* f3cea38 add a
假设我使用 git merge --no-commit --no-ff my_branch
从 my_branch
开始合并到当前分支 (HEAD
),例如here.
现在,在 MERGING
状态下,我取消暂存所有内容,然后 git commit
完成合并。
结果我仍然得到一个合并提交,即使实际上 HEAD
:
没有任何变化
* 5990dce (HEAD -> master) Merge branch 'my_branch'
|\
| * ded49bb (my_branch) add b
* | 51c3dd7 add c
|/
* f3cea38 a
我觉得这很混乱。合并不应该自动中止吗?
当然这是一个微不足道的例子,但是在 "selective" 合并之后可能会出现类似的混淆,例如here.
是否应将合并提交解释为:"Something may, or may not, have been added from this branch?"
I find this quite confusing.
关于 Git,很多人经常这么说。 :-)
在我进一步讨论之前,让我做一下这个术语说明。 merge 这里的词既可以是形容词——a merge commit——也可以是动词:merge another commit。当 a merge commit 缩写为 a merge 时,形容词形式可以变成名词。区分动词 to merge 和形容词(或名词)a merge commit 很重要。 合并提交 只是具有两个或更多父提交的任何提交。我们通常使用 git merge
命令来启动合并为动词的过程,最后以进行这些合并为名词的事情之一结束。
(可以告诉 git merge
命令执行动词合并而不进行名词合并。Git 中还有更多命令也可以执行merge-as-a-a-a-verb 而无需将 merge-as-a-a-noun。不过,我们在这里不需要担心它们。)
Shouldn't the merge automatically abort?
否:Git 假设您是认真的。
您说:开始合并过程,但不要完成它,即使它看起来有效。让我对索引大惊小怪,然后自己完成合并,通过 运行ning git commit
.1 为了理解这个,你需要了解 index 的作用,也称为临时区域,有时也称为缓存。
尽可能简单地说,索引是你构建下一个提交的地方。无论下一次提交是否是合并提交都是如此。对于普通的非合并提交,索引只保存每个文件的副本:它从 当前 提交的每个文件的副本开始,然后使用 [=13 覆盖其中一些=] 将工作树版本复制到索引中,替换旧的当前提交版本。如果你 git add
一个完全 new 的文件,采取的操作是一样的,只是文件是新的而不是被替换。如果你 git rm
一个文件 - 有或没有 --cached
- 你正在从索引中删除文件,这样文件 就不会 在下一次提交中.
在合并为动词的过程中,索引扩大了它的作用,至少在 合并冲突 的情况下是这样。在这里,索引最终持有(最多)三个 每个文件的副本。这些用 "higher stage" 编号编号。阶段槽零用于普通文件;插槽 1-3 用于合并冲突状态文件。虽然这些更高阶段编号中有任何条目,但索引不能用于提交。 Git 强制您首先解决冲突。
现在 git add
有一个新功能:它告诉 Git 它应该删除文件的三个更高阶段版本,并将正常的阶段零写入索引入口。你在这里没有做任何这些,但值得一提。
请注意,git rm
只是删除文件,而不考虑阶段槽号。同时,git reset
和 git add
一样获得一个新功能:git reset
照常将文件从当前提交复制到阶段槽 0,但像 git add
、also 删除更高的阶段插槽条目(如果存在)。如果当前提交中不存在该文件,git reset
将从索引中删除该文件。
(事实上,git add
和 git reset
总是 做这个额外的工作。当周围没有更高的阶段编号时,它什么都不做。如果文件 foo.txt
仅作为 :0:foo.txt
存在于阶段零,删除 :1:foo.txt
(同一文件的阶段槽 1 条目)无效。)
无论如何,在此合并过程结束时,索引具有将进入新合并提交的所有文件,就像它具有将进入正常非合并提交的所有文件一样。最后的 git commit
步骤注意到 git merge
为它留下的信息——具体来说,用于使新提交 成为 合并提交的额外父级(在 .git/MERGE_HEAD
).因此,git commit
进行了一次新的提交,使用索引内容就像任何提交一样,但是设置了至少一个额外的父项,如 MERGE_HEAD
文件中所记录的那样。 重要的是索引处于可提交状态。无论其内容是什么,这些文件都会成为提交中的文件。在 git merge --no-commit
和 git commit
之间 运行 的每个 (Git) 命令,作为其真正的最终目的,都对索引中的文件进行了一些修改。
1在相对较新的 Git 版本中,您可以 运行 git merge --continue
拥有 git merge
运行 git commit
给你。如果您打算停止 合并,请使用git merge --abort
,它是正古git reset --merge
的同义词。 (每个人都应该有一个足够新的 Git 来使用 git merge --abort
;一旦 git merge --continue
足够普遍,我建议在这里也使用它。)
这是提交历史的示例,其中添加了一些文件(a
、b
和 c
):
* 51c3dd7 (HEAD -> master) add c
| * ded49bb (my_branch) add b
|/
* f3cea38 add a
假设我使用 git merge --no-commit --no-ff my_branch
从 my_branch
开始合并到当前分支 (HEAD
),例如here.
现在,在 MERGING
状态下,我取消暂存所有内容,然后 git commit
完成合并。
结果我仍然得到一个合并提交,即使实际上 HEAD
:
* 5990dce (HEAD -> master) Merge branch 'my_branch'
|\
| * ded49bb (my_branch) add b
* | 51c3dd7 add c
|/
* f3cea38 a
我觉得这很混乱。合并不应该自动中止吗?
当然这是一个微不足道的例子,但是在 "selective" 合并之后可能会出现类似的混淆,例如here.
是否应将合并提交解释为:"Something may, or may not, have been added from this branch?"
I find this quite confusing.
关于 Git,很多人经常这么说。 :-)
在我进一步讨论之前,让我做一下这个术语说明。 merge 这里的词既可以是形容词——a merge commit——也可以是动词:merge another commit。当 a merge commit 缩写为 a merge 时,形容词形式可以变成名词。区分动词 to merge 和形容词(或名词)a merge commit 很重要。 合并提交 只是具有两个或更多父提交的任何提交。我们通常使用 git merge
命令来启动合并为动词的过程,最后以进行这些合并为名词的事情之一结束。
(可以告诉 git merge
命令执行动词合并而不进行名词合并。Git 中还有更多命令也可以执行merge-as-a-a-a-verb 而无需将 merge-as-a-a-noun。不过,我们在这里不需要担心它们。)
Shouldn't the merge automatically abort?
否:Git 假设您是认真的。
您说:开始合并过程,但不要完成它,即使它看起来有效。让我对索引大惊小怪,然后自己完成合并,通过 运行ning git commit
.1 为了理解这个,你需要了解 index 的作用,也称为临时区域,有时也称为缓存。
尽可能简单地说,索引是你构建下一个提交的地方。无论下一次提交是否是合并提交都是如此。对于普通的非合并提交,索引只保存每个文件的副本:它从 当前 提交的每个文件的副本开始,然后使用 [=13 覆盖其中一些=] 将工作树版本复制到索引中,替换旧的当前提交版本。如果你 git add
一个完全 new 的文件,采取的操作是一样的,只是文件是新的而不是被替换。如果你 git rm
一个文件 - 有或没有 --cached
- 你正在从索引中删除文件,这样文件 就不会 在下一次提交中.
在合并为动词的过程中,索引扩大了它的作用,至少在 合并冲突 的情况下是这样。在这里,索引最终持有(最多)三个 每个文件的副本。这些用 "higher stage" 编号编号。阶段槽零用于普通文件;插槽 1-3 用于合并冲突状态文件。虽然这些更高阶段编号中有任何条目,但索引不能用于提交。 Git 强制您首先解决冲突。
现在 git add
有一个新功能:它告诉 Git 它应该删除文件的三个更高阶段版本,并将正常的阶段零写入索引入口。你在这里没有做任何这些,但值得一提。
请注意,git rm
只是删除文件,而不考虑阶段槽号。同时,git reset
和 git add
一样获得一个新功能:git reset
照常将文件从当前提交复制到阶段槽 0,但像 git add
、also 删除更高的阶段插槽条目(如果存在)。如果当前提交中不存在该文件,git reset
将从索引中删除该文件。
(事实上,git add
和 git reset
总是 做这个额外的工作。当周围没有更高的阶段编号时,它什么都不做。如果文件 foo.txt
仅作为 :0:foo.txt
存在于阶段零,删除 :1:foo.txt
(同一文件的阶段槽 1 条目)无效。)
无论如何,在此合并过程结束时,索引具有将进入新合并提交的所有文件,就像它具有将进入正常非合并提交的所有文件一样。最后的 git commit
步骤注意到 git merge
为它留下的信息——具体来说,用于使新提交 成为 合并提交的额外父级(在 .git/MERGE_HEAD
).因此,git commit
进行了一次新的提交,使用索引内容就像任何提交一样,但是设置了至少一个额外的父项,如 MERGE_HEAD
文件中所记录的那样。 重要的是索引处于可提交状态。无论其内容是什么,这些文件都会成为提交中的文件。在 git merge --no-commit
和 git commit
之间 运行 的每个 (Git) 命令,作为其真正的最终目的,都对索引中的文件进行了一些修改。
1在相对较新的 Git 版本中,您可以 运行 git merge --continue
拥有 git merge
运行 git commit
给你。如果您打算停止 合并,请使用git merge --abort
,它是正古git reset --merge
的同义词。 (每个人都应该有一个足够新的 Git 来使用 git merge --abort
;一旦 git merge --continue
足够普遍,我建议在这里也使用它。)