linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
Intro
Lessons
Footer
linuxlab-УчебникиЦеныО платформеКонфиденциальность и куки
Copyright © 2026 LinuxLab. Все права защищены.
linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
  • Введение
  • Главы
  • How it works
  • Уроки
  • База знаний
  • Собеседование
home/git/how/fast-forward-vs-merge

how/история

Fast-forward vs merge-коммит

«Слил ветку» - но как? Без merge-коммита или с ним? Что значит «branches diverged» и зачем существует --no-ff. На графе коммитов всё видно за секунду.

git merge feat может закончиться двумя совершенно разными способами, и от того, какой случится, зависит, как потом выглядит история.

  • Fast-forward (ff) - указатель ветки просто двигается вперёд. Новых коммитов не создаётся. Возможен, когда ветки не разошлись: в целевой ветке нет коммитов после ветвления.
  • Merge-коммит - создаётся отдельный коммит с двумя родителями. Возможен всегда, но обязателен только когда ветки разошлись.

Жми ▶ - посмотрим на пять сценариев. Тот же git merge feat ведёт себя по-разному в зависимости от того, что было на main.

step 1/5·00 · feat ушёл вперёд, main отстал
MAINFEATABCmain →feat →main отстал от feat: B и C сидят на feat, у main только A

§ шаги

  1. Начальное состояние:

    main:  A
                ↘
    feat:  A → B → C

    На main только коммит A. На feat - A → B → C. Главное: на main после ветвления нет новых коммитов. Это значит, что верхушка main (A) - предок верхушки feat (C).

    В Git'е это и есть условие для fast-forward: целевая ветка отстаёт по прямой линии от исходной.

итого

Что важно запомнить:

  • FF - это переписывание refs/heads/main на SHA верхушки feat. Новых коммитов не появляется, история остаётся линейной, факт ветвления пропадает.
  • Merge-коммит обязателен, когда ветки разошлись (на обеих есть коммиты после ветвления). У него два parent'а - в этом и есть отличие от обычного коммита.
  • git merge --no-ff feat принуждает создать merge-коммит, даже когда FF возможен. Полезно, если важно видеть в логе «здесь была ветка feat». На GitHub-flow PR'ы мерджатся именно так.
  • git merge --ff-only feat - наоборот: «если FF не получается, не делай ничего». Защита от случайных merge-коммитов в git pull-ах (см. pull.ff = only).
  • git rebase feat onto main - третий путь: перенести коммиты feat поверх main так, чтобы FF снова стал возможен. История остаётся линейной, но SHA коммитов меняются (тот же diff, новый родитель = новый хеш). Поэтому ребейзить можно только то, что ещё никто не утянул.

Что выбирать на практике:

  • PR-ветки → --no-ff (стандарт PR-форджей).
  • Локальная синхронизация с main → rebase (либо git pull --rebase).
  • Прямые быстрые merge'ы (например, личной feature → личной integration) → ff вполне ок, история чище.

§ копнуть в базу знаний

  • mergemerge - три способа объединить ветки
  • fast-forwardfast-forward - как Git «перематывает» ветку
  • branchbranch - указатель на коммит
  • rebaserebase - переписать историю чужими родителями
  • merge-strategiesmerge-strategies - что выбирают на форджах
Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки