Что значит сквошировать коммиты в git?

117

Что означает Squashing в git. Как мне сквошировать коммиты в Github?

Я новичок в Git, и я попросил меня назначить ошибку новичка в coala-analyzer. Я исправил ошибку, и теперь меня попросили раздавить мои коммиты. Как мне это сделать?

Лакшманан Мейаппан
источник
Привет, @Lakshman, не стесняйтесь принимать ответ, получивший наибольшее количество голосов. Он правильно отвечает на ваш вопрос.
Мостафиз Рахман

Ответы:

181

Вы можете думать о Git как о расширенной базе данных моментальных снимков ваших рабочих каталогов.

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

Сжатие фиксации означает, с идиоматической точки зрения, переместить изменения, внесенные в упомянутую фиксацию, в ее родительский элемент, чтобы в итоге вы получили одну фиксацию вместо двух (или более).
Если вы повторите этот процесс несколько раз, вы можете уменьшить n коммитов до одного.

Визуально, если вы начали свою работу с коммита с тегом Start , вы хотите, чтобы это

Git совершает раздавливание

Вы можете заметить, что новый коммит имеет более темный оттенок синего. Это сделано намеренно.

В Git сжатие достигается с помощью Rebase специальной формы, называемой Interactive Rebase .
Упрощение, когда вы перемещаете набор коммитов в ветку B , вы применяете все изменения, внесенные этими коммитами, как они были сделаны, начиная с B вместо их исходного предка.

Визуальная подсказка

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

Еще раз обратите внимание на разные оттенки синего.

Интерактивная перебазировка позволяет вам выбирать, как следует перебазировать коммиты. Если вы запустите эту команду:

 git rebase -i branch

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

 pick ae3...
 pick ef6...
 pick 1e0...
 pick 341...

Я не назвал коммиты, но эти четыре предназначены для коммитов от начала до конца.

Этот список хорош тем, что его можно редактировать .
Вы можете опустить коммиты или раздавить их .
Все, что вам нужно сделать, это изменить первое слово на сквош .

 pick ae3...
 squash ef6...
 squash 1e0...
 squash 341...

Если вы закроете редактор и не обнаружите конфликтов слияния, вы получите эту историю:

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

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

git rebase -i HEAD~4

измените "команды" на squash для всех коммитов, кроме первого, а затем закройте редактор.


Примечание об изменении истории

В Git коммиты никогда не редактируются. Их можно обрезать, сделать недоступными, клонировать, но не изменять.
Когда вы перебазируете, вы фактически создаете новые коммиты.
Старые ссылки больше не доступны, поэтому не отображаются в истории, но они все еще там!

Вот что вы на самом деле получаете при перебазировании:

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

Если вы их куда-то уже отправили, переписывание истории фактически создаст ветку!

Маргарет Блум
источник
Хорошо - что же происходит с исходными комментариями коммита - объединяются ли они в один большой комментарий коммита или теряются?
Paul R
От man git rebase: Предлагаемое сообщение фиксации для свернутой фиксации представляет собой конкатенацию сообщений фиксации первой фиксации и тех, которые содержат команду "squash"
Маргарет Блум,
1
Это лучшее объяснение перебазирования, которое я видел, спасибо.
Керри Джонс
О сжатии в вашем первом изображении. Можете ли вы привести пример, где HEAD имеет другой рабочий каталог до (голубой) и после (темно-синий) сжатия? Во всех примерах, которые я пробовал, сжатие выглядело так, как будто он просто удалил три коммита между START и HEAD.
actual_panda
@actual_panda Я не уверен, что понимаю. HEAD - ссылка на коммит. Фиксирует дельты магазина. Рабочий каталог - это свойство репозитория в целом, это зависит от того, какой коммит вы зарегистрировали. В общем, две ссылки (например, HEAD и START) всегда дают два разных рабочих каталога при проверке. Если вы перебазируете сквош в той же ветке, это приведет к «потере» промежуточных коммитов, но на самом деле git создал новый со всеми дельтами. git diffможет помочь вам показать, что произошло.
Маргарет Блум,
22

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

Предупреждение: делайте это только для коммитов, которые не были отправлены во внешний репозиторий. Если другие основывают работу на коммитах, которые вы собираетесь удалить, может возникнуть множество конфликтов. Только не переписывайте свою историю, если ею поделились с другими.

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

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

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

$ git rebase -i HEAD~4

pick 01d1124 Adding license
pick 6340aaa Moving license into its own file
pick ebfd367 Jekyll has become self-aware.
pick 30e0ccb Changed the tagline in the binary, too.

# Rebase 60709da..30e0ccb onto 60709da
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

Итак, здесь произошло несколько вещей. Прежде всего, я сказал Git, что хочу выполнить перебазирование с использованием последних четырех коммитов, из которых HEAD находится с HEAD ~ 4. Теперь Git поместил меня в редактор с приведенным выше текстом и небольшим объяснением того, что можно сделать. На этом экране вам доступно множество опций, но сейчас мы просто собираемся объединить все в одну фиксацию. Итак, изменение первых четырех строк файла на это поможет:

pick 01d1124 Adding license
squash 6340aaa Moving license into its own file
squash ebfd367 Jekyll has become self-aware.
squash 30e0ccb Changed the tagline in the binary, too.

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

# This is a combination of 4 commits.
# The first commit's message is:
Adding license

# This is the 2nd commit message:

Moving license into its own file

# This is the 3rd commit message:

Jekyll has become self-aware.

# This is the 4th commit message:

Changed the tagline in the binary, too.

    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    # Explicit paths specified without -i nor -o; assuming --only paths...
    # Not currently on any branch.
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #   new file:   LICENSE
    #   modified:   README.textile
    #   modified:   Rakefile
    #   modified:   bin/jekyll
    #

Поскольку мы объединяем так много коммитов, Git позволяет вам изменять сообщение нового коммита на основе остальных коммитов, участвующих в процессе. Отредактируйте сообщение по своему усмотрению, затем сохраните и закройте. Как только это будет сделано, ваши коммиты будут успешно обработаны!

Created commit 0fc4eea: Creating license file, and making jekyll self-aware.
 4 files changed, 27 insertions(+), 30 deletions(-)
  create mode 100644 LICENSE
    Successfully rebased and updated refs/heads/master.

И если мы снова посмотрим на историю ... введите описание изображения здесь

Так что до сих пор это было относительно безболезненно. Если вы столкнетесь с конфликтами во время перебазирования, их обычно довольно легко разрешить, и Git проведет вас через все возможное. Основы этого - исправить конфликт, о котором идет речь, git addфайл, а затем git rebase --continueвозобновить процесс. Конечно, git rebase --abortесли вы захотите, вы вернетесь в предыдущее состояние. Если по какой-то причине вы потеряли фиксацию в перебазировании, вы можете использовать журнал ссылок, чтобы вернуть его.

Подробности можно найти по этой ссылке .

0xAliHn
источник
3
Спасибо! Если кому-то так же неудобно с VIM, как и мне ... когда вы дойдете до точки, где вы вводите действия для редактирования, нажмите «i», чтобы войти в режим редактирования. Когда вы закончите с изменениями, нажмите escape, затем введите «: wq», и он переместит вас вперед. (Mac)
Farasi78
+1 за предостережение и контекст того, когда это делать. По моему личному опыту, хорошо, если вы работаете в одиночку над функциональной веткой и имеете массу тривиальных коммитов, таких как «обновленный файл readme», «сделал что-то, о чем никому нет дела», и вы готовы объединить ветку, возможно, как ну просто свяжите все это в один коммит. Никто не захочет вернуться к вашему «сделал то, о чем никому нет дела», и это загрязняет историю коммитов
Адам Хьюз