当Git合并由于冲突或由于用户使用--no-commit
选项要求而停止时,则认为合并仍在进行中,文件{{1 }}。
此状态通常在提交合并结果或中止合并时结束。在后一种情况下,合并所引入的更改将被撤销。
是否有任何方法可以完成“正在进行的合并” 状态而不产生提交,也不会丢失合并中的更改?让我们假设所有可能的冲突已解决。 1 这类似于为进行樱桃采摘,还原和变基提供的$GIT_DIR/MERGE_HEAD
选项。
一种明显的方法是--quit
,但是在进行合并时,这会出错。
对于这个问题,我没有特定的用例,但是我想知道关于Git UI的完整性。
1 就像torek精心阐述的answer所示,未解决的冲突表示在索引槽1到3中的条目,这仅在正在进行的合并中才有意义,严格来说甚至构成一个。这意味着:只要存在未解决的冲突,就可以进行合并。因此,要使该问题反映一个恰当的问题,就必须将其解决所有可能的冲突问题。
答案 0 :(得分:2)
有什么方法可以完成“正在进行的合并”状态而无需生成提交?
不要打扰。提交合并git reset --soft @~
,您就完成了。
答案 1 :(得分:2)
使用Git 2.23(2019年第三季度),这将变得更加容易(不再使用git reset
),因为“ git merge
”学会了“ --quit
”选项,可以清除正在进行的合并而使工作树和索引仍然混乱不堪。
请参见commit f3f8311之前的commit b643355(2019年5月18日)和Nguyễn Thái Ngọc Duy (pclouds
)(2019年5月9日)。
(由Junio C Hamano -- gitster
--在commit c4a38d1中合并,2019年6月13日)
merge
:添加--quit
这允许取消当前合并,而无需重置工作树/索引,这就是--abort的用途。
与其他--quit
一样,当您忘记自己正处于合并过程中并且已经离开并执行其他操作时,通常会使用此方法。
到您意识到的时候,您甚至无法继续合并。这还将使所有正在进行的命令
am
,merge
,rebase
,revert
和cherry-pick
,取全部三个--abort
,--continue
和--quit
(bisect
有一个 不同的用户界面)。
文档位于commit 437591a的Phillip Wood (phillipwood
)(2019年6月17日)中。
(由Junio C Hamano -- gitster
--在commit 0af6d5d中合并,2019年7月9日)
忘记当前正在进行的合并。
保持索引和工作树不变。
答案 2 :(得分:1)
您主要必须执行git reset
,该操作会重置--mixed
。那确实会丢失一些信息,这意味着答案是肯定的。如果没有冲突要解决,则可以执行git add -u
或git add .
或类似操作来恢复丢失的信息;但是无论如何,要使这个答案有意义,还有一些其他事情要实现。
首先,Git根本没有真正使用您的工作树。可以肯定的是,它确实将文件放入您的工作树中,并且将在各种条件下(例如,与 index 的差异)检查它们的更改。 git add -u
,或者在由于另一个git checkout
而破坏工作树文件之前。而且,当然,git merge
以熟悉的形式将合并冲突写入工作树文件:
$ cat file
some contents
a few lines
of contents just
<<<<<<< HEAD
to make some
||||||| merged common ancestors
to make
=======
to make
>>>>>>> branch
things more
interesting
(这是merge.conflictStyle
设置为diff3
的一部分,用于添加||||||| merged common ancestors
部分,以便您可以看到发生合并冲突之前的情况-在这种情况下,之前是尾随空格,我通过移除branch
来固定空格,但在master
上通过添加更多单词来固定空格。
index 是真正的动作所在。这个东西-这个索引,Git也称它为登台区域或缓存,这取决于谁/哪个部分的Git进行了调用-包含版本将进入 next 提交的文件的数量。
就像工作树一样,索引纯粹是临时的。但是,从某种意义上说,它对Git的影响要大于工作树。您可以建立一个--bare
储存库;这样的存储库没有 工作树,但是它仍然具有提交,并且仍然具有索引。 1 Git可以将提交读入索引,并写入新的提交从索引开始,所有这些都不需要工作树。
通常情况下,索引中的内容非常简单。 Git中的每次提交都会保存每个文件的完整副本。它以特殊的,只读的,压缩的,仅Git的形式保存该文件。我喜欢将这些文件称为“冻干”。每个这样的文件都有一个唯一的blob哈希值,即文件内容唯一的哈希值。索引中的内容恰好是这些相同的冻干文件,或更确切地说是blob散列。提交中的文件和索引中的文件之间的主要区别在于,索引中的文件可以用新的不同的冻干文件(不同的blob散列)覆盖。好了,您可以再次添加新文件或删除现有文件,都以这种冻干形式进行。
无论如何,在Git中执行新提交的动作如此之快 ,因为它真正要做的就是获取索引中已经存在的所有冻干文件,并记录其blob哈希值在提交中(通过更多名为 trees 的Git对象,但这只是实现细节)。新提交将获得一个新的唯一哈希ID。新提交会记住先前当前提交的哈希ID;然后,通过将哈希ID写入HEAD
或直通到分支名称的行为,新的提交将成为当前的提交,并成为当前分支的头(如果您在分支上)。
因此,在通常的情况下,在一个非裸露的存储库中,每个文件总是有三个个活动副本。如果您有一个名为README.md
的文件,则实际上有:
HEAD:README.md
:这是当前提交中的冻结副本。您无法更改它,Git也无法更改。 (您可以将HEAD
移至另一个提交,但这不会影响此提交的README.md
。):README.md
:这是索引中的副本。它采用的是冻干格式,但是您可以随时将其替换为新副本。README.md
:这是您可以看到,品尝和闻到的唯一文件,或与计算机上的文件有关的任何文件。它不是不是冻干格式。它在您的工作树中,因此您可以处理任何其他文件。一次同时影响这三个文件的主要命令(忽略明显的git checkout <branch>
等一次影响许多文件的命令)是
git checkout [commit] [--] paths
:从某个提交中取出单个文件,将它们复制到索引中,然后再复制到工作树中。git reset [commit] [--] paths
:将某些提交中的单个文件复制到索引中,而不接触工作树。git add [--] paths
:将单个文件从工作树复制到索引,并在复制过程中将其冻干。但是,当您开始合并时,索引将扮演新的扩大角色。现在,索引中不仅有每个文件的一个副本,而且最多可以有三个个副本。上例中的file
的三个副本是:
:1:file
:这是来自合并基础提交的文件,是工作树冲突文件中提到的合并的共同祖先。:2:file
:这是来自HEAD
提交的文件。:3:file
:这是另一个提交的文件,在这种情况下,该提交位于branch
的尖端。目前没有:0:file
,名称:file
简写为:0:file
,因为存在这三个非零的阶段编号的文件。
当您最终解决所有冲突并运行git merge
或git commit
时,git merge --continue
进行合并提交的另一件事是另一次提交的原始哈希ID。因此,Git已将其保存到.git
(如您所述的.git/MERGE_HEAD
)中的文件中。因此,合并正在进行的事实记录在两个位置:此.git/MERGE_HEAD
文件,以及存在未合并的索引条目的事实。
要停止合并,必须必须将所有索引条目放回零阶段。这意味着您必须选择一些文件以从阶段1、2和/或3移到阶段0,或使用工作树副本(通过git add
)放入阶段0,或使用文件。 HEAD
复制到第零阶段。
现在,如果它们已经是所有处于零阶段的 ,要么是因为您解决了所有冲突,要么是因为您没有冲突,而仅使用git merge --no-commit
进入了这种状态,这会有一个非常不利的副作用:git reset --mixed
将HEAD
提交读入索引,这样您就失去了所有已经添加的已解决冲突。但是那些添加的已解决冲突现在也在您的工作树中,因此您可以(可能)将它们放回去(但请在脚注之前查看最后一段)。
从定义上讲,任何在零阶段没有的条目都意味着存在正在进行的未解决的合并。如果不销毁一些正在进行的未解决的合并,就无法解决。
git reset --mixed
具有删除.git/MERGE_HEAD
的附加副作用,因此不再有正在进行的合并。这样就解决了另一个问题。最大的问题是如何处理更高级别的索引条目,而该特定问题只能通过破坏信息来解决。无论您要保留的是信息,还是必须完成。
如果出于某种原因,您巧妙地上演了file
的某个版本,而该版本不在工作树的HEAD
提交 nor 中,则此{{1 }}将破坏其哈希值。因此,您可能想使用git reset --mixed
将其提取到某个位置的临时文件中,或者至少记录其blob哈希并使用git checkout-index
进行恢复。除此之外,答案主要只是git update-index --index-info
。
1 确实,它也可能也没有索引。毕竟,当您将工作树添加到非裸仓库时,实际上是同时添加了索引和工作树。但是Git的某些内部部分坚持或曾经坚持锁定索引,因此它必须有一个索引才能锁定。