В git, в чем разница между объединением --squash и rebase?

364

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

Gih
источник

Ответы:

360

И то, git merge --squashи другое git rebase --interactiveможет произвести «сдавленный» коммит.
Но они служат разным целям.

создаст сжатый коммит в ветви назначения, не помечая никаких отношений слияния.
(Примечание: он не производит коммит сразу: вам нужно дополнительное git commit -m "squash branch").
Это полезно, если вы хотите полностью отбросить ветку-источник, начиная с (схема взята из SO-вопроса ):

 git checkout stable

      X                   stable
     /                   
a---b---c---d---e---f---g tmp

чтобы:

git merge --squash tmp
git commit -m "squash tmp"

      X-------------------G stable
     /                   
a---b---c---d---e---f---g tmp

а затем удаляя tmpветку.


Примечание: git mergeесть --commitопция , но ее нельзя использовать с --squash. Это не было никогда возможно использовать --commitи --squashвместе.
Начиная с Git 2.22.1 (Q3 2019), эта несовместимость сделана явной:

См. Коммит 1d14d0c (24 мая 2019 г.) Вишала Вермы ( reloadbrain) .
(Слиты Junio C Hamano - gitster- в фиксации 33f2790 , 25 июл 2019)

merge: отказаться --commitс--squash

Ранее, когда --squashбыло предоставлено, « option_commit» было тихо отброшено. Это могло бы быть неожиданным для пользователя, который пытался переопределить поведение сквоша без коммитов --commitявно.

git/git builtin/merge.c#cmd_merge() теперь включает в себя:

if (option_commit > 0)
    die(_("You cannot combine --squash with --commit."));

воспроизводит некоторые или все ваши коммиты на новой базе, позволяя вам раздавить (или совсем недавно «исправить», см. этот вопрос ), перейдя непосредственно к:

git checkout tmp
git rebase -i stable

      stable
      X-------------------G tmp
     /                     
a---b

Если вы решили раздавить все коммиты tmp(но, вопрекиmerge --squash , вы можете выбрать переигрывание одних и подавление других).

Итак, различия:

  • squashне касается вашей исходной ветви ( tmpздесь) и создает один коммит, где вы хотите.
  • rebaseпозволяет вам продолжить в той же ветке исходного кода (все еще tmp) с:
    • новая база
    • более чистая история
VonC
источник
12
Gэто c--d--e--f--gсжато вместе?
Уэйн Конрад
9
@Wayne: да, G в этих примерах представляет собой tmpкоммиты, сжатые вместе.
VonC
3
@ Th4wn: Так как Git объясняет снимками всего проекта, Gне будет представлять тот же контент g, что и из-за внесенных изменений X.
VonC
1
@VonC: не уверен насчет последнего комментария. Если у вас есть git merge --no-ff tempвместо git merge --squash temp, то вы получите более грязную историю, но вы также можете делать вещи, как git revert e, гораздо проще. Это грязная, но честная и прагматичная история, и основная ветвь все еще остается довольно чистой.
naught101 13.12.12
2
@ naught101 Я согласен. Как объяснено в stackoverflow.com/a/7425751/6309, тем не менее, речь идет также о том, чтобы не ломаться git bisectили git blameкогда используется слишком часто (как в git pull --no-ff: stackoverflow.com/questions/12798767/… ). В любом случае, нет единого подхода, поэтому в этой статье описано три ( stackoverflow.com/questions/9107861/… )
VonC
184

Объединить коммиты: сохраняет все коммиты в вашей ветке и чередует их с коммитами в базовой веткевведите описание изображения здесь

Merge Squash: сохраняет изменения, но пропускает отдельные коммиты из истории введите описание изображения здесь

Rebase: это перемещает всю ветвь объекта, чтобы начать с кончика мастер-ветви, эффективно объединяя все новые коммиты в master

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

Больше здесь

Аюб Али Саркер
источник
Я нашел это более ясным, чем принятый ответ. Спасибо!
Пейн
81

Merge squash объединяет дерево (последовательность коммитов) в один коммит. То есть он подавляет все изменения, внесенные в н коммитах, в один коммит.

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

При интерактивном перебазировании вам предоставляется возможность либо раздавить, выбрать, отредактировать или пропустить коммиты, которые вы собираетесь перебазировать.

Надеюсь, это было ясно!

Маурисио Шеффер
источник
7
Когда я должен перебазировать и когда я должен раздавить?
Мартин Тома
31

Давайте начнем со следующего примера:

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

Теперь у нас есть 3 варианта объединить изменения признака филиала Into мастер филиала :

  1. Слияние коммитов
    Сохранит историю всех коммитов ветви функций и переместит их в основную ветку.
    Добавит дополнительный фиктивный коммит.

  2. Перебазирование и слияние Добавит
    всю историю коммитов ветви функций в начало главной ветки,
    НЕ добавит дополнительный фиктивный коммит.

  3. Сквош и слияние
    Сгруппирует все коммиты ветвей объектов в один коммит, затем добавит его перед главной ветвью.
    Добавит дополнительный фиктивный коммит.

Ниже вы можете увидеть, как главная ветвь будет выглядеть после каждого из них.

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

Во всех случаях:
мы можем безопасно УДАЛИТЬ ветку функций .

ahmednabil88
источник
1
Можете ли вы объяснить, что такое фиктивный коммит на 2-й картинке? Я новичок в Git.
Юсуф
1
@Yusuf, это просто дополнительный коммит, который содержит обновления обеих веток, это сообщение о
коммите