恢复git合并冲突标志

时间:2017-05-20 04:30:32

标签: git merge conflict restore flags

我正在尝试找出一种与团队其他成员共享合并冲突的方法。我们有一些非常大的分支,合并它们会产生很多冲突。我尝试了几种不同的方法,我当前的尝试涉及将处于冲突状态的文件推送到远程仓库(将合并标记保留在文件中),然后运行一个烦人的长别名来grep浏览文件并重新创建手动合并文件(LOCAL,BASE,REMOTE)。

我最近找到了

  

git checkout --conflict = merge - (file)

命令,在本地分支上运行良好,但只要它被推送到远程,该命令就不再能够恢复合并标志。

有没有办法强制git将文件重新标记为冲突,以便人们可以使用普通的合并工具来解决它们?

1 个答案:

答案 0 :(得分:4)

  

有没有办法强制git将文件重新标记为冲突,以便人们可以使用普通的合并工具来解决它们?

不,不管怎么说都没有编写自己的代码。 (有人应该编写一些代码,也许应该是 - 现在是时候为此设置一个工具了。但是有很多极端情况很难实现。)

这里的问题是Git中的冲突合并由存储在Git&#39> 索引中的状态表示。

退一步,让我们定义索引,以及当前提交HEAD,以及工作树(或工作)树,工作树和一堆类似的变种):

  • 当前提交(也称为HEAD或HEAD)非常简单。 (我喜欢在这样的计算机文本布局中使用HEAD来明确表示Git名称HEAD。您还可以在Git 1.8.5或更高版本中使用@。特殊名称是指当前分支,如果有当前分支,则当前分支随后找到该分支的 tip commit ,即当前提交。或者,在"分离的HEAD"模式下,HEAD直接包含当前提交的哈希ID。无论哪种方式,都命名当前提交。)

  • 工作树非常简单,就是您工作的地方。 Git的内部数据结构保存了提交和版本化的文件副本,不适用于任何其他内容,因此Git将版本提取到普通文件中,然后您可以照常阅读和操作。

    工作树还可以保存您尚未提交但不想提交的文件。这些是未跟踪的文件。 (从技术上讲,未跟踪文件是工作树中尚未包含在索引中的任何文件,但我们还没有定义索引。:-))

    Git倾向于抱怨未跟踪的文件未被跟踪;您可以通过在.gitignore文件中列出文件或路径名称模式来关闭这些投诉。请注意,向.gitignore 添加文件名不会使文件无法跟踪。如果跟踪该文件,则会对其进行跟踪。 .gitignore条目主要是关闭投诉,当您说"添加所有文件时,Git也不会自动添加这些未跟踪的文件。

  • 索引位于这两者之间。通常,当您首次签出提交或分支时,索引内容与HEAD提交内容匹配,Git也会将其提取到工作树中。然后,您可以随意修改工作树,但索引将继续匹配HEAD。您必须git add个文件将它们从工作树复制回索引。

    因此,索引基本上代表您将要进行的下一次提交。运行git commit时,Git将索引转换为新的提交(自动成为新的HEAD提交)。只有您将复制回索引的内容才会被提交,这意味着您可以通过一次git add一些文件将更改拆分为多个提交。 (并且,您可以使用git add -p仅添加文件的部分,而不是整个文件,以便索引版本本身位于HEAD提交版本和工作树之间版本)。

如果您从未进行任何合并,或者从未发生任何合并冲突,我们可以在此处停止并完成索引。当然,你正在进行合并,他们正在发生冲突,所以我们需要仔细观察。

索引有四个"阶段插槽"每个索引条目

索引按工作树中的路径名记录文件。如果您修改其中一些文件,并且git add它们已准备好进行下一次提交,则会更新文件的索引版本。但是如果在冲突合并期间运行git ls-files --stage,则会出现一个秘密。没有其他时间这通常仅在冲突的合并期间显示出来。秘诀是每个文件可以在编号为 stage slots 三次的索引中。 Slot zero是正常的日常插槽:

$ git ls-files --stage
[snip]
100644 d8d18736e74c7a5f61d794770a2dd94786501d12 0   Makefile
100644 046dcab7645305cbf4b94adef54a859234ac3caa 0   README
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0   lib/__init__.py

全零值列表示每个文件都在插槽0中。

在冲突的合并期间,README或其他名称之一在插槽1,2和3中最多可包含三个条目。在这种情况下,Git知道存在合并冲突。插槽1保存文件的合并基本版本。插槽2包含HEAD--ours版本,插槽3包含同一文件的MERGE_HEAD--theirs版本。 (根据定义,时隙零在此时未被占用。)

其中一些插槽可能为空。 (我曾经说过,最多其中一个可能是空的,但我错了:通过重命名/重命名或重命名/删除冲突,我们实际上可以看到多个空插槽。)空插槽或插槽表示< em> no 文件在合并的三个输入中的一个或多个中具有该名称。但是,任何更高编号的条目的存在表明存在冲突的合并。

正如您所见,您的工作就是解决这些冲突。命名文件的工作树版本通常包含Git在此时解决合并的最佳尝试,但由于Git无法解决冲突,因此工作树版本中包含冲突标记。解决冲突后,您应该像往常一样在路径上运行git add(如果解决方案是删除文件,则git rm)。这会清除较高级的插槽,同时还将工作树文件复制到插槽零,除非文件被真正删除。现在冲突得到了解决。

如果您正处于合并过程中,尚未提交结果,并且已编辑或甚至已解决文件但希望将其恢复到原始的未合并状态,则可以按照您的说明使用:

git checkout -m -- <path>

(或与--conflict相同)。您可以添加=<style>,以便您指定冲突样式:mergediff3(我更喜欢diff3,其中包含文件合并基础版本的文本) 。如果您创建了一个零阶段,则会删除阶段零条目,并恢复较高阶段的冲突条目。这种特殊形式的git checkout,但要求原始未合并的条目在索引中可用。

在任何情况下,都无法进行新的提交,直到所有更高级别的索引条目都得到解决。也就是说,如果git ls-files --stage显示阶段为零的任何条目,则您可能不会进行新的提交。

  

...只要它被推送到远程,这个[git checkout -m]命令就不再能够恢复合并标志。

事实上,在此之前很久。一旦提交,恢复冲突的能力就会消失。这将永久清除所有较高阶段的索引条目。但是你无法推送索引,也无法推送文件:你只能推送提交。这意味着要推送部分合并(让其他人处理它),您必须解决合并和提交。现在它不再进行中,不能再进行中了。

我们需要的是一个可以保存完整索引状态,工作树文件,合并状态的工具,包括两个提交HEADMERGE_HEAD的ID - 这意味着ID合并基础 - 甚至可能是未跟踪和/或忽略的文件(la git stash)到存储在非分支引用上的特殊提交或提交集合。然后,可以将此提交或这些提交从一个存储库传输到另一个存储库。同一工具的反向版本可以恢复合并状态,索引状态和工作树。存在构建此类工具所需的所有组件(因为git ls-files --stagegit update-index都存在)。但是编写这个工具对会很复杂,可能至少和git stash脚本一样困难。