В системе контроля версий Git есть два способа объединения одной ветки с другой, выраженные в виде разных команд:
-
git merge. Коммиты (изменения) из одной ветки переносятся в другую путем создания коммита слияния.
-
git rebase. Коммиты (изменения) из одной ветки переносятся из одной ветки в другую путем сохранения оригинального порядка изменений.
Говоря проще, при git merge коммиты одной из веток «схлопываются» в один, а при git rebase — остаются нетронутыми. При этом ветки объединяются.
Таким образом команда git rebase позволяет объединить коммиты обеих веток через образование общей истории изменений.

Разница между git merge и git rebase
В этом руководстве будет рассмотрена команда git rebase, отвечающая за перебазирование коммитов (изменений) из одной ветки в другую.
Все показанные примеры использовали систему контроля версий Git версии 2.34.1, которая запускалась на облачном сервере Timeweb Cloud под управлением операционной системы Ubuntu 22.04.
В блоге Timeweb Cloud есть отдельные публикации, подробно рассказывающие об установке Git на популярные операционные системы:
Теория: git rebase
Понять устройство ребазирования в Git лучше всего на примере абстрактного репозитория, состоящего из нескольких веток. При этом операцию ребазирования необходимо рассматривать поэтапно.
Создание веток
Предположим мы создали репозиторий с единственной веткой master, в которую сделали только один коммит. Ветка master приобрела следующий вид:
-
master -
commit_1
После этого на основе master мы создали новую ветку hypothesis, внутри который решили протестировать некоторые фичи. Внутри новой ветки мы сделали несколько коммитов, улучшающих кодовую. Ветка приобрела такой вид:
-
hypothesis -
commit_4 -
commit_3 -
commit_2 -
commit_1
А уже потом мы добавили еще один коммит в ветку master, исправив некоторую уязвимость в срочном порядке. Таким образом, ветка master стала выглядеть так:
-
master -
commit_5 -
commit_1
Теперь наш репозиторий имеет структуру из двух веток:
-
master -
commit_5 -
commit_1
-
hypothesis -
commit_4 -
commit_3 -
commit_2 -
commit_1
Ветка master является основной, а hypothesis — второстепенной (производной). Поздние коммиты указываются выше ранних, подобно тому, как их выводит команда git log.
VDS и VPS
биллингом по всему миру: Россия, Азия и Европа.
Объединение веток
Предположим, мы хотим продолжить работу над улучшением фичи, под которую ранее выделили отдельную ветку hypothesis. Однако эта ветка не содержит жизненно важное исправление уязвимости, которое мы сделали в ветке master.
Поэтому нам хотелось бы «синхронизировать» состояние ветки hypothesis с веткой master так, чтобы коммит исправления оказался в ветке с фичей. То есть мы хотим получить примерно такую структуру репозитория:
-
master -
commit_5 -
commit_1
-
hypothesis -
commit_4 -
commit_3 -
commit_2 -
commit_5 -
commit_1
Как видно, ветка hypothesis будет точно повторять историю изменений ветки master, несмотря на то, что изначально она была создана до коммита commit_5. Иными словами, ветка hypothesis будет содержать историю обеих веток — и свою, и master.
Чтобы получить такой результат, необходимо выполнить ребазирование с помощью команды git rebase.
Впоследствии изменения, сделанные в hypothesis, можно будет объединить с веткой master с помощью классической команды git merge, создающей коммит слияния.
Тогда структура репозитория станет такой:
-
master -
commit_merge -
commit_5 -
commit_1
-
hypothesis -
commit_4 -
commit_3 -
commit_2 -
commit_5 -
commit_1
Более того, выполнение git merge после команды git rebase может снизить вероятность возникновения конфликтов.
Практика: git rebase
Разобравшись с теоретическим аспектом команды git rebase, можно перейти к ее тестированию в реальном репозитории некого импровизированного проекта. При этом структура репозитория будет повторять показанный ранее теоретический пример.
Создание репозитория
Для начала создадим отдельную директорию, в которой будет размещаться репозиторий:
После чего перейдем в нее:
Теперь можно инициализировать репозиторий:
В консольном терминале должно вывестись стандартное информационное сообщение:
А в текущей директории появится скрытый каталог .git, который можно увидеть с помощью соответствующей команды:
Флаг -a означает all и позволяет просматривать файловую систему в расширенном режиме. Ее содержимое будет таким:
Перед тем, как начать делать коммиты, необходимо указать базовые сведения о пользователе.
Сперва имя:
А потом и почту:
Наполнение ветки master
С помощью простых текстовых файлов мы будем имитировать добавление различных функций в проект. Каждая новая функция будет оформляться в отдельный коммит.
Создадим файл импровизированной функции:
И наполним его содержимом:
Теперь проиндексируем изменения, сделанные в репозитории:
На всякий случай можно проверить статус индексации:
В консольном терминале должно появится сообщение со списком проиндексированных изменений:
Теперь можно выполнить коммит:
После этого в консольном терминале выведется сообщение об успешном внесении изменений в ветку master:
Наполнение ветки hypothesis
Теперь необходимо создать новую ветку hypothesis:
Флаг -b необходим, чтобы сразу переключиться на созданную ветку.
В консольном терминале появится сообщение об успешном переключении на новую ветку:
Теперь необходимо последовательно выполнить три коммита с тремя файлами по аналогии с веткой master:
-
commit_2с файломfunction_2и содержимымФункция 2 -
commit_3с файломfunction_3и содержимымФункция 3 -
commit_4с файломfunction_4и содержимымФункция 4
Если после этого просмотреть список всех коммитов:
То в консольном терминале появится такая последовательность:
В этой команде флаг --oneline необходим для вывода информации о коммитах в сжатом формате одной строки.
Последнее, что нужно сделать, — добавить еще один коммит в основную ветку master. Переключимся на нее:
В консольном терминале должно появится соответствующее сообщение:
После этого создадим еще один файл импровизированной функции:
Содержимое будет следующим:
Теперь можно проиндексировать изменения:
И выполнить очередной коммит:
Если проверить текущий список коммитов:
То в ветке master их будет всего два:
Объединение веток с git rebase
Для выполнения перебазирования сперва необходимо перейти в ветку hypothesis:
И выполнить ребазирование:
После этого в консольном терминале появится сообщение об успешном ребазировании:
Теперь можно проверить список коммитов:
В консольном терминале появится список, содержащий коммиты обоих веток в оригинальном порядке:
Теперь ветка hypothesis содержит общую историю всего репозитория.
Разрешение конфликтов
Как и в случае с git merge, при использовании команды git rebase могут возникать конфликты, требующие ручного разрешения.
Давайте модифицируем наш репозиторий таким образом, чтобы искусственно создать конфликт ребазирования.
Создадим в ветке hypothesis еще один файл:
И запишем в него следующий текст:
Проиндексируем изменения:
И выполним очередной коммит:
Теперь переключимся на ветку master:
Создадим аналогичный файл:
И наполним его следующим содержимым:
Аналогично, выполняем индексацию:
И делаем коммит:
Заново откроем созданный файл:
И изменим его содержимое на следующий текст:
Опять проиндексируется:
И снова сделаем коммит:
Теперь можно обратно переключиться на ветку hypothesis:
А далее выполнить еще одно ребазирование:
В консольном терминале появится сообщение о конфликте:
Git предлагает отредактировать файл conflict, проиндексировать изменения с помощью команды git add, после чего продолжить ребазирование, указав флаг --continue.
Именно так мы и поступим:
Файл будет содержать две конфликтующие версии файла, обрамленные специальными символами:
Наша задача убрать всё лишнее, наполнив файл итоговым вариантом произвольного текста:
Теперь индексируем изменения:
И продолжаем процесс ребазирования:
После этого в консольном терминале откроется текстовый редактор, предлагающий изменение оригинальное название того коммита, в котором возник конфликт:
В консольном терминале появится сообщение об успешном завершении процесса ребазирования:
Теперь если проверить список коммитов в ветке hypothesis:
Можно увидеть оригинальную последовательность всех сделанных изменений:
Обратите внимание, что коммиты conflict_2 и conflict_3, сделанные в ветке master, располагаются в истории изменений раньше, чем коммит conflict_1. Впрочем, это касается любых коммитов, сделанных в ветке master.
Ребазирование удаленного репозитория
Помимо работы с локальными ветками, ребазирование можно выполнить в момент подтягивания изменений из удаленного репозитория. Для этого к стандартной команде pull необходимо добавить флаг --rebase:
Здесь:
-
remote. Удаленный репозиторий. -
branch. Удаленная ветка.
По сути, такая конфигурация команды pull является эквивалентом git rebase за исключением того, что применяемые к текущей ветки изменения (коммиты) берутся из удаленного репозитория.
Преимущества git rebase
- Линейность
Команда git rebase позволяет сформировать достаточно линейную историю целевой ветки, представляющую собой последовательно сделанные коммиты.
Такая последовательность и отсутствие ветвления делает историю проще для восприятия и понимания.
- Снижение количества конфликтов
Предварительно выполненная команда git rebase может существенно снизить вероятность возникновения конфликтов при объединении веток с помощью git merge.
Конфликты проще разрешать в последовательно идущих коммитах, нежели в коммитах, сливающихся в один единый коммит слияния. Это особенно актуально при отправке веток в удаленные репозитории.
Недостатки git rebase
- Изменение истории
В отличие от слияния, ребазирование частично переписывает историю целевой ветки. При этом лишние элементы истории удаляются.
- Вероятность ошибок
Свойство существенно перестраивать историю коммитов может приводить к необратимым ошибкам внутри репозитория. А это значит, что некоторые данные могут быть безвозвратно утеряны.
Надежные VDS для ваших проектов
477 ₽/мес
657 ₽/мес
Заключение
Объединение двух веток методом ребазирования, который реализуется командой git rebase, существенно отличается от классического слияния, выполняемого командой git merge.
-
git mergeпревращает коммиты одной ветки ветки в один коммит другой.
-
git rebaseперемещает коммиты из одной ветки в конец другой, сохраняя оригинальный порядок.
При этом аналогичного поведения ребазирования можно добиться во время использования команды git pull, используя дополнительный флаг --rebase.
С одной стороны, команда git rebase позволяет добиться более чистой и наглядной истории коммитов в основной ветке, что увеличивает простоту поддержки репозитория. С другой стороны, команды git rebase снижает уровень детализации изменений внутри ветки, упрощая историю и удаляя некоторые ее записи.
По этой причине ребазирование — функция для более опытных пользователей, которые понимают механизм работы Git.
Чаще всего команда git rebase используется в связке с командой git merge, позволяя получить наиболее оптимальную структуру репозитория и веток внутри него.
