Git: ветки, слияние, rebase и stash
Вторая часть гида: работа с ветками, объединение изменений, конфликты, перенос коммитов и временное хранение правок
Ветки
| Команда | Вариант | Что делает |
| git branch | git branch | Локальные ветки (текущая помечена *). |
| git branch -a | git branch -a | Все ветки, включая удалённые (remotes/origin/...). |
| git branch -r | git branch -r | Только удалённые ветки. |
| git branch -vv | git branch -vv | С последним коммитом и связанной удалённой веткой. |
| git branch имя | git branch feature/login | Создать ветку, не переключаясь. |
| git branch -d | git branch -d feature/login | Удалить, только если ветка слита (безопасно). |
| git branch -D | git branch -D old-experiment | Удалить принудительно, даже без слияния. |
| git branch -m | git branch -m old-name new-name | Переименовать ветку. |
| git branch -u | git branch -u origin/main | Связать локальную ветку с удалённой. |
| git branch --merged | git branch --merged main | Ветки, уже влитые в main (кандидаты на удаление). |
| git branch --no-merged | git branch --no-merged main | Ветки, которые ещё не влиты. |
| git switch | git switch main | Переключиться на ветку (современная команда). |
| git switch -c | git switch -c feature/payments | Создать и сразу переключиться. |
| git switch - | git switch - | Вернуться на предыдущую ветку. |
| git checkout -b | git checkout -b hotfix/1.2.1 v1.2.0 | Старая форма: создать ветку от тега. |
| git checkout -- | git checkout -- app.py | Старая форма: отменить изменения файла (лучше git restore). |
| git restore | git restore app.py | Отменить изменения файла в рабочей папке (необратимо!). |
| git restore --source | git restore --source=HEAD~2 app.py | Вернуть файл из другого коммита. |
| git switch --detach | git switch --detach v2.0.0 | Перейти в состояние detached HEAD (на тег или коммит). |
Слияние: merge
| Команда | Вариант | Что делает |
| git merge | git switch main && git merge feature/login | Влить ветку в текущую. Может создать коммит слияния. |
| git merge --no-ff | git merge --no-ff feature/login | Всегда создавать коммит слияния (видно границы фичи в истории). |
| git merge --ff-only | git merge --ff-only origin/main | Только перемотка вперёд; если нельзя без слияния, команда остановится. |
| git merge --squash | git merge --squash feature/x && git commit -m "feat: x" | Собрать все коммиты ветки в один, без коммита слияния. |
| git merge --abort | git merge --abort | Отменить слияние с конфликтами и вернуться к исходному состоянию. |
| git merge -X | git merge -X theirs feature/x | Стратегия при конфликтах: ours — наша версия, theirs — их версия. |
| git merge -m | git merge --no-ff -m "merge: login" feature/login | Своё сообщение коммита слияния. |
| git log --merge | git 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 rebase | git switch feature/x && git rebase main | Переставить коммиты ветки поверх main (линейная история). |
| git rebase -i | git rebase -i HEAD~4 | Интерактивно: переупорядочить, объединить, изменить или удалить 4 последних коммита. |
| git rebase --onto | git rebase --onto main feature-base feature-x | Перенести коммиты feature-x с одной базы на другую. |
| git rebase --continue | git rebase --continue | После разрешения конфликта продолжить rebase. |
| git rebase --skip | git rebase --skip | Пропустить коммит, который не применяется. |
| git rebase --abort | git rebase --abort | Отменить rebase и вернуть исходное состояние. |
| git rebase --autosquash | git rebase -i --autosquash main | Автоматически поставить коммиты fixup! и squash! на нужное место. |
| git pull --rebase | git 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-pick | git cherry-pick abc1234 | Применить изменения одного коммита к текущей ветке. |
| git cherry-pick диапазон | git cherry-pick A^..B | Диапазон коммитов, включая A. |
| git cherry-pick -n | git cherry-pick -n abc1234 | Внести изменения в индекс без коммита, чтобы собрать несколько. |
| git cherry-pick -x | git cherry-pick -x abc1234 | Добавить в сообщение ссылку на исходный коммит. |
| git cherry-pick --continue | git cherry-pick --continue | Продолжить после конфликта. |
| git cherry-pick --abort | git cherry-pick --abort | Отменить. |
Временное хранение: stash
| Команда | Вариант | Что делает |
| git stash | git stash | Спрятать незакоммиченные изменения и очистить рабочую папку. |
| git stash push -m | git stash push -m "wip: кнопка оплаты" | Stash с понятным описанием. |
| git stash -u | git stash push -u | Включить новые неотслеживаемые файлы. |
| git stash -k | git stash push --keep-index | Оставить уже добавленные в индекс изменения в рабочей папке. |
| git stash pop | git stash pop | Вернуть последний stash и удалить его из списка. |
| git stash apply | git stash apply stash@{2} | Вернуть stash, но не удалять его. |
| git stash list | git stash list | Все сохранённые stash. |
| git stash show | git stash show -p stash@{0} | Что лежит в stash, с диффом. |
| git stash drop | git stash drop stash@{1} | Удалить один stash. |
| git stash clear | git stash clear | Удалить все stash (необратимо). |
| git stash branch | git stash branch feature/from-stash | Создать ветку из stash и применить его. |
Теги
| Команда | Вариант | Что делает |
| git tag | git tag -l "v1.*" | Список тегов по шаблону. |
| git tag -a | git tag -a v1.4.0 -m "Релиз 1.4.0" | Аннотированный тег с сообщением (рекомендуется для релизов). |
| git tag | git tag v1.4.0-rc1 abc1234 | Лёгкий тег на конкретный коммит. |
| git push --tags | git push origin --tags | Отправить все теги. |
| git push origin : | git push origin --delete v1.4.0-rc1 | Удалить тег на сервере. |
| git tag -d | git tag -d v1.4.0-rc1 | Удалить тег локально. |
| git show | git 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. Не копируйте файлы вручную: так легко потерять правки.