git - git索引的内容在 merge 期间如何演变( merge 失败后索引中的内容)?

标签 git git-merge git-index

我对git索引包含的内容与git-addgit-commit所包含的内容有一个模糊的想法,但是我不知道当执行git-merge时这些内容会发生什么。我特别想了解 merge 失败时(例如由于某些冲突)索引的内容。

最佳答案

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

(实际上,一旦在索引中创建了一个条目,就会在必要时用一个标志位CE_REMOVED进行标记。这很麻烦,因为可以将整个文件目录标记为“已删除”,然后可以使用以下名称创建文件:上一个目录并标记为“已添加”。让我们假装我们有固定的插槽,那里是空的,而不是。:-))

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

merge 成功后,一切都是“照常进行”,因此唯一的特殊情况是发生冲突的 merge 。当插槽1、2和/或3不为空时, merge 是“冲突的”。跳过大多数机制,会发生什么。 merge 对所有插槽都使用“最新”名称,并且:

  • 插槽零保留为空(除非您解决冲突,否则您不能“​​提交”,除非您确实要删除文件,否则该插槽将不再为空)。
  • 插槽1(“基本”)填充了公共(public)祖先版本。如果文件是新的(在两个修订版中),则此插槽为空。
  • 插槽2(“我们的”)中填充了目标版本(HEAD,除非您手动调用一些基础的 merge 机制)版本。如果在HEAD/merge 目标中删除了文件,则此插槽为空。
  • 插槽3(“它们的”)已被 merge 版本填充。如果在 merge 版本中删除了该文件,则该插槽为空。

  • 解决冲突并“git add”解决后,#0插槽将被您“添加”的内容填满,从#1到#3中清除条目;或者,如果您“git rm”有冲突的文件,则将另一个阶段条目仍被删除,但是现在#0插槽仍然为空,这也解决了冲突。

    然后,更具体地说,假设您有一个共同的祖先,(其中有)这两个文件:
    gronk
    flibby
    

    您位于cleanup分支上,并且已将gronk重命名为breem,并对其和flibby进行了编辑。您决定使用git merge work,在那里他们修改了gronk,但未重命名,并删除了flibby。其他一些文件已干净 merge 。

    该索引将包含三个版本的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
    

    您可以使用bleem查看git show :1:bleem的原始(基本)版本。在基本版本中(在本例中,在本例中也称为gronk)将其称为work,但现在将其称为bleem,因为git相信您在gronk中将bleem重命名为cleanup。 (在这种情况下,Git会在merge-base和HEAD之间找到重命名,然后在必要时对work应用相同的重命名。)

    同样,您可以看到work版本和git show :3:bleemgit show work:gronk,以及HEAD版本的任何一个:git show HEAD:bleemgit show cleanup:bleemgit show :2:bleem(插槽2包含HEAD aka cleanup版本,并根据HEAD中的名称进行命名)。

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

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

    顺便说一句,我在上面的插槽2和3中标记了“我们的”和“他们的”。这也是git checkout对待它们的方式(git checkout --oursgit checkout --theirs使您可以将版本2或3写入插槽0;这种 checkout (与大多数 checkout 一样)也“擦除”其他插槽,从而解决了冲突)。但是,在进行重新设置的过程中,HEAD分支实际上是要重新建立基础的分支,而“其”版本是您正在被重新建立基础的分支。因此,在我看来,我们(他们)的术语并不是那么好:在重新设置基准期间将其倒退是很容易的。

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

    关于git - git索引的内容在 merge 期间如何演变( merge 失败后索引中的内容)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21309490/

    相关文章:

    linux - 如何在 .gitconfig 代理身份验证中转义特殊字符

    git - 当强制推送到远程 git 存储库时,现有标签会发生什么?

    linux - 如何在 GIT 中处理这个 merge 问题

    git - 您如何在不暂存文件的情况下添加新文件?

    git - 如何更改 vscode 中的 github 用户以推送到我的第二个帐户?

    eclipse - 如何让新分支显示在 Eclipse Git 远程跟踪中?

    git - 如何将 git 分支声明为 merge 而不采用其中的更改?

    Git 标记和 Gitflow : What happens when you merge old commits

    git - 显示 Git 索引中和工作副本中更改的文件

    git - 获取 "stage"的 Git 概念