我对git
索引包含的内容有一个模糊的概念git-add
和git-commit
s,但我不清楚这些内容会发生什么一个做git-merge
。当合并失败时(例如由于某些冲突),我特别感兴趣的是学习索引的含义。
答案 0 :(得分:5)
对于任何给定的路径,索引中最多有四个“版本号”,编号为0(零)到3.我将它们称为“插槽”,就好像它们实际上是每个条目一样,然后很容易索引(这使它们更容易思考),虽然实际上只有在需要时动态引入了额外的版本。这些“虚拟插槽”可以是“空的”,这意味着该文件不存在。
(实际上,一旦在索引中创建了一个条目,它就会标记一个标志位CE_REMOVED
,如果需要的话。这会变得多毛,因为整个目录中的文件可以被标记为“已删除”,然后是可以使用上一个目录的名称创建文件并标记为“已添加”。让我们假装我们有固定的插槽,而不是空的,而是。:-))
Slot#0是“正常”,无冲突,全井进入。它包含一堆缓存数据,路径名和存储在存储库中的文件的blob-ID(SHA-1)。
当合并成功时,它就是“一切照旧”,所以唯一的特例是冲突合并。当插槽1,2和/或3非空时,合并是“冲突的”。跳过大多数机制,会发生什么。合并使用所有插槽的“最新”名称,并且:
HEAD
,除非您手动调用某些底层合并机制)版本。如果在HEAD
/ target-of-merge中删除了该文件,则此插槽为空。一旦解决了冲突和“git add”,#0插槽就会被你“添加”的内容填入,消除#1到#3中的条目,或者,如果你“git rm”冲突的文件,其他阶段条目仍然被删除,但现在#0插槽仍为空,这也解决了冲突。
更具体地说,假设你有一个共同的祖先(其中包括)这两个文件:
gronk
flibby
您在分支cleanup
上,并且已将gronk
重命名为breem
,并对其和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
您可以使用bleem
查看git show :1:bleem
的原始(基本)版本。这在基础版本中称为gronk
(在本例中也在work
中),但现在称为bleem
,因为git认为您将gronk
重命名为{{在bleem
中的1}}。 (Git在合并基础和cleanup
之间找到重命名,然后在必要时将相同的重命名应用于HEAD
,如本例所示。)
同样,您可以看到work
版本work
或git show :3:bleem
以及git show work:gronk
版本中的任何一个版本:HEAD
,{{1} },或git show HEAD:bleem
(广告位2包含git show cleanup:bleem
又名git show :2:bleem
版本,并根据HEAD
中的名称命名。
对于cleanup
,因为它已在HEAD
中删除,所以没有“他们的”(第3个插槽)版本。
要解决冲突,您只需告诉flibby
或work
更新slot-zero条目并删除1到3条目。当然,对于git add
,进入插槽0的是现在工作目录中的内容,因此您通常必须先编辑文件。
顺便说一下,我在上面标记了第2和第3个“我们的”和“他们的”。这也是git rm
对待它们的方式(git add
和git checkout
允许您将版本2或3写入插槽0;这样的结帐,像大多数结帐一样,“擦除”其他插槽从而解决冲突)。但是,在一个rebase中,git checkout --ours
分支实际上是正在重新定位的分支,而“他们的”版本是您的分支正在重新分配。因此,在我看来,我们/他们的术语并不是那么好:在反叛期间很容易让它倒退。
我还应该注意,git checkout --theirs
将“重新创建”合并冲突,如果你正处于冲突合并的中间,通过删除插槽0并“恢复”插槽1-3中的版本根据需要(并将冲突的合并文件写入工作目录,同时遵守HEAD
设置中的任何更改。)