Как изменяется содержимое индекса git во время слияния (и что находится в индексе после неудачного слияния)?

У меня есть смутное представление о том, что git Индекс содержит как один git-addс и git-commitс, но я понятия не имею, что происходит с этим содержанием, когда кто-то делает git-merge, Мне особенно интересно узнать, что индекс удерживает при слиянии (например, из-за некоторого конфликта).

1 ответ

Решение

Для любого заданного пути в индексе имеется до четырех "номеров версий", пронумерованных от 0 (ноль) до 3. Я буду называть их "слотами", как если бы они были на самом деле для каждой записи, а затем легко индексировать (это облегчает их обдумывание), хотя на самом деле дополнительные версии вводятся динамически только при необходимости. Эти "виртуальные слоты" могут быть "пустыми", то есть файл не существует.

(На самом деле, как только запись создается в индексе, она помечается битом флага, CE_REMOVED, если нужно. Это становится проблематичным, потому что весь каталог, полный файлов, может быть помечен как "удаленный", а затем файл может быть создан с именем предыдущего каталога и помечен как "добавленный". Давайте просто притворимся, что у нас есть фиксированные слоты вместо пустых.:-))

Слот № 0 - это "нормальная", неконфликтная, "все в порядке" запись. Он содержит набор данных кэша, имя пути и идентификатор BLOB-объекта (SHA-1) для файла, хранящегося в хранилище.

Когда слияние завершается успешно, все это "как обычно", поэтому единственным частным случаем является конфликтное слияние. Объединение "конфликтует", когда слоты 1, 2 и / или 3 не пусты. Пропустив большую часть механики, вот что происходит. Объединение использует "новейшее" имя для всех слотов и:

  • Нулевой слот остается пустым (вы не можете "зафиксировать", пока не решите конфликт, и к этому времени этот слот больше не будет пустым, если вы действительно не хотите, чтобы файл был удален).
  • Слот 1 ("база") заполнен версией общего предка. Если файл новый (в обеих ревизиях), этот слот пуст.
  • Слот 2 ("наш") заполнен целью (HEAD, если вы вручную не вызываете какую-либо версию базового механизма слияния). Если файл был удален в HEAD / target-of-merge, этот слот пуст вместо этого.
  • Слот 3 ("их") заполнен версией слияния. Если файл был удален в ревизии после слияния, этот слот пуст.

Как только вы разрешите конфликт и "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 потому что мерзавец считает, что вы переименовали gronk в bleem в cleanup, (Git находит переименования между базой слияния и 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 ака 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; такая проверка, как и большинство проверок, "стирает" и другие слоты, решая, таким образом, конфликт). Тем не менее, в перебазе, HEAD В действительности, ветвь - это ветвь, на которую делается перебазирование, а "их" версия - это ваша ветвь, которая перебазируется. Так что, на мой взгляд, наша / их терминология на самом деле не так уж и хороша: слишком легко вернуть ее назад во время ребазинга.

Я должен также отметить, что git checkout -m "заново создаст" конфликт слияния, если вы находитесь в середине конфликтующего слияния, удалив слот 0 и "воскресив" версии в слотах 1-3 по мере необходимости (и записав конфликтующий файл слияния в рабочий каталог подчиняясь любым изменениям в вашем merge.conflictstyle установка также).

Другие вопросы по тегам