Каковы основные процессы git merge в области подготовки? - PullRequest
9 голосов
/ 17 августа 2011

Git использует магию merge, а затем позволяет пользователю разрешать реальные конфликты, что и должно быть.Я ищу низкоуровневое описание того, как и почему базовое git-слияние и как оно использует область подготовки.

Я только что прочитал Притчу о Git , ипрокомментируйте здесь , что

Даже принимая во внимание тот факт, что это «притча», а не пересказ истории Git (которую вы можете найти в некоторых деталях на Git Wikiмежду прочим, остается одно замечание: IMVHO - плохая практика объяснять область размещения с точки зрения разделения изменений на более чем один коммит и / или коммит с деревом божества, то есть с некоторыми несвязанными изменениями.Основная сила промежуточной области (помимо явной версии других неявных областей, которые будут добавлены в SCM) связана с конфликтным слиянием, и, как мне кажется, это следует объяснить.

git merge man-страница идентифицирует элементы стадии 1/2/3 слияния, но, очевидно, не вдавается в детали почему и почему.

Могут ли люди давать советы по любым статьям о том, как и почему git удается добиться результатов, которых другие не достигают (помимо Linus V Bram, подробно описанного в блоге Винсента ), то есть о предполагаемых Trivial part?

Большинство веб-статей предполагают, что слияния «просто случаются», и я не нашел ничего, что объясняло бы проблемы (например, необходимость небольших коммитов, ценность общего коммитаи т. д.).

Ответы [ 2 ]

2 голосов
/ 18 августа 2011

В большинстве VCS используется базовая концепция трехстороннего слияния. Это сравнивает две ветви с общим предком каждой, поэтому, если строка кода отличается между двумя ветвями, вы знаете, какая ветвь изменила ее. Если они оба изменили его, у вас возникнет конфликт слияния, который должен разрешить человек.

Есть несколько случаев, когда трудно определить подходящего общего предка. Многие исследования были посвящены различным алгоритмам для этого, многие из которых включали отслеживание дополнительных метаданных с коммитами.

Важным нововведением Линуса было отслеживание деревьев , а не файлов . Это своего рода тонкое различие. Для иллюстрации на примере из блога Винсента рассмотрим файл foo в ветке A. Вы ветвитесь, чтобы сделать ветку B. В ветке A foo переименовывается в bar. В ветке B он удаляется. Затем вы пытаетесь объединиться.

Если вы отслеживаете файлы, это выглядит так:

Перед переходом создается версия 1 файла foo.

После следующего коммита ветвь A указывает на версию 2 foo, которая является удаленным файлом, и версию 1 нового файла bar.

После следующей фиксации ветвь B указывает на версию 2.1 foo, которая является удаленным файлом.

При слиянии версии 2 и 2.1 из foo сравниваются и обнаруживаются как идентичные. Там нет конфликта слияния там. Ветвь B даже не имеет файла с именем bar, поэтому в этом нет никакого конфликта. В результате вы получаете алгоритм слияния, который молча принимает переименование ветви A, хотя между удалением foo и его переименованием существовал реальный конфликт.

Если вы отслеживаете деревья, это выглядит так:

Перед ветвлением создается блоб с хешем dcb8bd7a97ab39f4c156a1a96d4b10720a39fb81. Дерево создается с записью, содержащей метку foo, указывающую на хеш.

После следующего коммита ветвь A указывает на дерево с записью, содержащей метку bar, указывающую на тот же хеш.

После следующего коммита ветвь B указывает на пустое дерево.

При слиянии деревья сравниваются: B показывает удаление, а A показывает переименование BLOB-объекта dcb8bd7a97ab39f4c156a1a96d4b10720a39fb81. Человека спрашивают, кого он предпочитает.

Вы можете несколько смягчить эффект с помощью VCS с отслеживанием файлов, добавив метаданные для переименований, но способ git использует свою обычную стандартную структуру данных. Кроме того, способ метаданных имеет трудности со сложными объединениями, когда существует много возможных вариантов для общего предка. Вы можете поместить миллиард возможных путей между общим предком и двумя ветвями, и git все равно увидит большой двоичный объект с таким же хешем и сможет обнаружить переименование и удаление. Также сложно сохранить метаданные, например, при принятии изменений в патче по электронной почте.

С переименованным файлом, который меняется одновременно, становится немного сложнее, но, отслеживая деревья, git получает всю необходимую информацию. Он видит BLOB-объект dcb8bd7a97ab39f4c156a1a96d4b10720a39fb81, ​​ушедший из обеих веток, но также видит новую запись дерева, указывающую на новый BLOB-объект, и может сравнить их. Если значительная часть файла совпадает, это считается переименованием. Очевидно, это сломается, если вы внесете массу изменений в переименованный файл, но в какой-то момент никакой алгоритм слияния не сможет вам помочь.

См. это электронное письмо от Линуса, чтобы узнать больше о его философии на эту тему.

2 голосов
/ 18 августа 2011

Это должно помочь, по крайней мере, с некоторыми из ваших вопросов, так как это git является наиболее распространенным слиянием:

git merge-file

git merge-файл разработан как минимальный клон слияния RCS;то есть он реализует все функциональные возможности слияния RCS, необходимые git (1).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...