7.6. Rewriting History
Это типа конспект, который я веду для себя, чтобы получше разобраться и запомнить. Вероятно, вам лучше сразу читать оригинал: 7.6 Rewriting History.
Короткий вывод от прочтения. Рибэйз оказывается в сто раз проще сделать через терминал, чем через UI приложения, хоть SourceTree, хоть SublimeMerge, которые только усложняют и запутывают процесс.
Аменд
Изменение последнего коммита (Changing the Last Commit)
Пожалуй, самая популярная фича, чтобы поменять камент последнего коммита:
git commit --amend
Если хотим поменять содержимое, а камент оставить преждним и не открывать текстовый редактор, то:
git commit --amend --no-edit
Рибэйз
Изменение сообщений нескольких коммитов (Changing Multiple Commit Messages)
Запускает интерактивный режим и позволяет ручками менять сообщение каждого из затронутых коммитов:
git rebase -i HEAD~3
HEAD~3 значит, что вы затрагиваете коммиты в интервале HEAD~3..HEAD.
Юзаем инструкцию edit или reword.
В любой непонятной ситуации пишем git rebase --continue,
чтобы наверняка понимать, завершился ли rebase.
Если он чего-то не сможет сделать, то он поругается и предложит варианты для исправления.
Изменение порядка коммитов (Reordering Commits)
Та же команда git rebase -i может использоваться, чтобы поменять коммиты местами.
Нужно для этого в отркывшемся текстовом редактори пикнуть их (pick) в нужном порядке.
Объединение коммитов (Squashing Commits)
Всё то же самое, но юзаем squash или fixup. В процессе ребэйза он покажет текстовый редактор, куда напиханы все сообщения всех коммитах, и мы сможем сформировать финальное к сообщение к итоговому коммиту.
Разделение коммитов (Splitting a Commit)
Всё то же самое. Пользуемся командой edit.
Он останавливается на шаге с edit, и мы можем манипулировать со стейджем,
добавляем и убираем туда, что нам надо, и коммитим, потом ещё и ещё.
Алгоритм такой:
- гит останавливается на шаге
edit. - ресет коммита
git reset HEAD^— это отменяет коммит
и даёт вам ресетнутые изменения в рабочую копию.
- сделать из них сколько угодно коммитов
- когда закончили, делаем
git rebase --continue
В этом месте я заодно научился добавлять в коммит изменения построчно. Про это написано в разделе https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging. Однако, пока самый удобный инструмент для построчного добавления в коммит — это SourceTree.
Удаление коммита (Deleting a commit)
Юзаем drop или просто удаляем коммит из rebase-скрипта.
Откат рибэйза
Если вы потерялись во время рибэйза, то спасительная команда git rebase --abort.
Если передумали уже после завершения, то вы можете найти старые коммиты через git reflog.
Сайт с практическим руководством по ребэйзу
The Nuclear Option: filter-branch
Эта фича даёт some scriptable way обработать много коммитов. Собственно, ради неё я и залез в этот раздел мануала.
Фича обладает множеством подводных камней, так что стоит быть осторожным.
Удаление файла из каждого коммита (Removing a File from Every Commit)
Может пригодиться, если кто-то случайно запулил в репозиторий большой бинарник от которого вы хотите избавиться, или кто-то сто лет назад захардкодил пароль, а вы теперь собрались выложить проект в опенсорс.
Грохнем файл passwords.txt из всех коммитов:
git filter-branch --tree-filter 'rm -f passwords.txt' HEAD
Так можно грохнуть все бэкапы оставленные вимом:
git filter-branch --tree-filter 'rm -f *~' HEAD
Есть смысл применять эту команду на пробной ветке и если результат устраивает, то только потом перекидывать на неё мастер.
Флаг --all запускает команду на всех ветках.
Превращаем подкаталог в корневой каталог (Making a Subdirectory the New Root)
Например, вы мигрировались из SVN и хотите подпапку trunk переместить в корень:
git filter-branch --subdirectory-filter trunk HEAD
Меняем почту авторов
git filter-branch --commit-filter '
if [ "$GIT_AUTHOR_EMAIL" = "schacon@localhost" ];
then
GIT_AUTHOR_NAME="Scott Chacon";
GIT_AUTHOR_EMAIL="schacon@example.com";
git commit-tree "$@";
else
git commit-tree "$@";
fi' HEAD