Типовые ситуации с Git
Эта глава — практический справочник по симптомам: «случилось X → сначала проверь Y → сделай Z». Теория команд, объектная модель и продвинутые темы — в шпаргалке; базовый цикл и три зоны — в «Как работать с Git»; команда и PR — в рекомендациях; секреты и .gitignore — в отдельном руководстве.
Тренажёр для отработки веток: Learn Git Branching.
Как пользоваться главой
- Найдите симптом (сообщение в терминале, ощущение «всё пропало»).
- Выполните минимальную диагностику (блок ниже).
- Определите зону риска — от этого зависит, можно ли переписывать историю.
- Следуйте шагам карточки. При сомнении на общей ветке (
main,develop) — согласуйте действия с командой.
Минимальная диагностика (всегда)
git status
git log --oneline -10
Если пропали коммиты, сбросили ветку или удалили branch — добавьте:
git reflog -20
reflog — локальный журнал движения HEAD и веток. Записи живут ограниченное время и не синхронизируются с сервером: после свежего git clone старых записей не будет.
Зоны риска
| Зона | Смысл | Типичные инструменты |
|---|---|---|
| A — только локально | История на сервере не тронута | reset, amend, restore, stash, reflog |
| B — ваша ветка на remote | Переписывание затронет только ваших ревьюеров | rebase, push --force-with-lease |
| C — общая ветка | Переписывание истории ломает коллег | revert, hotfix-ветка, согласование с maintainer |
reflog — главный инструмент «я нажал не то».Индекс ситуаций
| Симптом | Карточка |
|---|---|
| Забыл файл в последнем коммите | Дополнить последний коммит |
| Опечатка в сообщении коммита | Дополнить последний коммит |
| В коммит попало лишнее / хочу разбить коммиты | Разделить изменения |
| Нужна только часть файла в коммите | Выборочный stage |
| Отменить правки в файле / в индексе | Таблица отмены |
| Срочно переключить ветку, работа не готова | Stash |
Закоммитил в main, нужна feature-ветка | Коммит не в той ветке |
| Работал в чужой ветке | Неверная ветка |
push отклонён (non-fast-forward) | Push отклонён |
pull не из той ветки / не в ту ветку | Неверный pull |
| Локально лишние коммиты, на сервере другая история | Сброс к origin |
После reset --hard пропали файлы | Восстановление после hard reset |
| Удалили ветку, коммиты нужны | Удалённая ветка |
| Случайный merge в feature / на сервере | Отмена merge |
Конфликт при rebase | Rebase и конфликты |
| Сделал rebase, не хочу force push | Rebase без force push |
Секрет или .env в коммите | Секреты в истории |
Неверный URL origin | Исправить remote |
| Ветка на сервере удалена, локальные «висят» | Устаревшие ветки |
| Windows: смена регистра в имени файла | Регистр имени файла |
| Вклад в чужой open-source репозиторий | Форк и upstream |
| «Вчера работало, сегодня сломано» — найти коммит | Bisect |
| Перенести один коммит в другую ветку | Cherry-pick |
| «Не понимаю, что наделал» | Общий алгоритм |
Работа с индексом и коммитами
Дополнить или исправить последний коммит
Симптом: после git commit вспомнили про файл, опечатку в сообщении или мелкую правку.
Зона: A (если коммит ещё не push) или B/C (если уже на сервере — amend + force; на общих ветках лучше новый коммит).
# забытый файл
git add забытый.ts
git commit --amend --no-edit
# новое сообщение
git commit --amend -m "Исправить валидацию email в форме регистрации"
Проверка:
git show HEAD --stat
Если коммит уже отправлен в общую ветку — используйте обычный новый коммит или revert, а не amend. Для своей feature после согласования с командой:
git push --force-with-lease origin имя-ветки
--force-with-lease откажется пушить, если на сервере появились чужие коммиты с момента вашего последнего fetch.
Выборочный stage (часть файла)
Симптом: в одном файле два логических изменения, нужны два коммита.
git add -p путь/к/файлу
Интерактивный режим предложит для каждого фрагмента (hunk): y — в индекс, n — пропустить, s — разбить hunk, e — править вручную.
Для нового файла, где нужна только часть строк:
git add -N новый-файл.ts # intent to add
git add -p новый-файл.ts
Проверка перед коммитом:
git diff --staged
git commit -m "Только первая часть задачи"
# оставшиеся правки останутся в рабочей копии
Подробнее про три зоны — в главе про workflow.
Разделить изменения на несколько коммитов
Симптом: один коммит или один git add смешали несколько задач.
Ещё не коммитили, всё в индексе:
git reset -p HEAD # убрать из индекса выбранные hunks
git commit -m "Первая логическая часть"
git add -p ...
git commit -m "Вторая часть"
Уже один коммит, не отправлен:
git reset --soft HEAD~1 # коммит исчезает, правки остаются в индексе
git reset -p HEAD # убрать лишнее из индекса
git commit -m "Часть 1"
git add ...
git commit -m "Часть 2"
Несколько коммитов — интерактивный rebase (зона A/B):
git rebase -i HEAD~3
В редакторе: pick — оставить, squash / fixup — объединить с предыдущим, edit — остановиться и изменить коммит. Подробности — в шпаргалке, rebase -i.
Отмена изменений — рабочая копия, индекс, коммит
| Цель | Команда | Что останется |
|---|---|---|
| Отменить правки в файле (ещё не в индексе) | git restore путь/к/файлу | Версия из последнего коммита |
| Убрать файл из индекса, правки в файле сохранить | git restore --staged путь/к/файлу | Modified в рабочей копии |
| Отменить последний коммит, правки в индексе | git reset --soft HEAD~1 | Staged |
| Отменить последний коммит, правки в файлах | git reset --mixed HEAD~1 (по умолчанию) | Modified |
| Отменить коммит и все правки в tracked-файлах | git reset --hard HEAD~1 | Чистая копия как в коммите-родителе |
| Удалить неотслеживаемые файлы и папки | git clean -fd (сначала -n — dry run) | — |
Неотслеживаемые файлы reset --hard не трогает; для них — git clean. Оба действия необратимы без reflog / резервной копии. Стоп-лист и порядок спасения — Опасные скрипты.
Ветки и переключение
Временно спрятать правки (stash)
Симптом: нужно срочно переключиться на main или другую ветку, коммитить полуфабрикат рано.
git stash push -m "WIP: форма оплаты"
git switch main
# ... срочная правка ...
git switch feature-oplata
git stash list
git stash pop # применить и удалить запись
# или — git stash apply # применить, запись останется
С неотслеживаемыми файлами:
git stash push -u -m "включая новые файлы"
Долгие «кладбища» в stash list усложняют жизнь — для задачи на несколько дней лучше отдельная ветка wip/....
Изменения в неверной ветке
Правки ещё не закоммичены
git stash push -m "перенос на feature-x"
git switch feature-x
git stash pop
Уже есть коммиты, ветка не отправлена
# вы на wrong-branch, коммиты нужны в feature-x
git switch -c feature-x # ветка с коммитами остаётся
git switch wrong-branch
git reset --hard origin/wrong-branch # или на коммит, где ветка должна быть
git switch feature-x
Если wrong-branch уже на сервере — согласуйте с командой; часто проще cherry-pick:
git switch feature-x
git cherry-pick <hash1> <hash2>
git switch wrong-branch
git reset --hard origin/wrong-branch
Закоммитил в main, нужна отдельная ветка
Симптом: несколько коммитов в main, push ещё не было (зона A).
git switch -c feature/моя-задача # указатель ветки уходит с main, коммиты сохраняются
git switch main
git reset --hard origin/main # локальный main = сервер
git switch feature/моя-задача
git push -u origin feature/моя-задача
Если уже запушили в main (зона C) — откат через revert или отдельный PR от maintainer; самостоятельный reset + force на main недопустим в большинстве команд.
Синхронизация с сервером
Push отклонён (non-fast-forward)
Симптом:
! [rejected] feature-x -> feature-x (non-fast-forward)
На сервере есть коммиты, которых нет у вас (часто кто-то запушил в ту же ветку или вы делали rebase / amend).
git fetch origin
git status
git log --oneline HEAD..origin/feature-x # что пришло с сервера
Обновить свою feature-ветку (выберите политику команды):
# вариант 1 — merge (без переписывания истории)
git merge origin/feature-x
# вариант 2 — rebase (линейная история)
git rebase origin/feature-x
Затем:
git push origin feature-x
Если вы переписали историю (rebase, amend) и ветка только ваша:
git push --force-with-lease origin feature-x
git push --force в main / develop ломает работу всей команды. Используйте revert или процесс hotfix.Rebase без force push на remote
Симптом: сделали git rebase origin/main на ветке, которая уже была на сервере, и хотите избежать force push.
Влейте обратно merge-коммитом (история будет с merge, зато без force):
git switch feature-x
git merge origin/feature-x # после rebase remote может расходиться — обсудите с командой
На практике после публичного rebase обычно всё же push --force-with-lease на личную ветку; уточните правила в рекомендациях для команды.
Устаревшие ссылки на remote-ветки
Симптом: на GitHub ветку удалили после merge, локально она ещё в git branch -a.
git fetch --prune
git branch -vv | grep ': gone]' # локальные, у которых upstream исчез
git branch -d имя-ветки # -D если не смержена и вы уверены
Pull из неправильной ветки
Симптом: выполнили git pull origin чужая-ветка, находясь на main или на своей feature, и внезапно подтянулись чужие коммиты. В git status может быть «ahead/behind» или лишние файлы.
Зона: обычно A (если ещё не push); если уже отправили merge на сервер — зона C, нужен revert или помощь команды.
Сначала не делайте новый push, пока не разберётесь.
Fast-forward pull (самый частый случай)
reflog покажет, где была ветка до pull:
git reflog
Пример:
ab7555f HEAD@{0}: pull origin wrong-branch: Fast-forward
c5bc55a HEAD@{1}: checkout: moving to main
Вернуть ветку на состояние до pull:
git reset --hard c5bc55a
# или — git reset --hard HEAD@{1}
Pull создал merge-коммит
Если слияние ещё не завершили (конфликты):
git merge --abort
Если merge-коммит уже создан, но не отправлен:
git reflog
git reset --hard HEAD@{1} # на коммит до merge
Проверка:
git log --oneline -5
git status
Профилактика: явно указывайте ветку и remote: git pull origin main только на main; на feature — git fetch origin и git merge origin/main (или rebase), стоя на своей ветке.
Сбросить локальную ветку к серверу
Симптом: git status пишет Your branch is ahead of 'origin/feature-x' by N commits, а эти коммиты нужно выбросить и совпасть с тем, что на GitHub.
Зона: A для неотправленных коммитов; если коммиты уже на remote — это другая задача (revert / force).
Убедитесь, что лишние коммиты не нужны (или сохраните в запасную ветку):
git branch backup-before-reset HEAD
git fetch origin
git reset --hard origin/feature-x
Локальная ветка станет точной копией удалённой. Неотслеживаемые файлы reset --hard не удаляет — при необходимости git clean -fd (сначала git clean -n).
Неверный URL удалённого репозитория
git remote -v
git remote set-url origin https://github.com/org/правильный-repo.git
git fetch origin
Если склонировали чужой репозиторий целиком — проще удалить папку и git clone снова с правильным URL.
Слияние, rebase, конфликты
Отменить слияние (merge)
Слияние ещё идёт (конфликты, не завершили):
git merge --abort
Merge-коммит уже создан, не отправлен:
git reset --hard HEAD~1
Merge уже на сервере (зона C):
git log --oneline -5 # найти hash merge-коммита
git revert -m 1 <hash-merge-коммита>
git push origin main
-m 1 указывает, какого родителя считать «основной линией» (обычно первая родительская ветка — та, на которой вы стояли при merge).
Конфликты при обычном merge — в главе про ветвление.
Конфликт при rebase
Симптом: во время git rebase origin/main Git остановился с конфликтом.
# правим файлы, убираем маркеры <<<<<<< ======= >>>>>>>
git add исправленные-файлы
git rebase --continue
Отменить весь rebase:
git rebase --abort
Отличие от merge: при rebase вы «переигрываете» свои коммиты поверх новой базы; каждый конфликтный коммит может потребовать отдельного add + continue.
Перед rebase на shared-ветке убедитесь, что команда допускает переписывание истории feature-веток.
Потеря данных и восстановление
После git reset --hard
Симптом: файлы и коммиты «исчезли» после жёсткого сброса.
git reflog
Пример вывода:
a1b2c3d HEAD@{0}: reset: moving to HEAD~3
e4f5g6h HEAD@{1}: commit: Важная работа
Вернуть ветку на состояние до сброса:
git reset --hard e4f5g6h
# или — git reset --hard HEAD@{1}
Перед экспериментами на незнакомых командах:
git branch backup-$(date +%Y%m%d) HEAD
Удалена локальная ветка
git reflog
git branch восстановление e4f5g6h
git switch восстановление
Если ветка была на сервере:
git fetch origin
git switch -c feature-x origin/feature-x
Восстановить один файл из старого коммита
git log --oneline -- путь/к/файлу
git restore --source=abc1234 -- путь/к/файлу
git add путь/к/файлу
git commit -m "Вернуть рабочую версию config из abc1234"
Detached HEAD
Симптом: git status сообщает detached HEAD, вы смотрели старый коммит.
Сохранить работу в ветку:
git switch -c temp-save
Вернуться без новых коммитов:
git switch main
Подробнее — в рекомендациях.
Безопасность и open source
Секрет или конфиденциальный файл в Git
Сразу:
- Ротировать пароль, ключ, токен (старый считать скомпрометированным).
- Убедиться, что путь в
.gitignore(см. руководство по.gitignore).
Ещё не push:
git rm --cached .env
git commit -m "Убрать .env из отслеживания"
Уже на сервере — одного коммита мало: секрет остаётся в истории. Нужны git filter-repo (или поддержка платформы), уведомление команды, ротация ключей. Краткий чек-лист — в 116, раздел «файл уже попал в Git».
Форк и синхронизация с upstream
Симптом: вносите вклад в чужой репозиторий на GitHub; ваш форк отстаёт от оригинала.
git clone git@github.com:ВАШ-ЛОГИН/repo.git
cd repo
git remote add upstream https://github.com/ОРИГИНАЛ/repo.git
git fetch upstream
git switch -c feature/issue-42
# ... коммиты ...
git push -u origin feature/issue-42
Перед новой задачей обновить main в форке:
git switch main
git fetch upstream
git merge upstream/main
git push origin main
Для feature-ветки часто:
git switch feature/issue-42
git rebase upstream/main
git push --force-with-lease origin feature/issue-42
На GitHub откройте Pull Request из форка в оригинальный репозиторий. Схема PR — в ветвлении и слиянии.
Отладка истории
Найти коммит, который всё сломал (bisect)
Симптом: в main (или в релизной метке) что-то перестало работать; между «точно хорошей» и «точно плохой» версией — десятки коммитов, вручную искать долго.
git bisect делит диапазон пополам: Git переключает репозиторий на средний коммит, вы проверяете (тест, запуск приложения) и отвечаете good или bad, пока не останется один коммит-виновник.
Перед стартом — чистое дерево или stash:
git status
git stash push -m "bisect WIP" # при необходимости
Ручной режим (подходит новичкам):
git bisect start
git bisect bad # текущий HEAD сломан
git bisect good v1.0.0 # тег или hash, где всё работало
Git перейдёт на коммит посередине. Проверьте поведение, затем:
git bisect good # на этом коммите всё ок
# или
git bisect bad # здесь уже сломано
Повторяйте, пока Git не напечатает hash первого плохого коммита. Завершение:
git bisect reset
git stash pop # если откладывали правки
Автоматический режим — если есть скрипт с кодом выхода 0 (успех) / не-0 (ошибка):
git bisect start HEAD v1.0.0
git bisect run npm test
git bisect reset
На «мелком» клоне (git clone --depth 1) bisect может не найти старые коммиты — нужна полная история или углубление shallow-клона (см. шпаргалку, bisect).
Перенести один коммит (cherry-pick)
Симптом: нужен один коммит из другой ветки (исправление с hotfix, коммит, случайно сделанный не в той ветке), без полного merge.
git switch целевая-ветка
git cherry-pick abc1234
При конфликте — правите файлы, затем:
git add .
git cherry-pick --continue
Отмена:
git cherry-pick --abort
Несколько коммитов подряд (без коммита A, с B включительно):
git cherry-pick A..B
Подробнее — шпаргалка, cherry-pick.
Платформа и мелочи
Смена регистра имени файла (Windows)
NTFS часто не различает File.txt и file.txt. Двухшаговый rename через Git:
git mv File.txt temp-name.txt
git mv temp-name.txt file.txt
git commit -m "Привести имя файла к нижнему регистру"
На macOS с нечувствительной FS — тот же приём.
Игнорировать локальные правки в отслеживаемом файле
Симптом: в репозитории appsettings.json, локально меняете URL, Git постоянно показывает modified.
git update-index --skip-worktree appsettings.json
# отменить — git update-index --no-skip-worktree appsettings.json
Для командного шаблона лучше appsettings.Development.json в .gitignore и .example в репозитории.
Не понимаю, что произошло
git status— merge/rebase в процессе? конфликты?git log --oneline --graph -15— куда смотрит ветка.git reflog -20— что делали последние шаги.- Определить зону риска (таблица в начале главы).
- Сохранить текущее состояние:
git branch rescue-$(date +%H%M) HEAD
git stash push -u -m "rescue before fix"
- Найти карточку в индексе или спросить коллегу, показав вывод
statusиreflog.
filter-repo, сбой CI после force push — лучше сразу подключить тимлида или DevOps.Связанные материалы
| Тема | Где читать |
|---|---|
Базовый цикл, add -p, просмотр коммита | 112 — Как работать с Git |
| PR, конфликты merge, инструменты | 113 — Ветвление и слияние |
| Культура команды, detached HEAD, краткое восстановление | 114 — Рекомендации |
| Объектная модель, bisect (справочник), worktree, filter-repo | 115 — Шпаргалка |
Секреты, .gitignore, утечки | 116 — .gitignore |
См. также
Другие статьи этого же раздела в боковом меню (как на странице «О разделе»). Git представляет собой систему контроля версий. И самое это понятие является результатом долгого развития программирования как профессии и как науки. Установка и базовая настройка Git - конфигурация пользователя, области действия параметров и проверка окружения. Базовый workflow Git - изменения, staged-состояние, коммиты, история и публикация веток в удаленный репозиторий. Ветвление и слияние в Git - работа с pull request, разрешение конфликтов и безопасная интеграция изменений. Практические рекомендации по Git в команде - роли HEAD, ветвление, код-ревью и безопасная история изменений. Если в рабочей директории есть несохранённые изменения, которые конфликтуют с целевым состоянием, переключение отклоняется — это защита от потери данных. Что такое .gitignore, синтаксис правил, обязательные паттерны, шаблоны для популярных языков и стеков, типичные ошибки и отладка. Краткие итоги раздела «Основы работы с Git». Чек-лист раздела Основы работы с Git — вопросы для самопроверки в энциклопедии Вселенная IT.Система контроля версий Git
Установка и настройка Git
Как работать с Git
Ветвление и слияние в Git
Рекомендации по использованию Git в команде
Справочник-шпаргалка по Git
Файл .gitignore — полное руководство
Итоги
Чек-лист самопроверки