Як зливається git після вишні?


190

Уявімо собі, що у нас є masterфілія.

Тоді ми створюємо newbranch

git checkout -b newbranch

і зробіть два нові зобов’язання newbranch: commit1 та commit2

Потім переходимо на майстер і робимо cherry-pick

git checkout master
git cherry-pick hash_of_commit1

Дивлячись на те, gitkми бачимо, що commit1 та його вишнева версія мають різні хеши, тому в технічному відношенні це два різні коміти.

Нарешті ми зливаємось newbranchу master:

git merge newbranch

і бачите, що ці два коміти з різними хешами були об'єднані без проблем, хоча вони означають, що одні й ті ж зміни слід застосовувати двічі, тому один з них повинен зазнати невдачі.

Чи дійсно git робить розумний аналіз вмісту фіксації під час об'єднання та вирішує, що зміни не слід застосовувати двічі або ці комірки позначаються внутрішньо як пов’язані між собою?

Відповіді:


131

Коротка відповідь

Не хвилюйтесь, Git впорається з цим.

Довга відповідь

На відміну, наприклад, SVN 1 , Git не зберігає комісії у форматі дельти, а базується на моментах 2,3 . У той час як SVN наївно намагався застосувати кожну об'єднану комісію як патч (і не вдалося з точної причини, яку ви описали), Git, як правило, може впоратися з цим сценарієм.

Під час об'єднання Git намагатиметься поєднати знімки обох HEAD у новий знімок. Якщо частина коду або файл однакові в обох знімках (тобто тому, що комісія вже була вибрана вишнею), Git не торкнеться її.

Джерела

1 Skip-Deltas в підривній основі
2 Основи Git
3 Модель об'єкта Git


40
Насправді, я б сказав, що ви повинні турбуватися про злиття, і "git впорається з цим" - це не дуже добре правило.
Крего

4
Насправді злиття CAN в деяких випадках призводить до дублювання вмісту. Гіт справді справляється з цим, але іноді - ні.
donquixote

Це жахливо неправильно. Зберігає файли файлів у всіх доступних формах. І якщо я пригадую правильно, SVN використовується для зберігання знімків.
he_the_great

2
@he_the_great, ні. Формат зберігання пропуску-дельта SVN (! = Знімки) добре задокументований у посібнику . І я насправді не розумію, що ви маєте на увазі під запевним . Я не носій мови, але я майже впевнений, що це не справжнє слово.
helmbert

2
@he_the_great Але навіть як пакети, будь-який заданий хеш для файлу призводить до повного файлу. Так, він стискає, використовуючи дельти, але це не дельта для змін у коміті, а натомість дельта між хешами для файлу. Що стосується об'єкта комісії, то він посилається на дерево, яке посилає хеш на повний файл. Те, що під капотом стискаються дані, не впливає на роботу git. Git зберігає повні файли, що стосується фіксації, SVN зберігає дельти для комісій, наскільки я розумію.
Пітер Олсон

44

Після такого злиття у вас можуть виникла вишні в історії два рази.

Рішення для запобігання цьому я цитую в статті, яка рекомендує для гілок з дублікатами (вишневий) зобов’язується використовувати ребайт перед об'єднанням:

git merge after git cherry-pick: уникати повторюваних комітетів

Уявіть, у нас є головна гілка та гілка b:

   o---X   <-- master
    \
     b1---b2---b3---b4   <-- b

Тепер нам терміново потрібні доручення b1 і b3 у master, але не решта доручень у b. Тож, що ми робимо, це перевірити головну гілку та вишневий комітет b1 та b3:

$ git checkout master
$ git cherry-pick "b1's SHA"
$ git cherry-pick "b3's SHA"

Результатом буде:

   o---X---b1'---b3'   <-- master
    \
     b1---b2---b3---b4   <-- b

Скажімо, ми робимо ще один вчинок на майстра і отримуємо:

   o---X---b1'---b3'---Y   <-- master
    \
     b1---b2---b3---b4   <-- b

Якби ми тепер об'єднали гілку b в головну:

$ git merge b

Ми отримаємо наступне:

   o---X---b1'---b3'---Y--- M  <-- master
     \                     /
      b1----b2----b3----b4   <-- b

Це означає, що зміни, внесені b1 і b3, з’являлися б двічі за всю історію. Щоб уникнути того, що ми можемо перезавантажити замість об’єднання:

$ git rebase master b

Що б дало:

   o---X---b1'---b3'---Y   <-- master
                        \
                         b2'---b4'   <-- b

Нарешті:

$ git checkout master
$ git merge b

дає нам:

   o---X---b1'---b3'---Y---b2'---b4'   <-- master, b

Виправлення EDIT, що передбачаються коментарем Девіда Лемона


1
чудовий натяк про ребазу! вона автоматично "пропустить" всі вишневі зобов'язання.
iTake

2
Чесно кажучи, це звучить занадто добре, щоб бути правдою, я маю це бачити очима. Крім того, база даних модифікує комісії, останньою часовою шкалою має бути---Y---b2'---b4'
Девід Лемон

Працює чудово. Дуже корисно, якщо ви не хочете, щоб вишня вибирала двічі за всю історію.
користувач2350644

1
Чи не слід зазначати, що хоча база даних є прекрасною, небезпека її використання полягає в тому, що будь-які вилки або гілки, створені зі старого b, не синхронізуються, і користувачам, можливо, доведеться вдатися до таких речей, як скидання git --hard та git push -f?
JHH

1
@JHH ось чому ми
відновили
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.