Управление версиями с помощью Git стало стандартом в инструментарии каждого современного разработчика. Команды типа commit
, push
и pull
уже закрепились в мускульной памяти наших пальцев. Но сравнительно немногие разработчики знают о “более продвинутых” функциях Git — и о том, как невероятно ценными они могут быть! В этой статье мы рассмотрим “интерактивный ребейс”, один из самых мощных инструментов Git.
Почему Интерактивный Ребейс Должен Быть В Наборе Каждого Разработчика
В двух словах, без преувеличения, интерактивный ребейс может помочь вам стать лучшим разработчиком, позволяя создавать чистую и хорошо структурированную историю коммитов в ваших проектах.
Почему важна хорошо структурированная история коммитов? Просто представьте противоположность: трудночитаемую историю коммитов, где вы не имеете понятия, что ваши коллеги на самом деле сделали с их недавними изменениями. Все больше и больше “темных уголков” начинают появляться в таком проекте, и вы понимаете только небольшие части, над которыми работали сами.
В сравнении с чистой и хорошо структурированной историей коммитов: это помогает сделать код проекта более читаемым и легче понятным. Это важный компонент для здорового, долговечного проекта!
Что Интерактивный Ребейс Может Сделать для Вас
Интерактивный Ребейс помогает оптимизировать и почистить вашу историю коммитов. Он охватывает множество различных случаев, некоторые из которых позволяют вам делать следующее:
- редактировать сообщение старого коммита
- удалить коммит
- склеить/объединить несколько коммитов
- переупорядочить коммиты
- исправить старые коммиты
- разделить/переоткрыть старые коммиты для редактирования
Когда использовать интерактивное перебазирование (и когда не надо!)
Как и некоторые другие инструменты Git, интерактивное перебазирование “переписывает историю”. Это означает, что при манипуляции серией коммитов с помощью интерактивного перебазирования эта часть вашей истории коммитов будет переписана: хэши SHA-1 коммитов изменятся. Они полностью новые объекты коммитов, так сказать.
Этот факт требует простого, но важного правила: не используйте интерактивное перебазирование (или другие инструменты, которые переписывают историю) для коммитов, которые вы уже поделились с коллегами на удаленном репозитории. Вместо этого используйте его для очистки своих собственных, локальных коммитов — таких как в одной из своих фича-ветвей — перед их слиянием в командной ветке.
Основной механизм операции интерактивного перебазирования
Хотя интерактивное перебазирование можно использовать для множества различных целей, основной рабочий процесс всегда одинаков. Как только вы твердо поймете этот основной механизм, интерактивное перебазирование потеряет свой ауру “сложной тайны” и станет ценным, доступным инструментом в вашем ремне.
Шаг 1: Где следует начать сессию?
Первый вопрос, на который нужно ответить, это: “Какую часть моей истории коммитов я хочу манипулировать?” Это подсказывает, где вы должны начать свою интерактивную сессию перебазирования. Давайте рассмотрим практический пример и скажем, что мы хотели бы отредактировать старый коммит-сообщение (что мы на самом деле и сделаем через мгновение).
Начальная ситуация изображена ниже, где мы редактируем старую сообщение коммита через интерактивный ребейс.
Чтобы изменить сообщение коммита в C2
, мы должны начать наш интерактивный сеанс ребейса от его родительского коммита (или даже раньше, если хотите). В данном примере мы будем использовать C1
в качестве отправной точки для нашего интерактивного сеанса ребейса.
Шаг 2: начало фактического сеанса!
Начало фактического сеанса довольно просто:
$ git rebase -i HEAD~3
Мы используем команду git rebase
с флагом -i
(чтобы указать, что нам действительно нужен “интерактивный” режим) и предоставляем базовый коммит (который мы определили на первом шаге выше). В этом примере я использовал HEAD~3
для указания коммита, который на “3 коммита назад от текущего”. В качестве альтернативы, я также мог бы предоставить конкретный SHA-1 хэш.
Шаг 3: сообщаем Git, что вы хотите сделать
После начала интерактивного сеанса ребейса, вы увидите окно редактора, где Git перечисляет ряд коммитов — от самого последнего коммита до (но не включая) того, который вы выбрали в качестве базового коммита на Шаге 1.
На этом шаге важно помнить две вещи:
- Коммиты перечислены в обратном порядке! Самый новый коммит, который мы ожидаем увидеть на вершине, окажется на дно списка. Не волнуйтесь: ваш Git репозиторий в порядке! 🥳 Помните, что мы находимся в процессе выполнения интерактивного ребейса, и это требует от Git переприменения коммитов от самых старых к самым новым в конце операции.
- Не делайте свои фактические изменения в этом редакторе! Хотя вам, возможно, захочется просто продолжить и изменить сообщение о коммите в этом редакторе (в конце концов, это то, что мы действительно хотим сделать…), вам нужно проявить терпение. Здесь мы только собираемся рассказать Git что мы хотим сделать — но не совершать само изменение. Я продемонстрирую этот момент на практике в ближайшее время!
Теперь, когда теоретический обзор позади, давайте окунемся в некоторые практические случаи вместе!
Редактирование старого сообщения коммита
Одно из самых популярных применений интерактивного ребейза заключается в том, что вы можете редактировать старое сообщение коммита после того, как оно было создано. Возможно, вы знаете, что git commit --amend
также позволяет вам изменить сообщение коммита — но только если это самый последний коммит. Для любого коммита, который старше этого, мы должны использовать интерактивный ребейз!
Давайте рассмотрим конкретный сценарий. Ниже представлено изображение плохого сообщения коммита, которое нужно исправить.
Примечание: Для лучшего обзора и более четкой визуализации я использую Tower Git десктоп-клиент в некоторых из моих скриншотов. Вам не нужен Tower, чтобы следовать этому уроку.
Для нашего примера, допустим, что мы хотели бы отредактировать сообщение коммита, которое в настоящее время называется “Оптимизировать структуру разметки в индексе…”
Наш первый шаг – определить базовый коммит для начала интерактивной сессии ребейса. Поскольку нам нужно (как минимум) вернуться к родителю нашего “плохого” коммита, мы начинаем нашу сессию с HEAD~3 (три коммита назад от текущего коммита HEAD, который называется “Изменение заголовков …”):
$ git rebase -i HEAD~3
Сразу после выполнения этой команды, ваш любимый редактор откроется и представит список выбранных коммитов (указав базовый коммит).
Напоминаем: хотя вам может быть захочется сделать это, мы не меняем сообщение коммита здесь. Мы только отмечаем соответствующую строку с помощью “ключевого слова действия”. В нашем случае, мы хотим перефразировать
коммит (что означает, что мы хотим изменить сообщение коммита, но оставить остальную часть коммита без изменений).
Достаточно практично, все доступные ключевые слова действий документированы внизу этого окна – так что не нужно ничего запоминать наизусть!
После замены стандартного ключевого слова pick
(что означает “принять коммит как есть”) на ваше предпочтительное ключевое слово действия, вы можете просто сохранить и закрыть окно.
После этого, откроется новое окно редактора, содержащее текущее сообщение коммита. Наконец, мы можем сделать то, ради чего изначально начали: отредактировать это старое сообщение коммита!
После внесения изменений и затем сохранения и закрытия окна редактора, интерактивная сессия ребейса завершена – и наше сообщение коммита обновлено! 🎉
Удаление нежелательного коммита
Интерактивный ребейз также позволяет вам удалить старый коммит из вашей истории, который вам больше не нужен (или не хочется иметь). Представьте, что вы случайно включили личный пароль в недавний коммит: такая конфиденциальная информация, как правило, не должна содержаться в коде.
Также помните, что просто удаление информации и повторный коммит не решает вашу проблему: это означает, что пароль все еще сохранен в репозитории в виде вашего старого коммита. То, что вам действительно нужно, это полностью удалить эту информацию из репозитория!
Начнем с определения базового коммита для нашей интерактивной сессии ребейза. Поскольку нам нужно начать хотя бы с родительского коммита плохого коммита, мы используем коммит “Оптимизация структуры разметки…” в качестве основы:
$ git rebase -i 6bcf266b
Обратите внимание, что на этот раз я использовал конкретный хэш SHA-1 в команде git rebase -i
. Вместо хэша коммита, конечно, я мог бы использовать HEAD~2
для обращения к этому коммиту.
После выполнения этой команды нам снова представлен список коммитов.
На этот раз мы используем ключевое слово действия drop
для удаления ненужного коммита. В качестве альтернативы в этом специальном случае мы могли бы просто удалить всю строку из редактора. Если строка (представляющая коммит) больше не присутствует при сохранении и закрытии окна, Git удалит соответствующий коммит.
Однако вы это сделаете, после сохранения и закрытия окна редактора коммит будет удален из истории вашего репозитория!
Объединение нескольких коммитов в один
Еще один случай использования интерактивного ребейза — это когда вы хотите объединить несколько отдельных коммитов в один. Прежде чем мы углубимся в как это работает, давайте поговорим о когда или зачем это может быть полезным.
Как правило, делать коммиты “большими” (объединяя несколько в один) не является хорошей стратегией в большинстве случаев. Общий принцип — держать коммиты как можно меньше, потому что “маленькие” означают “легче читать и понимать”. Но есть ситуации, когда это все же имеет смысл. Вот два примера:
- Представьте, что вы обнаружили проблему в более старом коммите. Вы можете сделать новый коммит, который исправляет проблему. В такой ситуации иметь возможность объединить эти коммиты в один имеет большой смысл: новый коммит, в конце концов, был всего лишь “платкой на рану”, чтобы исправить проблему, которой изначально не должно было быть. Объединив эти коммиты, можно сделать так, чтобы проблема никогда не возникала!
- Другой пример — когда вы заметили, что сделали вещи немного слишком мелкими. Мелкие коммиты — это хорошо, но разбрасывать по истории коммитов множество излишне мелких коммитов означает перебор.
Причина в обоих примерах одна и та же: объединяя два (или несколько) коммитов, которые изначально должны были быть одним, вы создаете более чистую и читаемую историю коммитов!
Давайте рассмотрим практический пример и возьмем ситуацию, изображенную ниже, как нашу исходную ситуацию.
Предположим, что семантически более логично объединить эти два коммита в один. Используя инструмент squash
интерактивного ребейса, мы действительно можем их объединить:
$ git rebase -i HEAD~3
К этому моменту вы уже привыкли к тому, что происходит дальше: открывается окно редактора с списком коммитов.
I already mentioned that we’re going to use the squash
action keyword in this case. There’s an important thing to know about how squash
works: the line you mark up with the keyword will be combined with the line directly above! This explains why I marked line 2 with the squash
keyword in our example.
После сохранения и закрытия этого окна, откроется новое. Это происходит потому, что объединяя несколько коммитов, мы, конечно же, создаем новый. И этот новый коммит тоже требует сообщения о коммите, как и любой другой!
На скриншоте выше вы видите, что Git подготовил для нас: он объединил сообщения коммитов из исходных коммитов вместе с некоторыми комментариями. Вы можете удалить старые сообщения и начать заново — или оставить их и добавить дополнительную информацию.
После сохранения и закрытия этого окна редактора, мы можем гордо заявить: то, что раньше было двумя отдельными коммитами, теперь является одним!
Использование возможностей интерактивного ребейса
I hope you agree that Git’s interactive rebase tools can be very valuable! As developers, it’s important for us to strive for a clean and clear commit history. It’s a crucial ingredient in keeping a codebase healthy and easy to understand (both for your teammates, and yourself, after some time has passed).
Если вы хотите узнать больше, я очень рекомендую “Первую помощь по Git“. Это (бесплатная) коллекция коротких видео, которая показывает, как чистить и отменять ошибки в Git.
Приятного использования!
Часто задаваемые вопросы (FAQ) о Git Interactive Rebase
В чем разница между Git Rebase и Git Merge?
Git Rebase и Git Merge — это два разных способа интегрировать изменения из одной ветки в другую. Git Merge — простой способ объединить код из двух разных веток. Он создает новый коммит в истории, сохраняя хронологический порядок коммитов. С другой стороны, Git Rebase — это способ перемещения или объединения последовательности коммитов в новый базовый коммит. Это похоже на то, что ты говоришь: «Я хочу базировать свои изменения на том, что сделали все остальные». Другими словами, он позволяет разместить изменения из текущей ветки сверху другой ветки.
Как отменить Git Rebase?
Чтобы отменить Git Rebase, можно использовать команду git reflog
, чтобы найти коммит, к которому хочешь вернуться, а затем использовать команду git reset --hard HEAD@{number}
. Команда git reflog
показывает список всех изменений, сделанных в HEAD, а команда git reset
позволяет установить текущий HEAD в указанное состояние.
Какова цель Git Interactive Rebase?
Git Interactive Rebase позволяет изменять коммиты различными способами, такими как редактирование, удаление и сжатие. Вы можете не только изменить сообщение коммита, но и изменить сам код, если допустили ошибку. Это мощный инструмент, который дает полный контроль над историей коммитов вашего проекта.
Как сжать коммиты с помощью Git Interactive Rebase?
Сглаживание – это акт объединения нескольких коммитов в один. В Git вы можете сглаживать коммиты с помощью команды git rebase -i
, после чего указывается хэш коммита, который вы хотите сгладить. В открывшемся текстовом редакторе вы можете отметить коммиты, которые хотите сгладить, заменив pick
на squash
или s
рядом с каждым коммитом.
Каковы риски использования Git Interactive Rebase?
Хотя Git Interactive Rebase является мощным инструментом, он может быть опасен, если использовать его неправильно. Он переписывает историю коммитов, что может быть проблематично, если вы работаете над публичной веткой, на которой также работают другие. Рекомендуется использовать его на локальных ветках, которые еще не были отправлены.
Как можно решить конфликты во время Git Rebase?
Во время ребейза могут возникнуть конфликты. Git приостановит процесс и позволит вам решить эти конфликты перед продолжением. Вы можете решить конфликты, редактируя файлы для исправления конфликтующих изменений, а затем добавив разрешенные файлы с помощью git add
. После решения всех конфликтов вы можете продолжить ребейз с помощью git rebase --continue
.
Могу ли я использовать Git Interactive Rebase для разделения коммита?
Да, вы можете использовать Git Interactive Rebase для разделения коммита на более мелкие. Это может быть полезно, если вы сделали несколько изменений в одном коммите, но потом решили, что они должны быть отдельными коммитами.
Как можно редактировать сообщение коммита с помощью Git Interactive Rebase?
Вы можете редактировать сообщение коммита во время интерактивного ребейса. В списке коммитов замените pick
на reword
или r
рядом с коммитом, который вы хотите отредактировать. При продолжении Git откроет текстовый редактор для каждого отмеченного reword
коммита, позволяя вам изменить сообщение коммита.
В чем разница между Git Rebase и Git Pull?
Git Pull – это команда, которая извлекает изменения из удаленного репозитория и объединяет их в текущую ветку. С другой стороны, Git Rebase – это команда, которая перемещает или объединяет последовательность коммитов в новый базовый коммит. Хотя обе команды используются для интеграции изменений, они делают это разными способами.
Могу ли я использовать Git Interactive Rebase для изменения порядка коммитов?
Да, вы можете изменить порядок коммитов с помощью Git Interactive Rebase. В списке коммитов вы можете просто изменить порядок строк, чтобы изменить порядок коммитов. Это может быть полезно, если вы хотите сделать историю коммитов более логичной или понятной.
Source:
https://www.sitepoint.com/git-interactive-rebase-guide/