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

Ответ

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

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 коммитов, которые уже были отправлены в общий репозиторий.

Ответ 18+ 🔞

А, слушай, история коммитов — это ж как семейное древо, только вместо бабушек и дедушек тут твои кривые правки в коде. И есть два способа скрестить ветки: мердж и ребейз. Разница — как между "давай жить дружно" и "я тут всё перепишу, чтоб красиво было".

git merge — классика, как борщ с пампушками

  • Что делает: Создаёт новый, ёбаный, коммит слияния. У этого коммита два родителя, он как мостик между двумя историями.
  • История: Всё остаётся, как было. Видно, где ветка отпочковалась, где слилась. Полная картина, хоть и похожая на паутину алкоголика.
  • Безопасность: Ничего не переписывает, историю не трогает. Идеально для веток, куда уже кто-то успел посмотреть.
# Делаем по-честному
git checkout main      # Переходим на главную ветку
git merge feature      # Вливаем фичу со всеми её костылями

git rebase — перфекционист с манией величия

  • Что делает: Берёт твою ветку и хуяк — пересаживает её на самый свежий кончик другой ветки. Коммиты физически пересоздаются, у них новые ID. История переписывается, будто ты с самого начала работал на свежей основе.
  • История: Получается ровная, линейная полоса, красивая, как стрелка на брюках. Все параллельные разработки стираются из виду.
  • Риск: ОПАСНОСТЬ, ПИЗДЕЦ! Если переписал историю, которую уже кто-то забрал к себе — всем придётся страдать. Только для локального гимнастического упражнения.
# Делаем красиво, но только локально!
git checkout feature   # Садимся на свою фичу
git rebase main        # Аккуратно примастыриваем её коммиты поверх свежего main

Как это выглядит, если нарисовать палкой на песке

Было так (ветка feature уехала в запой от main):

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

Стало после git merge (всех помирили):

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

Коммит F — тот самый merge-коммит, дипломат и миротворец.

Стало после git rebase (идеальная, но поддельная история):

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

Коммиты D' и E' — это те же D и E, но уже с новыми паспортами, притворяющиеся, что они всегда шли за C.

Так когда же что юзать, чтобы не вышло конфуза?

  • Жми merge без колебаний, если:

    • Сливаешь фичу в общую ветку (типа main).
    • Хочешь, чтобы в истории остался след, что тут было слияние, а не магия.
    • Не хочешь, чтобы тебя убили коллеги.
  • Юзай rebase осторожно, как сапер, если:

    • Только локально хочешь причесать свою ветку перед слиянием.
    • Нужно обновить свою старую фичу свежими изменениями из main (перед мерджем).
    • ЗАПОМНИ, КАК "ОТЧЕ НАШ": Никогда не ребейзь то, что уже ушло в общий репозиторий. Иначе будет ебаный шторм, и виноват будешь ты.