Разрушают ли запросы на извлечение данных алгоритм слияния git?

16

В настоящее время я работаю в компании, которая использует VSTS для управления git-кодом. «Рекомендованный» для Microsoft способ объединения веток - это «объединение в сквош», означающее, что все коммиты для этой ветки будут объединены в один новый коммит, включающий все изменения.

Проблема в том, что если я сделаю некоторые изменения в одной ветви для одного элемента журнала невыполненных работ, то сразу же захочу начать вносить изменения в другой ветви для другого элемента журнала невыполненных работ, и эти изменения зависят от набора изменений первой ветви?

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

Итак, мой вопрос: есть ли способ обойти это (кроме того, что никогда не основывать одну ветку функций на другой, что ограничивает мой рабочий процесс), или объединение в сквош просто нарушает алгоритм объединения git?

Еж
источник

Ответы:

15

С Git совершает

  • неизменны,
  • и сформировать ориентированный ациклический граф.

Сквош не объединяет коммиты. Вместо этого он записывает новый коммит с изменениями из нескольких других коммитов. Перебазирование похоже, но не сочетает коммиты. Запись нового коммита с теми же изменениями, что и существующий коммит, называется перезаписью истории . Но поскольку существующие коммиты неизменны, это следует понимать как «написание альтернативной истории».

Объединение пытается объединить изменения двух историй (ветвей) коммита, начиная с коммитов общего предка.

Итак, давайте посмотрим на вашу историю:

                                 F  feature2
                                /
               1---2---3---4---5    feature1 (old)
              /
-o---o---o---A---o---o---S          master

A - общий предок, 1–5 - исходная ветвь объектов, F - новая ветвь объектов и S - сдавленный коммит, содержащий те же изменения, что и 1–5. Как вы можете видеть, общий предок F и S - это А. Что касается git, то между S и 1–5 нет никакой связи. Таким образом, объединение мастера с S с одной стороны и feature2 с 1–5 с другой будет конфликтовать. Разрешить эти конфликты не сложно, но это ненужная, утомительная работа.

Из-за этих ограничений существует два подхода к слиянию / сжатию:

  • Либо вы используете переписывание истории, и в этом случае вы получите несколько коммитов, которые представляют одинаковые изменения. Затем вы перебазируете вторую ветку объектов на сдавленный коммит:

                                     F  feature2 (old)
                                    /
                   1---2---3---4---5    feature1 (old)
                  /
    -o---o---o---A---o---o---S          master
                              \
                               F'       feature2
    
  • Или вы не используете переписывание истории, в этом случае вы можете получить дополнительные коммиты слияния:

                                     F  feature2
                                    /
                   1---2---3---4---5    feature1 (old)
                  /                 \
    -o---o---o---A---o---o-----------M  master
    

    Когда feature2 и master объединены, общий предок будет коммит 5.

В обоих случаях у вас будут усилия по объединению. Это усилие не очень зависит от того, какую из двух вышеуказанных стратегий вы выберете. Но убедитесь, что

  • ветви недолговечны, чтобы ограничить, насколько далеко они могут дрейфовать от основной ветви, и что
  • вы регулярно сливаете master в свою ветку Feature или перебазируете ветку Feature на master, чтобы синхронизировать ветви.

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

Амон
источник
2
Ваш ответ, похоже, не решает, что произойдет, если вы сначала сквош-слились с feature1мастером, а затем захотите слиться feature2позже. В таком случае, не приведет ли первый подход к конфликтам, поскольку git попытается повторно применить feature1коммиты поверх сжатого коммита, тогда как второй позволит git определить, что эти коммиты не нужно объединять?
Jez
@Jez Это именно то, что происходит, когда вы давите пиар. Недавно мне пришлось вручную переписывать PR в проекте OSS (путем git cloneсоздания репозитория и копирования моих измененных файлов!), Потому что я разветвлялся из ветви, а затем сопровождающий подавлял первую ветку. На моей работе они также делают сквош слияния. Это означает, что я не могу работать над функцией, bкоторая зависит от функции, aпока функция не aбудет объединена.
Сбросить счет
1
И разве это не раздражающая поломка чего-то, что в противном случае работало бы, как предназначен git? Видите ли, я вижу, что различные организации, такие как Microsoft и Github, на самом деле рекомендуют эти сквош-слияния, и они кажутся мне глупыми.
Еж
1
@Jez В исходном сценарии да, вы получите конфликты при слиянии feature2 с master, потому что слияние коммитов 1–5 будет конфликтовать с теми же изменениями в S. Решение состоит в том, чтобы перебазировать feature2 (решение 1) или не использовать сжатие / ребазинг в все (решение 2).
Амон
Подходит ли слияние сквоша для вас, зависит от того, что вы хотите записать в историю управления версиями. Если ветви ветвей имеют много WIP-коммитов, то при сжатии создается один большой коммит с полной функцией в основной ветке. Если вы предпочитаете сохранить все промежуточные коммиты ветви функции, используйте перебазирование или слияние.
Амон
11

Сквошное слияние нарушает алгоритм слияния для любых веток, которые содержат любые коммиты, которые были удалены сквошем. Иными словами, ребазы являются вирусными. Если вы перебазируете одну ветку, вам нужно перебазировать любые другие ветви, которые зависели от этой ветви. Если вы используете rerere , любые конфликты слияния, которые вы решили вручную в своем локальном репо, не нужно будет снова решать вручную, но это не поможет с конфликтами, разрешенными другими людьми.

Вот почему наше неписанное правило гласит, что все в порядке, если никто больше не зависел от вашей ветки функций, что может быть в 90% случаев. В противном случае прямое слияние помогает всем избежать проблем.

Карл Билефельдт
источник
Один из способов получить как сдавленный коммит в основной истории, так и ветвь функций, чтобы создать отдельную ветвь только для сквоша. Предположим, у вас есть feature-xyzфилиал. Вы можете создать feature-xyz-squashedветку, начинающуюся с того же коммита, что и feature-xyzветка, git cherry-pickкоммиты из feature-xyzв feature-xyz-squashed, раздавить их там и объединить feature-xyz-squashedс master. Вы не должны сливаться feature-xyzтогда. Иногда вышеупомянутое имеет смысл (например, вы не хотите включать коммиты с паролем), но это обходной путь, вряд ли лучший способ.
9000