Как / почему git rebase избегает коммитов слияния? - PullRequest
0 голосов
/ 11 сентября 2018

Команда git rebase использует слияние под капотом, поэтому мне интересно, как / почему git rebase избегает коммитов слияния, тогда как git merge обычно создает новый коммит, если между ветвями есть разница.

Ответы [ 5 ]

0 голосов
/ 12 сентября 2018

Многие люди ответили , как rebase избегает фиксации слияния, но я думаю , почему немного интересно. Есть множество вещей, которые вы можете сделать с этим, так что это только мое мнение о самом важном. (Другие с другими рабочими процессами, естественно, не согласятся:)

В централизованной системе хранилищ, такой как svn или perforce, фиксация выполняется прямо на сервере. Так что, если Боб и Джим работают над своими локальными копиями основной ветви ... они оба работают над основной веткой. Конец истории. После того, как Боб и Джим выполняют свои коммиты, мы видим их по порядку ... в одной ветке.

Одним из очень немногих потенциальных недостатков git является то, что удаленный репозиторий является эффективно неявной ветвью. Он ведет себя как единое целое, он отображается в журнале git как единое целое и т. Д. Так что, если Боб и Джим вносят изменения в свою локальную копию, последний, кто должен нажать, должен извлечь ... и выполнить слияние с удаленного компьютера. И это выглядит так, как будто Боб и Джим оба работали над своими собственными ветвями. Иногда это поведение идеально. Иногда это нежелательно.

git pull --rebase / git fetch;git rebase - вот как вы можете сказать git "Я знаю Вы считаете это ветвью, но я не знаю. Я просто хочу сделать свой коммит поверх последний похож на нормального человека и имеет то, что я считаю точной историей ветви. " Лично меня не волнует clean .

0 голосов
/ 11 сентября 2018

Вы правы, что ребаз - это в основном слияние под капотом. Фактически, вы можете создать свою собственную команду rebase, используя команду merge, и все, что вам нужно сделать, это впоследствии изменить некоторые метаданные коммита.

Допустим, это ваша история:

A - B - C (master)
 \
  D - E (dev)

Если вы хотите перебазировать dev на master, вы можете сделать это, сначала объединив D, а затем E,

A - B - C - D'- E'
 \         /   /
  + - - - D - E

И затем вы изменяете коммиты, чтобы удалить ссылки из D и E,

A - B - C - D"- E" (master)
 \
  D - E (dev)

Таким образом, вы можете видеть, что git rebase - это не более чем простая манипуляция с историей (только изменение метаданных) поверх слияния. Причина, по которой вы не видите коммиты слияния - это просто вопрос метаданных: каждый коммит имеет указатели на свои родительские коммиты, и если вы удаляете все, кроме одного из указателей, вы стираете связь коммита с этими родителями, превращая коммит слияния в фиксация без слияния.

Более сложные перебазировки могут быть выполнены таким же образом. Обратите внимание, что это не то, как на самом деле работает rebase, это просто способ, которым вы можете вручную перебазировать коммиты без использования команд rebase или cherry-pick. Важной частью является то, что коммит слияния - это не что иное, как коммит с двумя или более родителями, и вы можете изменить родителей любого коммита, просто изменив метаданные.

0 голосов
/ 11 сентября 2018

rebase не является слиянием, как слияние ветки.Вместо этого rebase - это серия git cherry-pick с.Черри выбирает коммит и копирует его, как если бы он был написан поверх какого-то другого коммита.Это как если бы вы взяли diff из коммита и применили его где-то еще.

Рассмотрим такой репозиторий.A, B, C и т. Д. ... представляют идентификаторы фиксации.

A - B - C - D [master]
         \
          E - F - G [feature]

Если master требуется E, возможно, это критическое исправление ошибки, но не остальная часть feature можетgit cherry-pick E.Git выполнит слияние D и E с C в качестве источника, что приведет к E1.Вот почему вы можете получить конфликты слияния во время перебазирования.Но в отличие от обычного слияния, у E1 будет только один родитель.

A - B - C - D - E1 [master]
         \
          E - F - G [feature]

Перебазировка - это как если бы это делалось для всех ваших коммитов.И вместо того, чтобы быть на вершине master, он движется feature.Вот как выглядит git rebase master, шаг за шагом.

Опять же, рассмотрим ваш репозиторий.

A - B - C - D [master]
         \
          E - F - G [feature]

Сначала, как и прежде, он делает cherry-pick на E и помещает его ввершина master.Но вместо перемещения master создается новая ветвь без метки.

              E1
             /
A - B - C - D [master]
         \
          E - F - G [feature]

Затем он выбирает F и помещает его поверх E1.

              E1 - F1
             /
A - B - C - D [master]
         \
          E - F - G [feature]

ЗатемВишня выбирает G и помещает его в F1 как G1.

              E1 - F1 - G1
             /
A - B - C - D [master]
         \
          E - F - G [feature]

Когда сбор вишни завершен, он перемещает метку feature на G1.

              E1 - F1 - G1 [feature]
             /
A - B - C - D [master]
         \
          E - F - G

И да,старые коммиты все еще там.Если ничто не ссылается на них, например, на тег или другую ветку, они будут собираться через несколько недель.Тем временем вы можете получить к ним доступ с помощью git reflog.См. Обслуживание и восстановление данных глава Pro Git для получения дополнительной информации.

0 голосов
/ 11 сентября 2018

Мне нравится разбивать концепцию слияния в Git на две части:

  • Глагол объединить означает объединить изменения .Многие команды используют это.

  • существительное слияние , полученное из формы прилагательного слияние совершают , где прилагательное «слияние» изменяет существительное«совершить», означает принятие с двумя или более родителями .Только git merge создает такие коммиты (ну, git merge или что-то, что запускает git merge, включая git pull).

Это означает, что git rebase использует глаголform, операция для слияния , которая обычно выполняется с помощью повторяющегося git cherry-pick. 1 Git cherry выбирает коммит, выполняя слияние с родительским коммитом 2 в качестве базы слияния, сам коммит как «другой» коммит, а текущий HEAD коммит играет свою обычную роль. Комментарий zzxyz , таким образом, является правильным: каждая операция выбора вишни может привести к конфликтам слияния, которые должен разрешить человек.

Результатом каждой операции выбора вишни является копия каждого коммита,как Шверн отметил в своем ответе .После копирования интересующих коммитов Git перемещает имя ветки так, чтобы оно указывало на последний скопированный коммит - конец новой ветки в новой позиции в графе коммитов.Первоначальные коммиты сохраняются как минимум на некоторое время из-за ORIG_HEAD - который rebase устанавливает перед перемещением имени ветви - и из-за различных reflogs (для самого HEAD и / или для имени ветви, которое git rebase простоизменено).

Последнее, на что стоит обратить внимание, это фраза коммитов в предыдущем абзаце.Когда rebase размещает коммиты, которые он будет копировать, он по умолчанию намеренно отбрасывает слияния .Есть аргументы, которые нужно сделать с обеих сторон (то есть «сохранить слияния» против «сбросить слияния»), но это то, что Git делает сегодня.Таким образом, после перебазирования копии никогда не содержат коммитов слияния, даже если процесс копий коммитов включает в себя для слияния глагол.


1 Интерактивный git rebase -i, или git rebase, запущенный с -m или -s <em>strategy</em>, действительно использует git cherry-pick.Неинтерактивный ребаз без -m или -s использует git format-patch и git am -3, что технически уступает в нескольких отношениях, но обратно совместимо с древним Git 1.5.

2 Это то, что затрудняет сбор вишни при слиянии: слияние - коммит слияния, который по определению является коммитом с двумя или более родителями - не имеет родителя, у него дваили больше родителей.Команда git cherry-pick позволит вам в любом случае выбрать его, но для этого необходимо указать , какого родительского элемента команда должна рассматривать как базу слияния во время процесса слияния как глагол.

0 голосов
/ 11 сентября 2018

Вы можете думать об этом следующим образом: git rebase берет новые коммиты из вашей ветки и откладывает их, затем перематывает вашу ветку, чтобы соответствовать обновленной оригинальной, и, наконец, добавляет ваши коммиты поверх результата;git merge просто создает новый коммит (слияние) с разницей между ветвями.Обратите внимание, что в случае перебазирования всех коммитов, которых не было в исходной ветке, они изменят свои хэши, поэтому вам придется принудительно выдвигать новую ветку (что не всегда легко, если на одной и той же стороне работают несколько человек)ветка).Перебазировка, однако, позволяет избежать коммитов слияния и сохранить более чистую историю.

...