В git, в чем разница между слиянием --squash и rebase?

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

6 ответов

Решение

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

  • git merge --squash abranch

создаст сжатый коммит в ветви назначения, не помечая каких-либо отношений слияния.
(Примечание: он не производит коммит сразу: вам нужен дополнительный 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 rebase --interactive

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

git checkout tmp
git rebase -i stable

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

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

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

  • merge не касается вашей исходной ветки (tmp здесь) и создает один коммит, где вы хотите.
  • rebase позволяет перейти на ту же ветку источника (до сих пор tmp) с:
    • новая база
    • более чистая история

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

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

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

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

Больше здесь

Начнем со следующего примера:

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

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

  2. Rebase и merge Добавит
    всю историюкоммитов ветки функции передосновной веткой
    НЕ добавит дополнительную фиктивную фиксацию.

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

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

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

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

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

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

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

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


Если вы последуете этому, это объяснит все, что вы хотите знать о сквош, слиянии, а также перемотке вперед и перебазировании.


Функциональные ветки

Допустим, у вас есть основная ветка в Origin с историей коммитов, A.

Вы извлекаете из Main и создаете новую ветку FeatureA , чтобы у вас была история коммитов:

  • A, B, C, F1, F2, F3 (три коммита в ветке FeatureA )

Вы хотите отправить свои изменения в Origin и объединить их с Main . Поскольку Main on Origin не изменился, вы также можете выполнить ускоренную перемотку вперед.

Объединить с быстрой перемоткой вперед

Примените всю историю коммитов ветки FeatureA поверх истории коммитов Main .

Объединиться со Сквошем

Опция, доступная всякий раз, когда в вашей ветке есть несколько коммитов, — это сжать. Сжатие объединяет историю ветки FeatureA в один коммит при слиянии с Main.

Перемотка вперед невозможна, если в Main произошли другие изменения.

Если вы внесли изменения в ветку FeatureA , в то время как другие внесли изменения в Main , так что история коммитов в Origin теперь выглядит так:A, B, C

Вы хотите отправить свои изменения в основную ветку Origin, и у вас есть несколько вариантов:

  • Объединить (без перемотки вперед)
  • Перебазировать,
  • Спрятать и вытащить.

Слияние (он же Слияние без перемотки вперед)

Если бы вам нужно было получить локальную копию основной ветки Origin и объединить ее с вашей локальной веткой FeatureA , вы бы создали коммит для этого слияния, M. Ваша локальная история в FeatureA будет:A, F1, F2, F3, M, где M — фиксация слияния.

Затем вы можете объединиться с Main (сжимая, если хотите). Обратите внимание: если вы не сделаете сжатие, вы добавите коммит слияния в основную историю коммитов:

  • А, Б, С, Ф1, Ф2, М.

Этого можно избежать, сжимая ветку при слиянии с Main , как описано выше в разделе «Сжатие», в результате чего получится:ABCF, например:

Перебазировать

Rebase — еще один способ избежать внесения коммита слияния в историю. По сути, он принимает ваши изменения и делает все так, как если бы вы начали с последней версии Main , а не с устаревшей версии Main . Например, после перебазирования ваша ветка Feature будет ответвляться от A, B, C (вместо A, как было изначально). Результат:

  • А, Б, С, Ф1, Ф2, Ф3

  • A, B, C, F (с кабачком)

Обратите внимание: коммит слияния отсутствует, M

Способ, которым Git достигает этого, заключается в систематическом — коммит за коммитом — применении изменений из основного источника в вашей ветке. Конечный результат выглядит так, как если бы вы не запускали ветку FeatureA в прошлом на основе фиксации A, а как если бы вы начали все свои изменения поверх последней версии Main .

Проблема в том , как это делается. Для каждого коммита, который необходимо применить к вашей ветке FeatureA , git проверяет наличие конфликтов слияния, и вы должны их разрешить. Если с момента вашей ветки FeatureA в Main в Origin было внесено более одного изменения , вы можете снова и снова разрешать конфликты слияния.

Возможно, проще спрятать и вытащить?

Спрятать и вытащить

Сохраните свою FeatureA , получите/извлеките обновленную локальную копию Main из Origin или создайте новую ветку и примените свой тайник. (Или объедините свою новую ветку Main со своей веткой и примените свой тайник. Если вы делаете последнее, раздавите, чтобы избежать слияния в истории коммитов.) Затем вы можете отправить запрос в Origin/создать запрос на включение.

Слияние и перебазирование сохраняют историю коммитов, а сквош - нет. Сохранение истории коммитов имеет огромное значение, и я усвоил это на собственном горьком опыте в следующем сценарии:

У нас есть основные ветки, ветки разработки и фич. Функция создается на стадии разработки и объединяется с основной версией после выпуска. Ветка исправлений была создана на основе master и объединена (поэтому разработчик не знает об этом). Мастер-версия не была объединена обратно в разработку после выпуска, поэтому они были рассинхронизированы: слияние из мастера обратно в разработку показывает изменения, а прямое слияние из разработки в мастер также показывает изменения (даже если в разработке ничего не изменилось).

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

Другие вопросы по тегам