Вступление
В мире программирования эффективное управление версиями кода играет ключевую роль в обеспечении качества и стабильности программного обеспечения. Система контроля версия Git предоставляет разработчикам мощные инструменты для работы с ветками и историей изменений. Два из таких инструментов — git merge
и git rebase
— часто используются для интеграции изменений в разных ветках, но они имеют свои уникальные особенности и преимущества.
Многие новички в Git склонны избегать git rebase
, опасаясь его сложностей и возможных последствий для истории версий. Это страх нередко обусловлен недостатком опыта и понимания, как правильно использовать этот инструмент. Тем не менее, git rebase
может предложить более чистый и логически структурированный журнал изменений, что делает его полезным в некоторых ситуациях. В этой статье мы рассмотрим различия между git merge
и git rebase
.
Данная статья будет опираться на книгу Git Pro (Scott Chacon).
1. Git merge
Данная команда выполняет объединение двух или более ветвей разработки и включает изменения из именнованных коммитов с момента, когда эти ветви разошлись с текущей. Зачастую эта команда используется вручную для слияния изменений из одной ветви в другую.
1.1 Пример
Рассмотрим следующую историю разработки:
A---B---C topic <-
/
D---E---F---G master
Мы имеем две ветви: topic
и master
. В текущий момент мы находимся в topic
. Наша задача: слить изменения из неё в master
. Выполним следующую команду:
git checkout master
A---B---C topic
/
D---E---F---G master <-
Теперь мы находимся в master
. Далее выполним следующую команду.
git merge topic
Рассмотрим историю разработки, после успешного выполнения команды:
A---B---C topic
/ \
D---E---F---G---H master <-
Важно отметить, что в процесс слияния остановится, если возникает конфликт, который не может быть разрешен автоматически!
Примерная последовательность коммитов в выводе команды git log:
D--E--A--F--B--G--C--H
1.2 Плюсы и минусы
Из плюсов команды можно выделить:
- Простота использования
- Сохранение полной истории разработки, а так же соблюдение хронологического порядка
- Создание нового коммита, сообщающего о выполнении команды
Из минусов можно выделить:
- История коммитов может заполняться "ненужными" коммитами
- Довольно сложная отладка процесса слияния
1.3 Литература
Подробнее про git merge и параметры данной команды можно почитать здесь.
2. Git rebase
Преобразование - это процесс перемещающий одну последовательность коммитов к новому базовому коммиту. В процессе данной операции Git создает новые коммиты и применяет их к указанному основанию. Это важно понимать. ведь в действительности новая часть ветки всегда будет состоять из совершенно новых коммитов.
2.1 Пример первый
Предположим, что существует следующая история с текущей веткой topic
A---B---C topic <-
/
D---E---F---G master
Выполним одну из следующих команд
git rebase master
git rebase master topic
A'--B'--C' topic <-
/
D---E---F---G master
2.2 Пример второй
Если topic имел бы изменение, которое уже было внесено (допустим, был отправлен некоторый патч, который был применен в master
ветки), то данный коммит с изменением будет пропущен и будет выдано предупреждение.
A---B---C topic <-
/
D---E---A'---F master
В результате будет получен следующий результат:
B'---C' topic <-
/
D---E---A'---F master
2.3 Плюсы и минусы
Из плюсов данной команды можно выделить:
- История проекта становится более читаемой и понятной. Изменения линейны.
- Изменения применяются поочередно, что приводит к более чистому состоянию истории, ведь потенциальные конфликты тоже устраняются постепенно.
- Есть возможность объединять или очищать коммиты.
Из минусов можно выделить:
- Данная команда изменяет историю коммитов и их хэш-коды.
- Встречаются конфликты более болезненные чем при merge.
- Сжатие коммитов может скрывать полезную информацию
2.4 Литература
Подробнее про git rebase можно прочитать здесь.
3. Git rebase -i (Интерактивное перемещение)
Данное исполнение команды позволяет изменять коммиты, при их перемещении в другую ветку. Это позволяет осуществлять лучший контроль над историей и содержимым коммитов. Например, очищение ненужных историй или их слияние в одну.
3.1 Пример
Рассмотрим уже известную нам историю:
A---B---C topic <-
/
D---E---F---G master
Выполним следующую команду
git rebase -i master
Откроется редактор, в котором будут перечислены все коммиты, планируемые к перемещению.
pick 11d2d3c A
pick 22e3a4b B
pick 33f4d5h C
Данный список предоставляет информацию о том, как будет выглядеть ветка после перемещения. Есть возможность изменить её, сделав историю такой, какой вы захотите. Есть возможность использовать следующие команды:
Commands:
p, pick = use commit
r. reword = use commit, but edit the commit message
e, edit = use commit, but stop for amending
s, squash = use commit, but meld into previous commit
f, fixup = like "squash", but discard this commit's log message
x, exec = run command (the rest of the line) using shell
d, drop = remove commit
В редакторе, который был открыт выше, изменим некоторую информацию:
pick 11d2d3c M
fixup 22e3a4b B
f 33f4d5h C
В результате выполнения данной команды история будет выглядеть так
M topic <-
/
D---E---F---G master
Подводя итоги, можно сказать,что rebase
не изменяет целевую ветку, он лишь переносит изменения из текущей ветки на вершину целевой, причем указатель остается на вершине текущей.
Резюме
Выбор между rebase
и merge
зачастую будет зависеть от "исторически сложившихся" обстоятельств и привычек в вашей команде. Оба метода имеют свои плюсы, минусы и особенности в работе. При работе в общих ветках рекомендуется использовать merge
. При работе в команде, где разработчики не меняются часто ветками и следят за чистой, красивой и понятной историей предпочитается использовать rebase
.