В чем разница между «git merge» и «git rebase»?

499

Какая разница между git mergeа git rebase?

Даниэль Пеньальба
источник
14
Поскольку мой ответ был удален, перейдите по этой ссылке, чтобы получить правильный ответ на этот вопрос: git-scm.com/book/en/Git-Branching-Rebasing#The-Basic-Rebase
HiB
6
Кстати я добавлю этот сайт. Все, что вам нужно знать о git, учитесь, играя: pcottle.github.io/learnGitBranching
Rollyng
Сначала прочтите это: git-scm.com/book/en/v2/… Затем: git-scm.com/book/en/v2/Git-Branching-Rebasing Вы действительно поймете.
Liber

Ответы:

867

Предположим , что первоначально было 3 фиксаций, A, B, C:

азбука

Затем разработчик Dan создал commit D, а разработчик Ed создал commit E:

ABCDE

Очевидно, этот конфликт нужно как-то решить. Для этого есть 2 способа:

Мердж :

ABCDEM

Оба коммита Dи Eвсе еще здесь, но мы создаем коммит слияния, Mкоторый наследует изменения от обоих Dи E. Тем не менее, это создает форму ромба , что многие люди находят очень запутанным.

ПЕРЕПИСКА :

ABCDER

Мы создаем коммит R, фактическое содержимое файла которого совпадает с Mвышеизложенным коммитом . Но мы избавляемся от коммита E, как будто его никогда не существовало (обозначено точками - линия исчезновения). Из-за этого уничтожения он Eдолжен быть локальным для разработчика Ed и никогда не должен передаваться в какой-либо другой репозиторий. Преимущество перебазирования в том, что форма ромба избегается, а история остается красивой прямой - большинству разработчиков это нравится!

MVP
источник
53
Хорошие иллюстрации. Тем не менее, я не полностью согласен с положительным тоном, что обрабатывается ребаз. При слиянии и перебазировании могут возникать конфликты, требующие ручного разрешения. И, как всегда, когда участвуют программисты, существует немаловажная вероятность ошибок, таких как ошибки. Если происходит ошибка слияния, вся команда или сообщество могут увидеть слияние и проверить, не была ли там введена ошибка. История перебазирования сохраняется в репозитории 1 разработчика, и даже там он имеет ограниченный срок службы в reflog. Это может выглядеть лучше, но никто другой не может так легко увидеть, что пошло не так.
Уве Гедер,
> «Тем не менее, это создает форму ромба, что многие люди находят очень запутанным». Хм ... можешь уточнить?
Грег Малетик
@GregMaletic: форма ромба - нелинейная история. Я не знаю о вас, но я не люблю нелинейные вещи в целом. Тем не менее, вы можете использовать слияние с бриллиантами, если вы действительно предпочитаете это - никто не заставляет вас.
MVP
1
Хотя этот ответ чрезвычайно полезен, было бы лучше, если бы вы добавили реальные команды git с простыми файлами foo.txt, чтобы воспроизводить их локально. Как сказал последний пользователь, не очевидно, кто делает ребаз.
Vortex
1
@pferrel: Я не думаю, что вы правильно поняли. git mergeне перемежает коммиты (но это может выглядеть так, глядя на них git log). Вместо этого git mergeсохраняет обе истории развития Дэна и Эда в неизменном виде, как это было видно с каждой точки зрения за раз. git rebaseПохоже, что Дэн работал над этим первым, а Эд последовал за ним. В обоих случаях (слияние и перебазирование) фактическое результирующее дерево файлов абсолютно идентично.
MVP
158

Мне очень нравится этот отрывок из 10 вещей, которые я ненавижу в git (он дает краткое объяснение rebase во втором примере):

3. Дрянная документация

Страницы руководства - это одно всемогущее «f *** you» 1 . Они описывают команды с точки зрения ученого, а не пользователя. Дело в точке:

git-push – Update remote refs along with associated objects

Вот описание для людей:

git-push – Upload changes from your local repository into a remote repository

Обновление, другой пример: (спасибо CGD)

git-rebase – Forward-port local commits to the updated upstream head

Перевод:

git-rebase – Sequentially regenerate a series of commits so they can be 
             applied directly to the head node

И тогда у нас есть

git-merge - Join two or more development histories together

это хорошее описание.


1. без цензуры в оригинале

MVW
источник
Проблема не в языке или в том, является ли пользователь компьютерным специалистом или нет. Хотя его переписывание другим способом помогает прояснить цели (то есть, что происходит), оно не дает объяснения средств (как это происходит). Git требует понимания средств, чтобы понять цели. Именно понимание средств делает Git таким трудным. Как инструмент, который используется для упрощения или уменьшения усилий, необходимых для выполнения задачи, Git ужасно терпит неудачу. К сожалению, слишком много разработчиков не осознают этого.
ATL_DEV
128

Лично я не нахожу стандартную технику построения диаграмм очень полезной - стрелки всегда, кажется, указывают неправильный путь для меня. (Они обычно указывают на «родителя» каждого коммита, который в конечном итоге оказывается назад во времени, что странно).

Чтобы объяснить это словами:

  • Когда вы перемещаете свою ветку на их ветку, вы говорите Git, чтобы она выглядела так, как будто вы аккуратно проверили их ветку, а затем выполнили всю свою работу, начиная с нее. Это делает чистый, концептуально простой пакет изменений, который кто-то может просмотреть. Вы можете повторить этот процесс еще раз, когда в их ветке появятся новые изменения, и у вас всегда будет чистый набор изменений «на кончике» их ветки.
  • Когда вы объединяете их ветку с вашей веткой, вы соединяете две истории ветвей вместе на этом этапе. Если вы сделаете это снова позже с большим количеством изменений, вы начнете создавать чередующийся поток историй: некоторые их изменения, некоторые мои изменения, некоторые их изменения. Некоторые люди считают это грязным или нежелательным.

По причинам, которые я не понимаю, инструменты GUI для Git никогда не делали больших усилий, чтобы представить истории слияний более четко, абстрагируя отдельные слияния. Так что если вы хотите «чистую историю», вам нужно использовать rebase.

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

пример

Я попытаюсь объяснить это на примере только слова. Допустим, другие люди в вашем проекте работают над пользовательским интерфейсом, а вы пишете документацию. Без перебазирования ваша история может выглядеть примерно так:

Write tutorial
Merge remote-tracking branch 'origin/master' into fixdocs
Bigger buttons
Drop down list
Extend README
Merge remote-tracking branch 'origin/master' into fixdocs
Make window larger
Fix a mistake in howto.md

То есть слияния и пользовательский интерфейс фиксируются в середине вашей документации.

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

Write tutorial
Extend README
Fix a mistake in howto.md
Bigger buttons
Drop down list
Make window larger

Все ваши коммиты находятся вверху (самые новые), за ними следуют остальные masterветви.

( Отказ от ответственности: я являюсь автором поста «10 вещей, которые я ненавижу в Git», о котором говорится в другом ответе )

Стив Беннетт
источник
42

Хотя принятый и получивший наибольшее количество голосов отличный ответ, я также считаю полезным попытаться объяснить разницу только словами:

слияние

  • «Хорошо, у нас есть два разных состояния нашего хранилища. Давайте объединим их вместе. Двое родителей, один ребёнок.

перебазироваться

  • «Передать изменения основной ветви (независимо от ее имени) моей функциональной ветви. Сделайте так, притворившись, что моя работа с функциями началась позже, по сути, над текущим состоянием главной ветви ».
  • «Переписать историю моих изменений, чтобы отразить это». (нужно принудительно их толкать, потому что обычно управление версиями - это не вмешательство в данную историю)
  • «Скорее всего - если изменения, которые я совершил, не имеют ничего общего с моей работой, - история на самом деле не сильно изменится, если я посмотрю на мои коммиты diff по diff (вы также можете подумать о« патчах »)».

Резюме: когда это возможно, ребаз почти всегда лучше. Упрощение реинтеграции в основную ветку.

Потому что? Feature ваша функциональная работа может быть представлена ​​в виде одного большого «файла патча» (он же diff) по отношению к основной ветке, без необходимости «объяснять» нескольких родителей: по крайней мере, два из одного слияния, но, вероятно, еще много, если есть было несколько слияний. В отличие от слияний, множественные ребазы не суммируются. (еще один большой плюс)

Фрэнк Нок
источник
18

Git rebase ближе к слиянию. Разница в ребазе:

  • местные коммиты временно удаляются из ветви.
  • запустить мерзавец
  • вставьте снова все ваши локальные коммиты.

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

Виллем Франко
источник
7

Для легкого понимания можно увидеть мою фигуру.

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

введите описание изображения здесь

Нхан Цао
источник
0

Я нашел одну действительно интересную статью о git rebase vs merge , думал поделиться ею здесь

  • Если вы хотите увидеть историю полностью такой же, как она произошла, вы должны использовать слияние. Слияние сохраняет историю, тогда как rebase переписывает ее.
  • Слияние добавляет новый коммит в вашу историю
  • Перебазирование лучше упростить сложную историю, вы можете изменить историю фиксации с помощью интерактивной перебазировки.
nagendra547
источник