Git: ветки, слияние, rebase и stash

Вторая часть гида: работа с ветками, объединение изменений, конфликты, перенос коммитов и временное хранение правок

Ветки

КомандаВариантЧто делает
git branchgit branchЛокальные ветки (текущая помечена *).
git branch -agit branch -aВсе ветки, включая удалённые (remotes/origin/...).
git branch -rgit branch -rТолько удалённые ветки.
git branch -vvgit branch -vvС последним коммитом и связанной удалённой веткой.
git branch имяgit branch feature/loginСоздать ветку, не переключаясь.
git branch -dgit branch -d feature/loginУдалить, только если ветка слита (безопасно).
git branch -Dgit branch -D old-experimentУдалить принудительно, даже без слияния.
git branch -mgit branch -m old-name new-nameПереименовать ветку.
git branch -ugit branch -u origin/mainСвязать локальную ветку с удалённой.
git branch --mergedgit branch --merged mainВетки, уже влитые в main (кандидаты на удаление).
git branch --no-mergedgit branch --no-merged mainВетки, которые ещё не влиты.
git switchgit switch mainПереключиться на ветку (современная команда).
git switch -cgit switch -c feature/paymentsСоздать и сразу переключиться.
git switch -git switch -Вернуться на предыдущую ветку.
git checkout -bgit checkout -b hotfix/1.2.1 v1.2.0Старая форма: создать ветку от тега.
git checkout --git checkout -- app.pyСтарая форма: отменить изменения файла (лучше git restore).
git restoregit restore app.pyОтменить изменения файла в рабочей папке (необратимо!).
git restore --sourcegit restore --source=HEAD~2 app.pyВернуть файл из другого коммита.
git switch --detachgit switch --detach v2.0.0Перейти в состояние detached HEAD (на тег или коммит).

Слияние: merge

КомандаВариантЧто делает
git mergegit switch main && git merge feature/loginВлить ветку в текущую. Может создать коммит слияния.
git merge --no-ffgit merge --no-ff feature/loginВсегда создавать коммит слияния (видно границы фичи в истории).
git merge --ff-onlygit merge --ff-only origin/mainТолько перемотка вперёд; если нельзя без слияния, команда остановится.
git merge --squashgit merge --squash feature/x && git commit -m "feat: x"Собрать все коммиты ветки в один, без коммита слияния.
git merge --abortgit merge --abortОтменить слияние с конфликтами и вернуться к исходному состоянию.
git merge -Xgit merge -X theirs feature/xСтратегия при конфликтах: ours — наша версия, theirs — их версия.
git merge -mgit merge --no-ff -m "merge: login" feature/loginСвоё сообщение коммита слияния.
git log --mergegit log --merge --onelineКоммиты, из-за которых возник конфликт.

Разрешение конфликтов

git merge feature/x
# CONFLICT (content): Merge conflict in app.py

# В файле появятся маркеры:
<<<<<<< HEAD
timeout = 30
=======
timeout = 60
>>>>>>> feature/x

# 1. Исправьте файл, оставив нужный вариант, и удалите маркеры
# 2. Добавьте исправленный файл
git add app.py
# 3. Завершите слияние
git commit        # или git merge --continue

# Список файлов с конфликтами
git diff --name-only --diff-filter=U

# Выбрать одну из версий целиком
git checkout --ours app.py      # наша
git checkout --theirs app.py    # их

Инструменты для сложных конфликтов: git mergetool откроет настроенную программу слияния. Для настройки используйте git config --global merge.tool vimdiff или другой редактор.

Перенос изменений: rebase

КомандаВариантЧто делает
git rebasegit switch feature/x && git rebase mainПереставить коммиты ветки поверх main (линейная история).
git rebase -igit rebase -i HEAD~4Интерактивно: переупорядочить, объединить, изменить или удалить 4 последних коммита.
git rebase --ontogit rebase --onto main feature-base feature-xПеренести коммиты feature-x с одной базы на другую.
git rebase --continuegit rebase --continueПосле разрешения конфликта продолжить rebase.
git rebase --skipgit rebase --skipПропустить коммит, который не применяется.
git rebase --abortgit rebase --abortОтменить rebase и вернуть исходное состояние.
git rebase --autosquashgit rebase -i --autosquash mainАвтоматически поставить коммиты fixup! и squash! на нужное место.
git pull --rebasegit pull --rebase origin mainПолучить изменения и переставить свои коммиты поверх них.

Команды в интерактивном rebase

КомандаЧто делает
pickоставить коммит как есть
rewordоставить, но изменить сообщение
editостановиться на коммите, чтобы изменить содержимое
squashобъединить с предыдущим, сообщения склеиваются
fixupобъединить с предыдущим, сообщение предыдущего коммита сохраняется
dropудалить коммит
execвыполнить команду (например, тесты) после коммита
Rebase переписывает историю: коммиты получают новые хэши. Не делайте rebase веток, которые уже опубликованы и с которыми работают другие люди. Для общей ветки используйте merge. После rebase опубликованной ветки потребуется git push --force-with-lease, и коллеги должны будут синхронизироваться заново.

Перенос отдельных коммитов: cherry-pick

КомандаВариантЧто делает
git cherry-pickgit cherry-pick abc1234Применить изменения одного коммита к текущей ветке.
git cherry-pick диапазонgit cherry-pick A^..BДиапазон коммитов, включая A.
git cherry-pick -ngit cherry-pick -n abc1234Внести изменения в индекс без коммита, чтобы собрать несколько.
git cherry-pick -xgit cherry-pick -x abc1234Добавить в сообщение ссылку на исходный коммит.
git cherry-pick --continuegit cherry-pick --continueПродолжить после конфликта.
git cherry-pick --abortgit cherry-pick --abortОтменить.

Временное хранение: stash

КомандаВариантЧто делает
git stashgit stashСпрятать незакоммиченные изменения и очистить рабочую папку.
git stash push -mgit stash push -m "wip: кнопка оплаты"Stash с понятным описанием.
git stash -ugit stash push -uВключить новые неотслеживаемые файлы.
git stash -kgit stash push --keep-indexОставить уже добавленные в индекс изменения в рабочей папке.
git stash popgit stash popВернуть последний stash и удалить его из списка.
git stash applygit stash apply stash@{2}Вернуть stash, но не удалять его.
git stash listgit stash listВсе сохранённые stash.
git stash showgit stash show -p stash@{0}Что лежит в stash, с диффом.
git stash dropgit stash drop stash@{1}Удалить один stash.
git stash cleargit stash clearУдалить все stash (необратимо).
git stash branchgit stash branch feature/from-stashСоздать ветку из stash и применить его.

Теги

КомандаВариантЧто делает
git taggit tag -l "v1.*"Список тегов по шаблону.
git tag -agit tag -a v1.4.0 -m "Релиз 1.4.0"Аннотированный тег с сообщением (рекомендуется для релизов).
git taggit tag v1.4.0-rc1 abc1234Лёгкий тег на конкретный коммит.
git push --tagsgit push origin --tagsОтправить все теги.
git push origin :git push origin --delete v1.4.0-rc1Удалить тег на сервере.
git tag -dgit tag -d v1.4.0-rc1Удалить тег локально.
git showgit show v1.4.0Информация о теге и его коммите.

Типичный рабочий цикл

# Новая фича от актуальной main
git switch main
git pull --rebase origin main
git switch -c feature/invoice-pdf

# работа, коммиты
git add -p
git commit -m "feat: генерация PDF счетов"

# синхронизация с main перед слиянием
git fetch origin
git rebase origin/main

# публикация и слияние через Merge Request / Pull Request
git push -u origin feature/invoice-pdf

# после одобрения: локально обновиться
git switch main
git pull --rebase
git branch -d feature/invoice-pdf
git push origin --delete feature/invoice-pdf
Если вы переключаетесь с незакоммиченной работой на другую ветку, а Git не даёт этого сделать, используйте git stash push -m, переключитесь и затем git stash pop. Не копируйте файлы вручную: так легко потерять правки.