Git merge vs rebase: отличия, примеры и когда что использовать

  1. Главная
  2. Блог
  3. Разработка ПО
Разработка ПО

Git merge vs rebase: отличия, примеры и когда что использовать

Выбор между Git merge и rebase определяет, как выглядит история проекта. Сравните оба варианта на одном примере с реальным выводом log, узнайте правило, которое предотвращает беды, и скопируйте безопасный рабочий процесс для команды.

7 мин чтения
Git merge vs rebase: отличия, примеры и когда что использовать
Главное
  • Merge соединяет две ветки новым коммитом слияния и сохраняет историю такой, какой она была.
  • Rebase воспроизводит ваши коммиты поверх другой ветки, давая прямую линию, но новые хеши.
  • Никогда не делайте rebase коммитов, которые другие уже забрали.
  • Делайте rebase своей ветки функциональности перед pull request, а при переносе в основную ветку используйте merge.

Ваша ветка функциональности отстаёт от main, а новая работа вам нужна. Git merge vs rebase — это выбор между двумя способами её получить, и оба верны. Они различаются тем, как выглядит история после.

Мы создали крошечный репозиторий, выполнили обе команды и вставили реальный вывод ниже, чтобы вы сравнивали результат, а не воображали его. Только знакомитесь с Git? Начните с нашего учебника по Git для начинающих (на английском).

Что делают git merge и git rebase

git merge берёт вершины двух веток и объединяет их. Если в обеих есть новые коммиты, Git создаёт коммит слияния с двумя родителями. Ничто из существующего не меняется.

git rebase берёт коммиты, которые есть только в вашей ветке, откладывает их, переносит вашу ветку на вершину другой и затем воспроизводит ваши коммиты один за другим. Воспроизведённые коммиты — это новые коммиты с новыми хешами, хотя изменения в них те же.

Git merge на практике

Наша отправная точка: коммит A в main, два коммита (F1, F2) в feature и ещё один коммит (M1), добавленный затем в main. Теперь сливаем main в feature.

git switch feature
git merge main
git log --oneline --graph

*   f507aab Merge main into feature
|\
| * 8842fb5 M1
* | 082cc6a F2
* | 5a71e3c F1
|/
* 8766865 A

Граф показывает настоящую историю: две линии работы, которые соединили. Исходные коммиты F1 и F2 сохраняют свои хеши. Цена — лишний коммит слияния, а в оживлённом проекте граф превращается в паутину.

Git rebase на практике

Та же отправная точка, но теперь мы делаем rebase feature на main.

git switch feature
git rebase main
git log --oneline --graph

* 1ff474b F2
* bf9149e F1
* 8842fb5 M1
* 8766865 A

История — одна прямая линия, будто вы начали работу после M1. Посмотрите на хеши: F1 был 5a71e3c, а стал bf9149e; F2 изменился с 082cc6a на 1ff474b. Git переписал их, поэтому rebase требует осторожности.

Merge и rebase рядом

АспектMergeRebase
Форма историиВетвящийся граф с коммитами слиянияОдна прямая линия
Существующие коммитыНе меняютсяПереписываются с новыми хешами
КонфликтыРазрешаются один раз, в коммите слиянияМогут понадобиться для каждого воспроизводимого коммита
Безопасно в общих веткахДаНет
Лучше всего дляПереноса готовой работы в mainОбновления своей ветки перед ревью

Совет: если не можете решить, спросите, у кого ещё есть ваша ветка. Если ни у кого — rebase безопасен. Если коллега её забрал — используйте merge.

Золотое правило rebase

Не делайте rebase коммитов, которые существуют за пределами вашего репозитория. После rebase ваша ветка больше не совпадает с копией на сервере, поэтому для отправки нужен принудительный push. Если коллега построил работу на старых коммитах, его история теперь расходится с вашей, и разбираться с этим мучительно.

Делать rebase своей приватной ветки функциональности нормально. Делать его для main или любой ветки, которой пользуются другие, — нет.

Безопасный рабочий процесс для команды

Эта процедура сохраняет историю чистой и никого не удивляет. Так же поступает большинство команд перед CI-конвейером, например таким, как в нашем руководстве по GitHub Actions CI/CD (на английском).

git switch feature
git fetch origin
git rebase origin/main        # or: git pull --rebase
# fix conflicts, then: git add <file> && git rebase --continue
git push --force-with-lease   # only on your own branch

--force-with-lease отказывается перезаписывать ветку на сервере, если с вашего последнего fetch туда кто-то отправил изменения, — обычный --force молча уничтожил бы их. Когда pull request одобрен, слейте его в main.

Как отменить неудачный rebase

Rebase выглядит разрушительным, но старые коммиты некоторое время остаются в reflog Git, так что можно вернуться.

git reflog                    # find the commit before the rebase
git reset --hard HEAD@{5}     # example position, check reflog first

Создайте резервную ветку командой git branch backup перед любым рискованным rebase, и восстановление сведётся к одной команде. Запускаете базу данных или инструменты в контейнерах? Загляните в наш учебник по Docker для начинающих (на английском).

Итоги

Merge хранит правду, rebase держит её в порядке. Используйте rebase, чтобы обновить свою ветку, merge — чтобы доставить её, и никогда не переписывайте историю, от которой зависят другие.

Часто задаваемые вопросы

В чём разница между git merge и git rebase?

Merge объединяет две ветки коммитом слияния и сохраняет все существующие коммиты. Rebase переносит ваши коммиты поверх другой ветки и переписывает их, давая линейную историю.

Что использовать: merge или rebase?

Делайте rebase своей ветки функциональности, чтобы быть в курсе изменений, и merge — при её доставке в общую ветку вроде main. Используйте merge всегда, когда ветку делят с другими.

Опасен ли git rebase?

В приватных ветках он безопасен, в общих рискован, потому что переписывает хеши коммитов. Используйте резервную ветку и reflog, чтобы восстановиться при проблемах.

Что делает force-with-lease?

Он выполняет принудительный push, только если удалённая ветка всё ещё там, где вы видели её в последний раз, поэтому вы не перезапишете случайно новые коммиты коллеги.

Удаляет ли rebase мои коммиты?

Нет. Он создаёт новые коммиты с теми же изменениями, а старые остаются в reflog, пока Git их не очистит.

Продолжайте изучать (статьи на английском)

Работайте со Stack Quora

Нужна помощь с тестированием, WordPress или SEO?

Мы помогаем командам выпускать более качественное ПО и развивать сайты. Расскажите, над чем вы работаете, и мы предложим понятный следующий шаг.

Продолжайте читать

Больше руководств по тестирование, искусственный интеллект и современные разработки

Понравилась эта статья? Выберите тему и сразу приступайте к нашим новейшим руководствам.

Искусственный интеллект

Объяснение галлюцинаций искусственного интеллекта: почему языковые модели все выдумывают и как их уменьшить

Галлюцинации ИИ объяснили: что это такое, почему языковые модели их создают, распространенные типы, как уменьшить их с помощью заземления и подсказо…

Читать статью →
DevOps

Объяснение переменных среды: файлы .env, секреты и правильно выполненная конфигурация

Переменные среды объясняются на примерах Python, которые мы запускали: их чтение и установка, почему каждое значение является строкой, файлы .env, н…

Читать статью →
Разработка ПО

Объяснение ограничения скорости API: алгоритмы, заголовки и обработка ошибок 429

Ограничение скорости API объясняется с помощью проведенного нами моделирования: сегмент токенов, фиксированное окно, скользящее окно, 429 ответов, з…

Читать статью →
Автоматизация тестирования

Издевательство в Python: unittest.mock, патч и ошибки, из-за которых тесты лгут

Издевательство на Python с помощью unittest.mock, протестировано: Mock и return_value, Side_effect, исправление использования имени, спецификация и …

Читать статью →
Тестирование ПО

Объяснение покрытия кода: покрытие линий или ветвей и что на самом деле означает 100%

Покрытие кода объяснено с помощью реального запуска покрытия.py: покрытие строк, ветвей и условий, чтение отчета, почему 100%-ное покрытие все еще м…

Читать статью →
Базы данных и SQL

DELETE, TRUNCATE и DROP в SQL: различия, откат и когда использовать каждый из них

Объяснение DELETE, TRUNCATE и DROP на примере протестированного SQL: что каждый из них удаляет, откат, триггеры, сброс идентификаторов, скорость и ч…

Читать статью →
Базы данных и SQL

Объяснение представлений SQL: создавайте, используйте и избегайте ловушек, с примерами

Представления SQL, объясненные с помощью запросов, которые мы выполняли: создание представления, результаты в реальном времени, скрытие столбцов, пр…

Читать статью →
Разработка ПО

Интерфейс TypeScript и тип: реальные различия, протестированные с помощью компилятора

Интерфейс TypeScript против типа, проверенный реальным компилятором: что могут делать оба, что может делать только один, слияние объявлений, расшире…

Читать статью →
Разработка ПО

Объяснение Python *args и **kwargs: гибкие функции с понятными примерами

Python *args и **kwargs, объясненные с помощью кода, который мы запускали: упаковка и распаковка, порядок параметров, аргументы только по ключевым с…

Читать статью →
Разработка ПО

Лямбда-функции Python: синтаксис, реальное использование и когда их не следует использовать

Лямбда-функции Python, объясненные с помощью кода, который мы запускали: синтаксис, сортировка с помощью ключа, карты и фильтра, замыкания, ловушка …

Читать статью →
Искусственный интеллект

Что такое ИИ-агенты? Как они работают: можно запустить простой цикл агента

Что такое агенты ИИ? Простое руководство по циклу агента, инструментам, памяти и ограничениям, с небольшим циклом Python, который мы запустили, реал…

Читать статью →
DevOps

Мониторинг и наблюдаемость: реальная разница с журналами, метриками и трассировками

Объяснение мониторинга и наблюдаемости: известные и неизвестные сбои, журналы, метрики и трассировки, пошаговое руководство по инцидентам при оформл…

Читать статью →
DevOps

Docker Volumes против Bind Mounts: правильное сохранение данных контейнера

Объяснение томов Docker и монтирования привязки: почему исчезают данные контейнера, именованные тома, монтирование привязки, tmpfs, примеры создания…

Читать статью →
Автоматизация тестирования

TDD против BDD: ключевые различия, одна функция, созданная для обоих способов, и когда использовать каждый

TDD и BDD объясняются с помощью одной функции скидки, созданной в обоих направлениях: красно-зеленый рефакторинг с кодом, который мы запускали, сцен…

Читать статью →
Разработка ПО

Git merge vs rebase: отличия, примеры и когда что использовать

Git merge vs rebase с реальным выводом log, сравнительной таблицей, золотым правилом rebase и безопасным рабочим процессом для команды.

Читать статью →
Разработка ПО

Генераторы списков в Python: синтаксис, примеры и когда их избегать

Генераторы списков в Python: синтаксис, фильтры, if-else, вложенные циклы, измеренное время и случаи, когда обычный цикл for лучше.

Читать статью →
Базы данных и SQL

SQL JOIN: объяснение с примерами (Inner, Left, Right, Full)

Разберите SQL JOIN шаг за шагом на примерах таблиц и запросов: INNER, LEFT, RIGHT, FULL, CROSS и SELF, а также частые ошибки и советы по производите…

Читать статью →