Git, кажется, использует неверного предка в качестве базы при слиянии - PullRequest
1 голос
/ 15 мая 2019

Я пытаюсь объединить нашу ветку релиза с нашей веткой функций, но git, похоже, не понимает, что такое общий предок.

Я использую SourceTree v3.1.2 и git v2.21.0.windows.1

до 7 февраля Ветвь разработки работала параллельно с веткой Release, с изменениями, внесенными в разработку и исправлениями в Release.

7 февраля Релиз был разветвлен до Feature.

9 мая Ветка разработки объединена с веткой Release.

15 мая (сегодня) Попытка слить ветку Release с веткой Feature.У меня 78 конфликтов.

  • Некоторые файлы были добавлены в ветку разработки до слияния. Не могу понять, почему это конфликты.
  • Некоторые файлы существовали, ноне изменено в ветке Feature - Не можете понять, почему это может быть конфликтом?Трехстороннее объединение (в Beyond Compare 4) предполагает, что в ветви Feature было удалено много кода, хотя фактически он был добавлен в ветку Development.
  • Некоторые файлы были изменены в обеих ветвях, но имеют одинаковыйпроблема в трехстороннем слиянии.

Я вижу, что такое беспорядок в трехстороннем слиянии при просмотре конфликтов, поэтому я не уверен, возникла ли та же проблема с неконфликтующими файлами,На первый взгляд они выглядят хорошо, но их много, поэтому я не уверен.

Я выполнил следующую команду git, которая с 24 апреля возвращала на первый взгляд случайную регистрацию в ветке разработки.

git merge-base (последняя фиксация ветки Feature) (последняя фиксация ветви Release)

Я бы подумал, что получу последний коммит до того, как разработка и выпуск разойдутся до 7 февраля.

Я пробовал:

  • Слияние релиза с функцией
  • Слияние функции с релизом
  • Перебазирование функции на релиз (я не думаю, что эторекомендовано, но я все равно решил попробовать) Мне показалось, что при этом я потерял кучу файлов.
  • Перебазирование релиза на функцию
  • Сброс на ветку 7 февраля, повторное ветвление, а затемслияние.
  • Слияние Ветвь разработки на момент ее слияния с Релизом.
  • Я пытался выяснить, могу ли я заставить общего предка выполнять слияние, ноЯ не уверен, что могу сделать этоИз того, что я прочитал.

Стоит отметить, что я сделал пробное слияние ветви разработки (не ветки Release на этот раз) с веткой Feature несколько недель назад, и все, казалось, шло довольноЧто ж.С тех пор я обновил SourceTree с версии 1.7 до 3.1.2, что также потребовало обновления git.

Я не очень хорош в этом git, поэтому любая помощь будет принята с благодарностью.

1 Ответ

2 голосов
/ 15 мая 2019

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

Нет. Git вычисляет базы слияния для вас. Они основаны на графике фиксации.

Стоит сесть и нарисовать график (или сделать git log --graph для вас). Попробуйте использовать git log --all --decorate --oneline --graph (запомните это как , чтобы получить помощь от A DOG ), и, возможно, добавьте --simplify-by-decoration, чтобы помочь отбросить большую часть визуального беспорядка.

Поиск баз слияния с помощью глазного яблока

С помощью простых графиков легко увидеть визуально, какой коммит является базой слияния двух других коммитов. Например, учитывая график, который может отображаться таким образом, с последующими коммитами вправо:

          o--o--L   <-- branch1 (HEAD)
         /
...--o--*
         \
          o--o--R   <-- branch2

... база слияния коммитов L (ваш текущий извлеченный коммит, HEAD, на кончике branch1) и коммит R (коммит на кончике branch2) это совершить *.

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

...--o--o--o--o--o--o--*--o--L   <-- branch1
         \     \        \
          o--o--A--o--o--B--o--R  <-- branch2

Еще раз, база слияния L и R является коммитом *. Существует два существующих слияния, A и B. Слияние A не имеет значения, потому что слияние B создает первый коммит, достижимый из обеих подсказок ветви: мы начинаем с L и возвращаемся к двум коммитам до *, а начинаем с R, возвращаемся к двум фиксирует B, идет к его родителю * и достигает общего коммита.

перебазирования

Я пытался [перебазировать]

Обратите внимание, что при использовании git rebase копий коммиты, обычно , отбрасывая слияний. Предположим, у вас есть график выше, сливающийся в branch2, и вы решаете git rebase branch2 branch1. Это будет перечислять все коммиты, которые доступны с branch2, но не с branch1, за исключением слияний. Хотя мы можем достичь коммита * из branch2 и branch1, мы не можем достичь любого коммитов нижнего ряда из branch1. Таким образом, копируемые коммиты - это все те, которые находятся в нижнем ряду. Давайте дадим им всем однобуквенные имена, чтобы мы могли говорить о них:

...--o--o--o--o--o--o--*--o--L   <-- branch1
         \     \        \
          C--D--A--E--F--B--G--R  <-- branch2

(я сохранил однобуквенные имена, которые у нас уже были для A, B и R здесь).

Операция rebase - git checkout branch2; git rebase branch1 - выбирает все фиксации без слияния вдоль нижнего ряда и копирует их. Копии идут после коммита L, на кончике branch1, поэтому получается:

                               C'-D'-E'-F'-G'-R'   <-- branch2
                              /
...--o--o--o--o--o--o--o--o--L   <-- branch1
         \     \        \
          C--D--A--E--F--B--G--R  <-- ???

Хотя имя branch2 было перемещено в этот момент - теперь оно указывает на R', копия R - оригинального коммитов все еще существует. Они просто не достижимы от названия branch2 больше.

Если есть другая ветвь - скажем, branch3 - которая происходит от некоторых или всех этих коммитов, мы могли бы нарисовать это в:

                               C'-D'-E'-F'-G'-R'   <-- branch2
                              /
...--o--o--o--o--o--o--o--o--L   <-- branch1
         \     \        \
          C--D--A--E--F--B--G--R  <-- ???
                       \
                        H--I   <-- branch3

Поскольку R, G и B не могут быть легко найдены, мы можем прекратить рисовать их полностью:

                               C'-D'-E'-F'-G'-R'   <-- branch2
                              /
...--o--o--o--o--o--o--o--o--L   <-- branch1
         \     \
          C--D--A--E--F
                       \
                        H--I   <-- branch3

Коммиты C-D-A-E-F все еще живы и здоровы, однако достижимы, начиная с branch3 (коммит I) и работая в обратном направлении.

Если теперь вы решите объединить branch3 с branch1 или branch2, база для слияния будет найдена, начиная с обоих концов веток и работая в обратном порядке, как обычно. В этом случае база слияния - это коммит, которого мы достигаем, переходя вверх и влево от коммита A (слияние все еще достижимо с кончика branch3), поскольку этот коммит доступен с обеих кончиков веток и является «ближе всего к концу».

BecausИз этой вещи, состоящей из нескольких имен, доходят до старых коммитов, обычно нет смысла перебазировать ветви, поддерживающие другие ветви.Также сложно перебазировать ветки, содержащие слияния.Современный (2.18+) Git имеет опцию --rebase-merges, которая позволяет Git заново создавать слияния;У старого Git есть --preserve-merges, который пытается сделать то же самое, но более хрупок, чем современный метод.Во всех случаях, однако, важно знать, что когда rebase должен скопировать коммит слияния, он действительно просто снова запускает git merge, чтобы вычислить new базу слияния и повторить слияние с нуля.

Дополнительные примечания

Обратите внимание, что отметки даты и времени на коммитах здесь совершенно неактуальны. Только граф имеет значение .Коммиты с их хэш-идентификаторами узлов и родительскими хэш-идентификаторами ребер образуют граф фиксации.Содержимое внутри каждого коммита - это история;* * * * * * * * * * * * * * * *

* * * * * * * * *1132* * * * * * *1132* Чтобы Git сообщал вам, что он использует для базы слияния, делайте то же, что и вы, но добавьте --all в случае нескольких баз слияния:

git merge-base --all branch1 branch2

Git выполнит поиск базы слияния: начните с последнего коммита, на который указывают имена, пройдитесь назад по всем путям и найдителучший коммит (ы) .Затем он распечатает хеш-код (ы) всех баз слияния.Затем слияние будет продолжено путем сравнения (как и в случае git diff) (единственной) базы слияния с двумя коммитами с ветвлением.

Если равно более чем одной базе слияния,стратегия по умолчанию -s recursive сначала будет запускаться git merge на самих базах слияния, 1 делать рекурсивное слияние до тех пор, пока Git не сможет создать один коммит, который будет использоваться в качестве "виртуальной базы слияния" процесса слияния,Вы можете сделать так, чтобы Git просто выбрал один из них (по-видимому) случайным образом, используя вместо этого -s resolve.Обычно это не является каким-либо улучшением, но это стоит знать в сложных случаях.


1 Если вы не действительно невезучие / сошли с умаВ вашем предыдущем построении графиков будет максимум две базы слияния.Если их больше, Git объединяет два, фиксирует результат, объединяет его со следующим, фиксирует результат и т. Д.

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