Страницы

Поиск по вопросам

понедельник, 25 марта 2019 г.

Как правильно сплющить (объединить) удалённые коммиты?

Дано:
Последовательные коммиты А и В, запушенные в удалённый репозиторий.
Задача:
Сделать из них один коммит С
Вопрос:
Беглое гугленье убеждает меня в том, что достаточно что-то типа такого сделать:
git squash А git squash В git push origin branchname
Верно ли я понял и что в процессе может пойти не так?


Ответ

Шаг 0: а можно ли это делать?
что в процессе может пойти не так
Если коммиты последовательные, то конфликтов изменений не будет. Но поскольку коммиты уже отправлены на удалённый репозиторий, то вам придётся переписывать историю там и что-нибудь может пойти не так у коллег. Вот пара вопросов о том, что и когда можно ребейзить и переписывать:
В каких случаях rebase можно и нужно делать, а в каких нет? Откатить уже опубликованный коммит и опубликовать новый, не вызывая мержа у других
Кратко: никогда нельзя это делать в стабильных ветках репозитория, где кроме вас есть ещё хоть один разработчик.
Шаг 1а: сплющивание через rebase -i
Под git squash вы наверное понимаете git rebase --interactive с последующим выбором опции squash. Действительно, можно сделать так:
Ребейз к третьему коммиту с конца (пред-предпоследнему)
git rebase -i HEAD^^
откроется такой документ:
pick 7423f96 сообщение предпоследнего коммита pick 91e9b6e сообщение последнего коммита
# Rebase c9e8f38..91e9b6e onto c9e8f38 (2 commands) ...
Чтобы объединить два коммита в один нужно сделать squash последнего в предпоследний:
pick 7423f96 сообщение предпоследнего коммита squash 91e9b6e сообщение последнего коммита
А потом сохранить документ и выйти из редактора. Откроется новый документ, в котором можно написать сообщение для вновь полученного коммита. По умолчанию там будет:
# This is a combination of 2 commits. # This is the 1st commit message:
сообщение предпоследнего коммита
# This is the commit message #2:
сообщение последнего коммита
Закомментированные строки не войдут в сообщение. Если оставить пустую строку, то rebase будет прерван.
Шаг 1б: сплющивание через reset
Поскольку нужно объединить N последних коммитов, отлично подойдёт более простой способ:
# сначала очистим индекс (staging area, область подготовки коммита), # чтобы потом не закоммитить ничего лишнего git reset . # поехали git reset --soft HEAD^^
Произошло следующее:
текущая ветка переставлена на коммит HEAD^^, т.е. на два коммита назад. изменения всех коммитов вплоть до, но не включая HEAD^^ собраны в индекс
Можно сделать новый коммит:
git commit -m'message'
В отличие от способа с rebase, информация об авторе и дате оригинального коммита не сохраняется. Лучше не ребейзить таким образом чужие коммиты, т.к. информация об авторстве обычно важна.
Шаг 1в: комбинированный подход
Предположим, что в предпоследнем коммите у вас написано нормальное сообщение, раскрывающее суть изменений. А в последнем вы исправили опечатку. Т.е. было бы удобно объединить два коммита, оставив сообщение от предпоследнего.
# То же, что и в шаге 1б: собираем содержимое последнего коммита в индекс git reset . git reset --soft HEAD^
# "редактируем" последний коммит, добавляя в него содержимое индекса # (на самом деле создаём новый коммит с тем же сообщением и переставляем на него ветку) git commit --amend --no-edit
Шаг 2. запушить на удалённый репозиторий
Поскольку вы переписали свою ветку, нужно будет запушить с -f.
git push -f origin mybranch

Комментариев нет:

Отправить комментарий