[Перевод] Поддержание аккуратной истории в Git с помощью интерактивного rebase

Прим. перев.: эта статья была написана автором Git-клиента Tower, Tobias Günther, и опубликована в блоге GitLab. В ней просто и наглядно рассказывается об основных возможностях интерактивного rebase’а, что может стать отличным введением для тех, кто только начинает им пользоваться.

Interactive rebase — один из самых универсальных инструментов Git’а. В этой статье мы поговорим о том, как с его помощью корректировать сообщения при коммитах, исправлять ошибки, и о многом другом.

Интерактивный rebase иногда называют «швейцарским армейским ножом» Git’а, поскольку он объединяет в себе так много различных инструментов для совершенно разных сценариев применения. При этом главным вариантом использования, без сомнения, является очистка локальной истории коммитов.

Обратите внимание на слово «локальной»: rebase следует использовать только для очистки локальной истории коммитов (например, перед включением одной из ваших локальных feature-веток в общую ветку команды). И наоборот, этот мощный инструмент НЕ следует использовать для исправления коммитов в ветке, которая уже загружена и открыта для совместной работы в удаленном репозитории. Интерактивный rebase — инструмент для «переписывания» истории Git, и его не следует использовать для редактирования коммитов, которые уже открыты для других.

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

Примечание: для визуализации сценариев и последовательностей операций для некоторых скриншотов я использовал GUI к Git под названием Tower.

Редактирование сообщения в старом коммите

Иногда вы замечаете опечатку в старом коммите или вспоминаете, что забыли упомянуть нечто важное в его описании. Если бы речь шла о самом последнем коммите, можно было бы воспользоваться опцией –amend команды git commit. Но в случае более старых коммитов придется воспользоваться интерактивным rebase’ом.

Вот пример описания к коммиту, которое мы будем исправлять:

«Плохое» сообщение к коммиту, которое мы будем исправлять

Первый шаг при использовании interactive rebase — определить, какой частью истории мы обираемся манипулировать. В примере выше для того, чтобы изменить «плохое» коммит-сообщение, мы должны начать с его родительского коммита.

Начинаем с родительского коммита

Теперь нужно скормить хэш родительского коммита команде:

$ git rebase -i 0023cddd

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

Окно редактора со списком выбранных коммитов

Обратите внимание: в этом окне менять ничего не нужно! Или, говоря о нашем конкретном примере: не пытайтесь здесь поменять сообщение к коммиту ca9aacb! В этом окне вы только помечаете нужный коммит ключевым словом для соответствующего действия. Поскольку нужно перефразировать описание коммита, мы вводим reword. Сохраните изменения и закройте окно редактора. После этого появится новое окно, содержащее сообщение к старому коммиту. Теперь можно вносить изменения:

Редактирование описания старого коммита

Сохраните изменения и закройте окно. Поздравляю — сессия интерактивного rebase’а завершена, сообщение к коммиту успешно отредактировано!

Объединение нескольких коммитов в один

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

Давайте предположим, что нужно объединить следующие выбранные коммиты в один:

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

Как и в первом случае, процесс начинается с запуска сессии интерактивного rebase’а на коммите-предшественнике тех, что мы хотим изменить.

$ git rebase -i 2b504bee

Снова откроется окно редактора с историей коммитов, которые мы хотим объединить:

Помечаем нужные строки кодовым словом «squash»

Действию, которое мы собираемся произвести над коммитами, соответствует кодовое слово squash. В данном случае следует помнить лишь об одной тонкости: строка, помеченная «squash», будет объединена со строкой, которая находится выше нее. Именно поэтому на скриншоте выше я пометил словом squash строку №2 (она будет объединена со строкой №1).

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

Вводим сообщение для нового коммита

Сохраните сообщение и закройте окно. Будет создан новый коммит, содержащий изменения обоих старых коммитов. Вуаля!

Исправление ошибок

Interactive rebase отлично подходит для исправления ошибок в предыдущих коммитах. При этом не имеет значения, какая именно это ошибка: забыли ли вы внести определенное изменение, должны ли были удалить файл, или просто опечатались…

Обычное решение в подобной ситуации — просто сделать новый коммит, исправляющий ошибку. Но с другой стороны, это внесет дополнительную путаницу в историю: сначала у нас оригинальный коммит, затем мы добавили еще один, исправляющий ошибки… в общем, не слишком «чистый» рабочий подход. Очень скоро в истории коммитов станет нелегко разобраться, поскольку она будет забита всеми этими исправлениями/заплатками.

Именно для таких случаев и предназначен fixup. Этот инструмент берет коммит с быстрым исправлением, применяет его изменения к оригинальном коммиту (тем самым исправляя его), и удаляет корректирующий коммит.

Как работает fixup

После этого все будет выглядеть так, словно с оригинальным коммитом не было никаких проблем! Итак, давайте изучим весь процесс на практическом примере.

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

Следующий шаг — сделать коммит этих изменений в репозиторий, но с небольшой добавкой: делать коммит надо с флагом --fixup, попутно указав хэш «плохого» коммита:

$ git add corrections.txt

$ git commit --fixup 2b504bee

Если теперь посмотреть на историю, вы увидите, что был создан ничем не примечательный коммит (разве вы ожидали чего-то иного?). Но при более внимательном взгляде становятся заметны некоторые особенности: к новому коммиту были автоматически добавлены пометка «fixup!» и описание старого «плохого» коммита:

Оригинальный коммит и корректирующий коммит (fixup)

Теперь пора запускать interactive rebase. Опять же, в качестве отправной точки выбираем коммит, предшествующий «плохому»:

$ git rebase -i 0023cddd –autosquash

А вторым ингредиентом нашего секретного соуса выступает флаг --autosquash. Он позволяет не вносить дополнительных правок в открывшемся окне редактора. Внимательно посмотрите на скриншот:

Корректирующий коммит помечен как «fixup» и размещен в правильном порядке

Git автоматически сделал две вещи:

  1. Он пометил новый коммит как fixup.

  2. И переупорядочил строки так, чтобы fixup-коммит оказался непосредственно под «плохим» коммитом. Дело в том, что fixup работает в точности как squash: он объединяет выделенный коммит с коммитом выше.

Таким образом, нам ничего делать не надо. Сохраните изменения и закройте окно редактора.

Давайте еще раз взглянем на историю коммитов:

Счастливый финал!

Мало того, что оригинальный коммит теперь содержит правки из вспомогательного, но и некрасивый вспомогательный коммит (с исправлениями) исчез из истории. Все красиво, словно никогда и не было никаких проблем!

Откройте для себя возможности interactive rebase

Существует множество различных вариантов использования интерактивного rebase’а: большинство из них связаны с исправлением ошибок. Подробнее узнать о других способах можно в бесплатном (англоязычном) курсе «First Aid Kit for Git» — коллекции коротких видео (по 2-3 минуты на эпизод).

Примечание оригинального редактора: забавно, но мне пришлось воспользоваться interactive rebase при редактировании этой статьи! Один из коммитов включал изображение, размер которого превышал 1 Мб (что противоречит правилам сайта GitLab). Пришлось вернуться к этому коммиту и включить в него изображение подходящего размера. Спасибо за урок, Вселенная! ?

P.S. от переводчика

Читайте также в нашем блоге:

Let’s block ads! (Why?)

Read More

Recent Posts

Apple возобновила переговоры с OpenAI и Google для интеграции ИИ в iPhone

Apple возобновила переговоры с OpenAI о возможности внедрения ИИ-технологий в iOS 18, на основе данной операционной системы будут работать новые…

3 дня ago

Российская «дочка» Google подготовила 23 иска к крупнейшим игрокам рекламного рынка

Конкурсный управляющий российской «дочки» Google подготовил 23 иска к участникам рекламного рынка. Общая сумма исков составляет 16 млрд рублей –…

3 дня ago

Google завершил обновление основного алгоритма March 2024 Core Update

Google завершил обновление основного алгоритма March 2024 Core Update. Раскатка обновлений была завершена 19 апреля, но сообщил об этом поисковик…

3 дня ago

Нейросети будут писать тексты объявления за продавцов на Авито

У частных продавцов на Авито появилась возможность составлять текст объявлений с помощью нейросети. Новый функционал доступен в категории «Обувь, одежда,…

3 дня ago

Объявлены победители международной премии Workspace Digital Awards-2024

24 апреля 2024 года в Москве состоялась церемония вручения наград международного конкурса Workspace Digital Awards. В этом году участниками стали…

4 дня ago

Яндекс проведет гик-фестиваль Young Con

27 июня Яндекс проведет гик-фестиваль Young Con для студентов и молодых специалистов, которые интересуются технологиями и хотят работать в IT.…

4 дня ago