📖 Теория — Merge и rebase

К оглавлению урока

⚡ Кратко: merge и rebase

  • git merge — создаёт коммит слияния, сохраняет историю обеих веток.
  • git rebase — переписывает коммиты поверх целевой ветки, история становится линейной.
  • Золотое правило: никогда не делать rebase на публичных ветках.
  • git commit --amend — исправить последний коммит без нового коммита.
  • git reset --soft/--mixed/--hard — откатить HEAD; --hard безвозвратно!
  • git revert — безопасная отмена: создаёт новый коммит, историю не меняет.

1. Что такое git merge

Git merge — это операция в системе контроля версий Git, которая объединяет изменения из одной ветки с другой. Когда вы выполняете слияние веток, Git автоматически объединяет изменения, сделанные в одной ветке, с изменениями из другой ветки.

Git merge используется для объединения «целевой» ветки с «исходной» веткой. Git анализирует изменения, сделанные в каждой из этих веток, и пытается автоматически объединить их.

Как объединить main и feature branch

Самым простым вариантом является:

# Переключиться на feature и влить туда main
git checkout feature
git merge main

Или в одну строку:

git merge feature main
Коммит слияния: При выполнении git merge создаётся дополнительный коммит слияния (merge commit), который объединяет изменения из двух веток. Этот коммит сохраняет историю обеих веток.

2. Что такое git rebase

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

При выполнении git rebase Git берёт коммиты из вашей текущей ветки и применяет их поверх коммитов другой ветки (чаще всего это ветка, от которой вы решили отойти с помощью ребейза). Это позволяет поддерживать более линейную историю коммитов без лишних слияний.

Перебазирование feature branch в main branch

git checkout feature
git rebase main

Отличия git rebase и git merge

Критерий git merge git rebase
История коммитов Создаёт дополнительный коммит слияния; сохраняет историю обеих веток Переписывает историю; создаются новые коммиты с теми же изменениями поверх целевой ветки
Чистота истории Могут накапливаться «мусорные» коммиты слияния История становится более чистой и линейной
Конфликты Разрешаются один раз при слиянии Могут потребоваться при каждом переносимом коммите
Безопасность Более безопасен; не изменяет историю коммитов Опасен при работе с общедоступными ветками — изменяет историю коммитов

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

Мы разобрались, что такое перебазирование. Теперь главное — понять, когда его делать не нужно.

Золотое правило перебазирования: rebase никогда не следует применять к публичным (общедоступным) веткам.

Rebase перемещает все коммиты из основной ветки в feature-ветку. Проблема заключается в том, что это происходит только в вашем репозитории. Все остальные разработчики всё ещё работают с исходной основной веткой. Поскольку перебазирование приводит к созданию совершенно новых коммитов, Git будет считать, что история вашей основной ветки расходится с историей всех остальных.

Единственный способ синхронизировать две основные ветки — это снова слить их вместе, что приведёт к дополнительному коммиту слияния и двум наборам коммитов, содержащих одни и те же изменения.

Правило проверки: Прежде чем запустить git rebase, всегда задайте себе вопрос: «Кто-нибудь ещё работает с этой веткой?» Если ответ утвердительный — не делайте этого!

Что если всё-таки нужно запушить перебазированную ветку?

Если вы попытаетесь отправить перебазированную основную ветку обратно в удалённый репозиторий, Git не позволит вам это сделать. Однако вы можете принудительно выполнить отправку с помощью --force:

git push --force
⚠️ ОПАСНО: git push --force
git push --force перезаписывает историю удалённого репозитория. Другие разработчики не смогут корректно синхронизироваться — их локальные копии «сломаются» и им придётся ручную пересинхронизировать работу.

Никогда не использовать git push --force на main/master в командной работе. Если вам нужно обновить публичную историю, используйте git revert для создания нового коммита, отменяющего изменения.

4. Git commit --amend

Git commit --amend — это команда, которая используется для изменения последнего коммита в репозитории и позволяет внести изменения в последний коммит без создания нового коммита.

Команда очень удобна для исправления небольших ошибок или добавления упущенных изменений в последний коммит.

Как работает

  • После выполнения этой команды откроется редактор сообщения коммита, где вы можете внести изменения в сообщение коммита.
  • Вы можете добавить новые файлы в индекс перед выполнением git commit --amend, и они будут включены в исправленный коммит.
# Изменить только сообщение последнего коммита
git commit --amend -m "Новое сообщение коммита"

# Добавить пропущенный файл к последнему коммиту
git add forgotten-file.txt
git commit --amend --no-edit
Важно: изменения, внесённые с помощью git commit --amend, изменят историю коммитов в вашем локальном репозитории. Поэтому, если вы уже поделились этим коммитом с другими разработчиками, будьте осторожны — это может создать проблемы с совместной работой.

5. Git reset

Git reset используется для изменения состояния вашего репозитория. Эта команда изменяет указатель HEAD и/или перемещает текущую ветку на определённый коммит.

Основные опции git reset

Опция Что происходит Рабочий каталог Индекс (staging)
--soft Сбрасывает HEAD на указанный коммит Сохраняется Сохраняется
--mixed (по умолчанию) Сбрасывает HEAD и сбрасывает индекс Сохраняется Сбрасывается
--hard Сбрасывает HEAD, индекс и рабочий каталог УДАЛЯЕТСЯ Сбрасывается
# Отменить последний коммит, сохранив изменения в staging
git reset --soft HEAD~1

# Отменить последний коммит, сохранив изменения в рабочем каталоге
git reset --mixed HEAD~1

# Полностью откатить к предыдущему коммиту (ОСТОРОЖНО!)
git reset --hard HEAD~1
⚠️ ОПАСНО: git reset --hard
git reset --hard HEAD~1 безвозвратно удаляет ВСЕ незакоммиченные изменения в рабочем каталоге и сбрасывает индекс. Восстановить эти данные без резервных копий невозможно.

Безопасные альтернативы:
— Используйте git reset --soft HEAD~1, чтобы сохранить изменения в рабочем каталоге.
— На публичных ветках используйте git revert — он создаёт новый коммит и не меняет историю.
— Перед reset --hard спрячьте изменения через git stash, если хотите их сохранить.

6. Git checkout

Git checkout используется для переключения между ветками и восстановления файлов из репозитория.

Основные использования git checkout

  • Переключение между существующими ветками с использованием их имён.
  • Создание новых веток на основе существующих веток или коммитов.
  • Восстановление файлов из определённого коммита, а не из последней версии ветки.
# Переключиться на ветку main
git checkout main

# Создать и переключиться на новую ветку
git checkout -b feature

# Восстановить файл из репозитория (отменить незакоммиченные изменения)
git checkout -- filename.txt

# Переключиться на определённый коммит (осторожно: Detached HEAD!)
git checkout abc1234
🔬 Современный способ (git 2.23+): Команда git checkout была разделена на две более специализированные команды:
git switch feature — для переключения веток (замена git checkout feature)
git restore filename.txt — для восстановления файлов (замена git checkout -- filename.txt)
⚠️ Проверить по документации — доступно начиная с Git 2.23.

7. Git revert

Git revert используется для отмены изменений, внесённых определённым коммитом, путём создания нового коммита, который отменяет изменения этого коммита.

Git revert безопасен для использования в общедоступных ветках, так как он не изменяет историю коммитов, а создаёт новые коммиты, отменяющие изменения.

# Отменить последний коммит (создаст новый коммит-откат)
git revert HEAD

# Отменить конкретный коммит по хэшу
git revert abc1234

# Отменить несколько коммитов (не создавая коммит сразу — --no-commit)
git revert --no-commit HEAD~3..HEAD

Отличия revert от reset

git revert git reset
Создаёт новый коммит, отменяющий изменения Изменяет состояние репозитория путём перемещения HEAD
Безопасен на общедоступных ветках; история не меняется Опасен на публичных ветках; изменяет историю коммитов
Уведомляет других разработчиков об отмене через новый коммит Не создаёт новых коммитов; при --hard данные теряются
Правило выбора: если вы работаете на общедоступной (публичной) ветке — всегда используйте git revert. Если на личной локальной ветке — можно использовать git reset, но с осторожностью.