Чтобы объединить ветки в Git, переключитесь на ветку, в которую нужно забрать изменения, и выполните git merge с именем второй ветки: git switch main, затем git merge feature/cart. Если в main за это время никто ничего не добавлял, Git просто передвинет указатель вперёд. Если добавлял, Git создаст коммит слияния с двумя родителями.
Ниже разберём, как выглядит каждый вариант в терминале, когда вместо merge лучше взять squash или rebase, как решить конфликт и как откатить слияние, если что-то пошло не так. Если ветки и коммиты для вас пока новые слова, начните с объяснения Git простыми словами, а сюда возвращайтесь с первым конфликтом. Те же команды пригодятся, если ветки за вас создаёт ИИ-агент: как работает Claude Code, мы разбирали отдельно.
Как объединить ветки в Git: пошаговая инструкция

Возьмём типичную ситуацию: вы сделали корзину в ветке feature/cart и хотите перенести её в основную ветку main. Весь путь занимает пять команд.
- Сохраните работу. Закоммитьте или уберите в stash всё, что лежит в рабочей папке. Справка git merge не советует запускать слияние с заметными незакоммиченными правками: при конфликте из такого состояния трудно выбраться.
- Перейдите в принимающую ветку:
git switch main. В старых версиях Git и во многих инструкциях то же самое делаетgit checkout main. - Обновите её с сервера:
git pull. Иначе вы сольёте фичу в устаревшую main, а при пуше получите отказ. - Слейте ветку:
git merge feature/cart. - Отправьте результат:
git push. Ветку фичи после этого можно удалить командойgit branch -d feature/cart.
Так выглядит слияние, когда main с момента ответвления не менялась:
$ git switch main
Switched to branch 'main'
$ git merge feature/cart
Updating a790c37..c7973cd
Fast-forward
cart.py | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 cart.py
Слово Fast-forward в выводе означает, что нового коммита Git не создавал. Чем это отличается от настоящего слияния, разберём в следующем разделе.
Направление слияния задаёт ветка, на которой вы стоите. Команда
git merge Xвсегда забирает X в текущую ветку. Перед слиянием проверьтеgit branch: звёздочка стоит у текущей.
Fast-forward и коммит слияния: что сделает Git
У git merge два режима, и какой сработает, решает форма истории. По описанию флага --ff в той же справке, если вливаемая история продолжает текущую, Git по умолчанию только передвигает указатель ветки. Если ветки разошлись, он создаёт коммит слияния.
Перемотка вперёд
Fast-forward случается, когда в main после ответвления фичи не было новых коммитов. Ветке main достаточно «догнать» feature/cart, история остаётся прямой линией:
$ git log --oneline --graph
* c7973cd Добавить корзину
* a790c37 Первый коммит
Трёхстороннее слияние
Теперь другой случай. Пока вы делали каталог в feature/catalog, в main успели закоммитить описание доставки. Ветки разошлись, и перемотать указатель уже нельзя. Git берёт общего предка и две вершины, сводит изменения и записывает результат в новый коммит. В книге Pro Git на русском этот приём называют трёхсторонним слиянием.
$ git merge feature/catalog
Merge made by the 'ort' strategy.
catalog.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 catalog.txt
$ git log --oneline --graph
* 86792f3 Merge branch 'feature/catalog'
|\
| * 8d095e7 Добавить каталог
* | e4948d1 Описать доставку
|/
* c7973cd Добавить корзину
* a790c37 Первый коммит
Перед записью коммита Git откроет редактор с сообщением Merge branch 'feature/catalog'. Можно оставить его как есть и закрыть редактор. Если открылся Vim, выход с сохранением набирается так: Esc, затем :wq и Enter.
Строка 'ort' в выводе называет алгоритм. В описании стратегий слияния сказано, что ort выбирается по умолчанию, когда вы сливаете одну ветку или делаете pull. Менять его в обычной работе не нужно.
Флаги —no-ff и —ff-only
Поведение по умолчанию можно переключить двумя флагами. Оба пригодятся, когда в команде договорились о форме истории. Такие правила обычно задаёт тимлид и записывает в регламент репозитория.
| Команда | Что делает | Когда пригодится |
|---|---|---|
git merge feature/b |
Перематывает, если можно, иначе создаёт коммит слияния | Обычная работа |
git merge --no-ff feature/b |
Создаёт коммит слияния всегда, даже когда хватило бы перемотки | Нужно видеть в истории, какие коммиты пришли одной фичей |
git merge --ff-only feature/b |
Только перемотка, иначе отказ с ненулевым кодом выхода | История должна оставаться прямой линией |
Вот как --ff-only отказывается сливать разошедшиеся ветки. Ничего не меняется, рабочая папка остаётся как была:
$ git merge --ff-only feature/a
fatal: Not possible to fast-forward, aborting.
А так --no-ff оставляет «петлю» даже там, где история могла бы быть прямой:
$ git merge --no-ff feature/b
Merge made by the 'ort' strategy.
b.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 b.txt
$ git log --oneline --graph -3
* f4d2b82 Merge branch 'feature/b'
|\
| * 21d023e Фича B
|/
* 86792f3 Merge branch 'feature/catalog'
|\
Канал основателя Checkroi Вани Буявца3 800 человек читают мой Телеграм-канал про нейросетиСобрал промпты для Claude Code и ChatGPT, разборы ИИ-инструментов и лайфхаки по продвижению бизнеса в одном местеПрисоединитьсяДругие способы объединить ветки: squash и rebase

Merge сохраняет все коммиты фичи как есть. Иногда это лишнее: в ветке десять коммитов вида «поправил опечатку», и в main они не нужны. Для таких случаев есть ещё два способа. Их же отрабатывают в онлайн-курсах по Git на учебных репозиториях с проверкой заданий.
| Способ | Команда | Что будет в истории main |
|---|---|---|
| Слияние | git merge feature |
Все коммиты фичи плюс коммит слияния (или перемотка) |
| Сжатие | git merge --squash feature, затем git commit |
Один новый коммит со всеми изменениями фичи |
| Перебазирование | git rebase main в ветке фичи, затем merge |
Коммиты фичи по одному, прямой линией, без коммита слияния |
| Перенос отдельных коммитов | git cherry-pick <хеш> |
Копии выбранных коммитов |
Squash: все коммиты ветки одним
Флаг --squash готовит в рабочей папке и индексе то же состояние, что дало бы обычное слияние, но коммит не создаёт. Его вы делаете сами, со своим сообщением. В ветке feature/search было три коммита, в main попадает один:
$ git merge --squash feature/search
Updating f4d2b82..bd75381
Fast-forward
Squash commit -- not updating HEAD
search.py | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 search.py
$ git commit -m "Добавить поиск по товарам"
[main 6fe8c23] Добавить поиск по товарам
1 file changed, 3 insertions(+)
create mode 100644 search.py
$ git log --oneline -2
6fe8c23 Добавить поиск по товарам
f4d2b82 Merge branch 'feature/b'
Учтите побочный эффект. Git не запоминает, что ветка уже слита, поэтому git branch -d feature/search откажется её удалять. Удаляйте флагом -D, когда убедились, что всё на месте:
$ git branch -d feature/search
error: The branch 'feature/search' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature/search'.
Rebase: перенести коммиты на вершину main
Rebase переписывает коммиты фичи так, будто вы начали работу от свежей main. После него слияние в main проходит перемоткой, а история читается сверху вниз без развилок:
Стоя в ветке feature/promo, выполните:
$ git rebase main
Successfully rebased and updated refs/heads/feature/promo.
$ git log --oneline --graph -3
* c745ae4 Промокоды
* 6fe8c23 Добавить поиск по товарам
* f4d2b82 Merge branch 'feature/b'
|\
Хеши коммитов после rebase новые: это уже другие коммиты с тем же содержимым. Отсюда главное правило из главы Pro Git о перебазировании: не перемещайте коммиты, которые уже отправлены в общий репозиторий. Если коллеги успели взять вашу ветку, после rebase их история разойдётся с вашей.
Что выбрать: merge или rebase
- Merge подходит для общих веток и для слияния готовой фичи в main. Он ничего не переписывает, и его безопасно делать в любой момент.
- Rebase подходит для своей локальной ветки, которую никто, кроме вас, не трогал. Им подтягивают свежую main перед пул-реквестом.
- Squash подходит, когда в main нужен один понятный коммит вместо промежуточных.
Подтянуть свежую main в свою ветку можно и без rebase. Стоя в ветке фичи, выполните git merge main: изменения придут коммитом слияния, история останется нетронутой.
Все три способа стоит один раз отработать руками на учебном репозитории, такие задания есть и в курсах по GitLab, где слияние идёт через merge request. Глубже всех в эти правила погружается Git-специалист, который настраивает процессы для всей команды.
Как решить конфликт слияния
Конфликт возникает, когда обе ветки поменяли одну и ту же строку. В нашем примере в main цену подняли до 1 200, а в ветке feature/discount сделали скидку и поставили 900. Чем больше людей правит один файл, тем чаще так бывает, поэтому для веб-разработчика разбор конфликтов входит в базовые навыки. Git не знает, какое число правильное, и останавливается:
$ git merge feature/discount
Auto-merging price.txt
CONFLICT (content): Merge conflict in price.txt
Automatic merge failed; fix conflicts and then commit the result.
Конфликт ничего не ломает. Слияние просто стоит на паузе и ждёт вашего решения. Дальше действуйте по шагам.
- Найдите файлы с конфликтом командой
git status. Они лежат в блокеUnmerged pathsс пометкойboth modified:$ git status On branch main You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add <file>..." to mark resolution) both modified: price.txt no changes added to commit (use "git add" and/or "git commit -a") - Откройте файл. Git разметил спорное место маркерами. Сверху версия текущей ветки (HEAD), под разделителем версия вливаемой:
<<<<<<< HEAD Цена: 1200 ======= Цена: 900 >>>>>>> feature/discount - Оставьте правильный вариант и удалите все три маркера. Можно взять одну из версий целиком или собрать третью. Здесь логичная итоговая цена со скидкой 10 % от новой:
Цена: 1080. - Отметьте конфликт решённым:
git add price.txt. - Завершите слияние:
git commit. Сообщение Git подставит сам.$ git add price.txt $ git commit --no-edit [main ea24dc6] Merge branch 'feature/discount'
В редакторе спорные блоки подсвечены цветом. Над каждым конфликтом VS Code показывает действия Accept Current Change, Accept Incoming Change и Accept Both Changes: оставить свою версию, вливаемую или обе подряд. Остальные способы, включая трёхсторонний редактор, описаны в статье VS Code о конфликтах слияния. Из терминала тот же выбор открывает git mergetool, если у вас настроена программа сравнения. Если вы пишете код в этом редакторе, пригодится и инструкция по запуску Python в VS Code.
Решили, что сливать сейчас рано? Прервите слияние командой git merge --abort. Git вернёт файлы к состоянию до merge, git status --short после этого пустой.
Как отменить merge
Способ отмены зависит от того, успели ли вы отправить слияние на сервер.
| Ситуация | Команда | Что произойдёт |
|---|---|---|
| Слияние остановилось на конфликте | git merge --abort |
Возврат к состоянию до merge |
| Коммит слияния есть, но не запушен | git reset --hard ORIG_HEAD |
Ветка возвращается туда, где стояла до merge |
| Коммит слияния уже на сервере | git revert -m 1 <хеш> |
Новый коммит, который отменяет изменения слияния |
До пуша: reset на ORIG_HEAD
Перед слиянием Git записывает прежнюю вершину ветки в ссылку ORIG_HEAD, это сказано в разделе DESCRIPTION справки git merge. Вернуться к ней можно одной командой:
$ git reset --hard ORIG_HEAD
HEAD is now at 6e6a451 Подорожание
Флаг --hard стирает незакоммиченные правки в рабочей папке. Проверьте git status до запуска.
После пуша: revert с флагом -m
Если слияние уже забрали коллеги, историю не переписывают. Вместо этого создают коммит, который отменяет изменения. Для коммита слияния нужен флаг -m 1: он говорит Git, что основной линией считается первый родитель, то есть ветка, в которую сливали. Без флага Git откажется:
$ git revert HEAD~1 --no-edit
error: commit 4cd0348f54c26d338cda9c59b281d275f55897e6 is a merge but no -m option was given.
fatal: revert failed
$ git revert -m 1 HEAD --no-edit
[main 810ea87] Revert "Merge branch 'feature/discount'"
Date: Fri Nov 6 10:25:00 2026 +0300
1 file changed, 1 insertion(+), 1 deletion(-)
У отката слияния есть ловушка, о которой предупреждает справка git revert: после него следующие слияния принесут только те коммиты, которых не было в отменённом merge. На практике повторный git merge feature/discount после такого отката отвечает Already up to date., а в файле остаётся старая цена. Чтобы вернуть фичу, отмените сам revert: git revert <хеш revert-коммита>.
Частые ошибки и что с ними делать

Ниже сообщения, которые чаще всего пугают на первых слияниях, и их причины.
Already up to date
Git считает, что всё из указанной ветки уже есть в текущей. Обычно вы стоите не на той ветке или сливаете в обратную сторону. Проверьте git branch и git log --oneline --graph --all. Вторая частая причина описана выше: ветку уже сливали, а потом откатили через revert.
not something we can merge
$ git merge feature/carts
merge: feature/carts - not something we can merge
Такой ветки Git не знает. Либо опечатка в имени, либо ветка есть только на сервере. Во втором случае сначала выполните git fetch, а потом сливайте origin/имя-ветки.
Your local changes would be overwritten by merge
$ git merge feature/readme
Updating 759910f..e197219
error: Your local changes to the following files would be overwritten by merge:
README.md
Please commit your changes or stash them before you merge.
Aborting
В рабочей папке есть незакоммиченные правки в файле, который меняет слияние. Git ничего не тронул и остановился. Решение: git commit или git stash, затем снова git merge, а после него git stash pop, если прятали.
refusing to merge unrelated histories
У двух веток нет общего предка. Так бывает, когда вы создали репозиторий на GitHub с README, а локально сделали git init отдельно. По описанию флага --allow-unrelated-histories, Git по умолчанию отказывается сливать такие истории. Если вы уверены, что это один проект, добавьте флаг:
$ git merge other/main
fatal: refusing to merge unrelated histories
$ git merge other/main --allow-unrelated-histories --no-edit
Merge made by the 'ort' strategy.
x | 1 +
1 file changed, 1 insertion(+)
create mode 100644 x
You have divergent branches при git pull
Pull делает две вещи: загружает коммиты с сервера и сливает их с вашими. Когда новые коммиты есть и у вас, и на сервере, Git просит выбрать способ объединения и останавливается:
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
fatal: Need to specify how to reconcile divergent branches.
Выберите один из трёх вариантов из подсказки и сохраните его глобально, например git config --global pull.rebase false, если в команде принято сливать. Те же настройки pull.rebase и pull.ff перечислены в справке git pull.
Слияние веток на GitHub через пул-реквест
В командах слияние в main редко делают руками. Вы пушите ветку, открываете пул-реквест, коллеги смотрят код, и кнопка внизу страницы делает merge на сервере. Как создать копию чужого репозитория и предложить в него изменения, мы разбирали в статье про форк на GitHub.
У кнопки три режима, они соответствуют способам из этой статьи. Названия даём так, как они подписаны в справке GitHub о методах слияния:
- Merge pull request: обычное слияние с флагом
--no-ff, коммит слияния создаётся всегда. - Squash and merge: все коммиты пул-реквеста сжимаются в один.
- Rebase and merge: коммиты добавляются в базовую ветку по одному, без коммита слияния.
Набор режимов настраивается в параметрах репозитория. Если кнопка предлагает только один, значит, остальные там выключили.
Где освоить Git системно
Слияние веток входит в набор операций, которые разработчик делает почти каждый день. Остальные, от cherry-pick до поиска сломавшего коммита через bisect, разбирают на курсах с практическими заданиями. Git входит в базу плана, как стать программистом с нуля, а для DevOps-инженера это ежедневный инструмент.
В каталоге Checkroi курсы по Git собраны с ценами и отзывами учеников. Отдельно есть подборка курсов по GitHub. Ниже пять программ из каталога.
| Курс | Школа | Стоимость со скидкой | В рассрочку | Длительность | Обзор курса от Checkroi |
|---|---|---|---|---|---|
| Gitlab CI/CD с нуля Перейти на сайт курса | 16 250 ₽ | 1354 ₽/мес. | 4 месяца | Обзор курса | |
| Gitlab CI/CD Перейти на сайт курса | 25 000 ₽ | 6250 ₽/мес. | 58 часов | Обзор курса | |
| Основы Git Перейти на сайт курса | 3999 ₽ | 2749 ₽/мес. | 2 месяца | Обзор курса | |
| Обучение Git Перейти на сайт курса | 22 500 ₽ | - | 1 месяц | Обзор курса | |
| Основы Git Перейти на сайт курса | Бесплатно | - | 1 месяц | Обзор курса |
Больше программ — в полном каталоге курсов по Git




