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

«В чем разница между командами git merge и git rebase?» — вопрос из категории DevOps, который задают на 31% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Обе команды интегрируют изменения из одной ветки в другую, но делают это принципиально разными способами, влияя на историю коммитов.

git merge

  • Действие: Создает новый коммит слияния (merge commit), который имеет двух родителей. Этот коммит объединяет историю двух веток.
  • История: Сохраняет нелинейную, полную историю разработки (видно ветвление и слияние).
  • Безопасность: Не переписывает существующую историю, поэтому безопасна для публичных веток.
# Стандартное слияние feature в main
git checkout main      # Переключиться на принимающую ветку
git merge feature      # Объединить изменения из ветки feature

git rebase

  • Действие: Перемещает (перебазирует) всю цепочку коммитов текущей ветки и «применяет» их поверх указанной ветки. Фактически переписывает историю, создавая новые коммиты с новыми хэшами.
  • История: Делает историю линейной, как если бы работа велась последовательно в одной ветке. Убирает видимость параллельной разработки.
  • Риск: Переписывает историю, что опасно для коммитов, уже отправленных в общий репозиторий (публичные ветки).
# Перебазирование feature на актуальный main
git checkout feature   # Переключиться на ветку, которую перебазируем
git rebase main        # «Перемотать» коммиты feature поверх main

Сравнение на диаграмме

До операции (ветка feature ответвилась от main):

A---B---C (main)
         
          D---E (feature)

После git merge:

A---B---C---F (main)
            /
          D---E (feature)

Коммит F — это merge-коммит, объединяющий C и E.

После git rebase (и последующего fast-forward merge):

A---B---C---D'---E' (main)

Коммиты D' и E' — это новые коммиты с тем же содержанием, что D и E, но примененные поверх C.

Когда что использовать?

  • Используйте merge:
    • Для слияния публичных веток (например, feature в main).
    • Когда важно сохранить полный контекст и историю слияний.
  • Используйте rebase:
    • Локально, чтобы поддерживать чистую линейную историю перед слиянием в основную ветку.
    • Для обновления своей feature-ветки актуальными изменениями из main (git rebase main).
    • Никогда не делайте rebase коммитов, которые уже были отправлены в общий репозиторий.