我对git
索引包含的内容与git-add
和git-commit
所包含的内容有一个模糊的想法,但是我不知道当执行git-merge
时这些内容会发生什么。我特别想了解 merge 失败时(例如由于某些冲突)索引的内容。
最佳答案
对于任何给定的路径,索引中最多有四个“版本号”,编号为0(零)到3。我将它们称为“插槽”,就好像它们实际存在于每个条目中一样,然后轻松地进行索引(此索引使它们更容易考虑),尽管实际上只有在需要时才动态引入额外的版本。这些“虚拟插槽”可以为“空”,表示该文件不存在。
(实际上,一旦在索引中创建了一个条目,就会在必要时用一个标志位CE_REMOVED
进行标记。这很麻烦,因为可以将整个文件目录标记为“已删除”,然后可以使用以下名称创建文件:上一个目录并标记为“已添加”。让我们假装我们有固定的插槽,那里是空的,而不是。:-))
插槽#0是“正常”,无冲突,完好无损的条目。它包含一堆缓存数据,路径名和存储在存储库中的文件的blob-ID(SHA-1)。
merge 成功后,一切都是“照常进行”,因此唯一的特殊情况是发生冲突的 merge 。当插槽1、2和/或3不为空时, merge 是“冲突的”。跳过大多数机制,会发生什么。 merge 对所有插槽都使用“最新”名称,并且:
HEAD
,除非您手动调用一些基础的 merge 机制)版本。如果在HEAD
/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:bleem
或git show work:gronk
,以及HEAD
版本的任何一个:git show HEAD:bleem
,git show cleanup:bleem
或git show :2:bleem
(插槽2包含HEAD
aka cleanup
版本,并根据HEAD
中的名称进行命名)。但是,对于
flibby
,由于已在work
中删除,因此没有“其”(插槽3)版本。要解决冲突,您只需要告诉
git add
或git rm
即可更新零槽条目并删除1至3条目。当然,使用git add
,进入插槽0的内容现在是工作目录中的内容,因此通常必须首先编辑文件。顺便说一句,我在上面的插槽2和3中标记了“我们的”和“他们的”。这也是
git checkout
对待它们的方式(git checkout --ours
和git 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/