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

Как подготовиться

Для некоторых операций из этой статьи Git будет открывать текстовый редактор. Во многих системах по умолчанию это Vim. Не самый дружелюбный для новичков. Чтобы вам было комфортно, установите в качестве Git-редактора ваш любимый редактор. Это делается с помощью команды:

git config --global core.editor

Если у вас Windows и вы хотите установить VS Code в качестве Git-редактора, ваша команда будет такой:

git config --global core.editor "code --wait"

А если у вас Mac OS и вы хотите установить Atom в качестве редактора по умолчанию, введите:

git config --global core.editor "atom --wait"

С другими редакторами нужно просто посмотреть команду и подставить её.

Как склеивать коммиты

Сначала узнаем, сколько коммитов нужно склеить. Эта команда покажет, какие коммиты у вас прибавились по сравнению с веткой master:

git cherry -v master

А эта — сколько их:

git cherry -v master | wc -l
git cherry -v master

Отлично, у нас пять коммитов. Теперь перепишем историю с момента HEAD~5, то есть с того, что было пять коммитов назад. Для этого делаем:

git rebase -i HEAD~5

Флаг -i — значит в интерактивном режиме. Открывается файл:

Тут список коммитов и большой комментарий о том, что можно сделать. Из списка команд видно, что мы можем использовать squash или fixup для склейки коммитов. Первый пригодится, когда нужно изменить коммит-месседж, а второй — когда хотите использовать коммит-месседж первого.

Итак, чтобы склеить все коммиты, делаем так:

То есть говорим «используй первый коммит, а остальные приклей к нему». Потом сохраняем файл и закрываем его. Git склеивает коммиты и предлагает ввести коммит-месседж (показывает коммит-месседжи всех склеенных коммитов):

Оставляем только последний:

Сохраняем файл и смотрим лог:

Ура, остался один коммит с нужным сообщением.

Теперь нужно работу отправить на ваш Git-сервер. Обычно это делается с помощью git push, но сейчас это не удастся:

Это потому, что ваша локальная ветка и ветка на сервере отличаются. Причём не просто в локальной ветке есть некоторые коммиты, которых нет на сервере, но и старых коммитов нет. Ведь теперь один новый коммит вместо всех прежних. Чтобы запушить на сервер все изменения, несмотря на конфликт, запустим пуш с флагом --force:

git push --force

Теперь всё получилось.

⭐ Используйте --force только тогда, когда вы уверены в своих действиях.

Как автоматизировать ребейз

Обычно всё-таки нужно оставить коммит-месседж первого изменения, типа «Сверстал то-то», остальные коммиты — просто правки к нему. Число правок иногда доходит до 15 — это не очень удобно, ведь нужно писать везде squash. Можно сделать так, чтобы коммиты автоматически присквошивались к нужному, для этого нужно их правильно коммитить. Предположим, мы поменяли файл и захотели закоммитить изменения как правку по ревью:

Сначала нужно узнать хеш коммита, к которому этот коммит является правкой. Воспользуемся уже знакомым cherry:

git cherry -v master

Вот наш хеш. А теперь следующий коммит обозначим правкой к этому:

git commit --fixup <хеш нужного коммита>

Необязательно в точности копировать весь хеш, достаточно первых 7 символов. Я обычно выделяю от начала и сколько выделится и копирую:

git commit --fixup

Изменения закоммитились с сообщением fixup! Сообщение того коммита. История теперь выглядит nак:

git log

Добавим ещё несколько правок таким образом. Посмотрим изменения:

git cherry -v master

Отлично. А теперь склеим все эти коммиты. Только не вручную. Git сделает это за нас:

git rebase -i --autosquash HEAD~4

И Git сам подставит слово fixup там, где нужно:

git rebase -i --autosquash

Просто сохраняем, и Git склеивает коммиты и использует коммит-месседж первого:

Результат автосквоша

Материалы по теме