6

我对git索引包含的内容有一个模糊的概念,因为一个人执行git-adds 和git-commits,但我不知道当一个人执行 s 时这些内容会发生什么git-merge。我对了解合并失败时索引的内容特别感兴趣(例如,由于某些冲突)。

4

1 回答 1

11

对于任何给定的路径,索引中最多有四个“版本号”,编号从 0(零)到 3。我将它们称为“插槽”,就好像它们实际上存在于每个条目中一样,然后很容易索引(这个使它们更容易思考),尽管实际上只有在需要时才动态引入额外的版本。这些“虚拟插槽”可以是“空的”,这意味着文件不存在。

(实际上,一旦在索引中创建了一个条目,如果需要,它就会用一个标志位 , 标记CE_REMOVED。这很麻烦,因为整个目录充满文件可以标记为“已删除”,然后可以创建一个名为上一个目录并标记为“已添加”。让我们假设我们有固定的插槽,但那里是空的。:-))

插槽#0 是“正常”、无冲突、一切正常的条目。它包含存储在存储库中的文件的一堆缓存数据、路径名和 blob-ID(SHA-1)。

当合并成功时,一切都是“一切照旧”,所以唯一的特殊情况是冲突合并。当插槽 1、2 和/或 3 非空时,合并是“冲突的”。跳过大部分机制,会发生什么。合并使用所有插槽的“最新”名称,并且:

  • 插槽 0 留空(在解决冲突之前,您不能“提交”,除非您真的希望删除文件,否则该插槽将不再为空)。
  • 插槽 1(“基础”)填充了共同祖先版本。如果文件是新文件(在两个版本中),则此插槽为空。
  • 插槽 2(“我们的”)填充了目标(HEAD,除非您手动调用一些底层合并机制)版本。如果文件在HEAD/target-of-merge 中被删除,则此插槽为空。
  • 插槽 3(“他们的”)填充了正在合并的版本。如果文件在正在合并的修订中被删除,则此插槽为空。

一旦你解决了冲突并“git add”,#0 槽就会被你“添加”的任何东西填充,清除 #1 到 #3 中的条目——或者,如果你“git rm”冲突的文件,另一个阶段条目仍然被删除,但现在 #0 插槽仍然是空的,这也解决了冲突。

那么,更具体地说,假设您有一个共同的祖先(其中包括)这两个文件:

gronk
flibby

您在分支上cleanup,您已重命名gronkbreem,并编辑了 和flibby。您决定git merge work,他们修改gronk但没有重命名的地方,并删除了flibby. 其他一些文件干净地合并了。

该索引将包含 的三个版本bleem和两个版本flibby

$ git checkout cleanup
Switched to branch 'cleanup'
$ git merge work
CONFLICT (modify/delete): flibby deleted in work and modified
in HEAD. Version HEAD of flibby left in tree.
Auto-merging bleem
CONFLICT (content): Merge conflict in bleem
Automatic merge failed; fix conflicts and then commit the result.
$ git ls-files --stage
100644 4362aba7f3b7abf2da0d0ed558cbf5bc0d12e4b0 1   bleem
100644 49db92a61392e9fd691c4af6e1221f408452a128 2   bleem
100644 04b399c8fe321902ce97a1538248878756678ca2 3   bleem
100644 366b52546711401122b791457793a38c033838dd 1   flibby
100644 6fecb1480f45faaabc31b18c91262d03d3767cde 2   flibby
100644 7129c6edb96d08bb44ca1025eb5ae41d41be8903 0   x.txt

您可以看到bleemwith的原始(基本)版本git show :1:bleem。这是gronk在基本版本中调用的(work在这种情况下也是 in ),但现在调用它是bleem因为 git 认为你重命名gronkbleemin cleanup。(Git 在合并库之间找到重命名HEAD,然后在work必要时应用相同的重命名,如本例所示。)

同样,您可以看到work带有git show :3:bleemorgit show work:gronk的版本,以及HEAD带有以下任一选项的版本:git show HEAD:bleemgit show cleanup:bleemgit show :2:bleem(插槽 2 包含HEADakacleanup版本,并根据 中的名称命名HEAD)。

但是,对于flibby,由于它已在 中删除work,因此没有“他们的”(插槽 3)版本。

要解决冲突,您只需告知git addgit rm更新槽零条目并删除 1 到 3 条目。当然,使用git add进入slot 0 的内容就是现在工作目录中的内容,因此您通常必须先编辑文件。

顺便说一句,我在上面将插槽 2 和 3 标记为“我们的”和“他们的”。这也是git checkout对待它们的方式(git checkout --oursgit checkout --theirs让您将版本 2 或 3 写入插槽 0;这样的结帐,像大多数结帐一样,也会“擦除”其他插槽,从而解决冲突)。但是,在变基中,HEAD分支实际上是要变基的分支,而“他们的”版本是要变基的分支。因此,在我看来,我们/他们的术语并不是那么好:在变基期间很容易将其倒退。

我还应该注意git checkout -m,如果您处于冲突合并的中间,则将“重新创建”合并冲突,方法是擦除插槽 0 并根据需要“恢复”插槽 1-3 中的版本(并编写冲突的合并文件到工作目录,同时遵守您的设置的任何更改merge.conflictstyle)。

于 2014-01-23T14:40:38.387 回答