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
  • Уроки
  • База знаний
  • Собеседование
Cluster

← все кластеры

Сценарии: потерял коммит, force-push, detached HEAD

Сценарные вопросы - самые ценные на собесе. Не «что такое reflog», а «снёс свои коммиты через reset --hard, что делать первым делом». Эти вопросы отличают того, кто читал учебник, от того, кто гасил инциденты в командном репо. Все сценарии реальные.

6 вопросов · ~35 мин чтения

Questions

На этой странице

  1. 01Случайно сделал `git reset --hard HEAD~5`. Локально, не пушнут. Что делаешь?
  2. 02Коллега сделал force-push в main, снёс 6 чужих коммитов. Что делаем?
  3. 03Я в detached HEAD. Что это и как выйти безопасно?
  4. 04Merge упал в конфликт. Что выбрать: abort или continue, и как принять решение?
  5. 05Кто-то закоммитил 2GB видеофайл год назад. Репо вырос до 5GB. Как выкинуть?
  6. 06`fatal: index file corrupt` при любой команде. Что делать?

#git-reset-hard-recovery

intermediateчасто

Случайно сделал `git reset --hard HEAD~5`. Локально, не пушнут. Что делаешь?

Что отвечать

`git reflog` - найди запись «HEAD@{1}» (это место до reset'а), там SHA того что было. Дальше один из двух способов: `git reset --hard HEAD@{1}` (вернуть ветку туда же), или `git checkout -b restored HEAD@{1}` (создать ветку из того места, оставив текущую как есть). Это работает потому что reset двигает только указатель ветки - коммиты физически остаются в `.git/objects/` пока не прошёл `git gc`.

Что хотят услышать

Кандидат должен: - первой командой назвать `git reflog`, без паники и без gc - объяснить почему это работает: reset не удаляет коммиты, только двигает ref, коммиты остаются dangling до gc (по умолчанию 90 дней для достижимых из reflog) - назвать `HEAD@{1}` как идиоматическое «один шаг назад в reflog» - предупредить: **не делай** `git gc --prune=now` после факапа - можешь снести dangling-коммиты - сказать что аналогично работает для `branch -D`: до gc ветка достижима через reflog

Подводные камни

  • ✗ Запустить `git gc --prune=now` сразу после паники - снесёшь то что хотел восстановить
  • ✗ Думать что reset физически стирает коммиты - не стирает, только двигает ref
  • ✗ Полагаться на reflog через 3 месяца - запись уже expired

Follow-up

  • ? Что покажет `git reflog HEAD` после нескольких reset'ов?
  • ? Как восстановить если reflog уже почистился?
  • ? Почему `git gc --prune=now` после reset опасен?

Глубина в базе знаний

  • git reflog
  • Commit
tags: troubleshooting, reset, reflog

#git-force-push-snosed-main

seniorчасто

Коллега сделал force-push в main, снёс 6 чужих коммитов. Что делаем?

Что отвечать

Любой, у кого main был свежим до force-push, имеет старый SHA в локальном reflog. `git reflog refs/heads/main` или `git reflog origin/main` покажет последний правильный SHA. Дальше: восстановить main с этого SHA локально (`git checkout -B main <sha>`), сделать force-push обратно правильную историю. Если у всех уже подтянут сломанный main - попросить того у кого reflog ещё содержит старое состояние, либо проверить серверный gc / backup.

Что хотят услышать

Senior должен: - назвать «у каждого свой reflog» как ключевую идею: распределённость Git это спасение - дать workflow: найти reflog с правильным SHA → восстановить локально → согласованный force-push обратно - сказать что если у всех уже сделан `git pull`, который перетащил force-push'нутую версию - reflog у каждого содержит **обе** записи, ищем «до pull» - упомянуть **профилактику**: branch protection на main с запретом force-push, требование PR через required reviewers - назвать что после восстановления нужен postmortem: почему force-push в main стал возможен, обычно это пробитая branch protection или admin-bypass

Подводные камни

  • ✗ Запаниковать и не проверить reflog - решение прямо там
  • ✗ Сделать `git pull` после force-push, надеясь что pull «всё разрулит» - получишь merge старой и новой истории
  • ✗ Положиться на сервер: bare-репо обычно без reflog, GitHub `Network` graph показывает прошлое, но восстановление из UI - только через REST API

Follow-up

  • ? Что покажет `git reflog origin/main` у того, кто только что сделал fetch?
  • ? Как восстановить через GitHub REST API если ни у кого нет reflog?
  • ? Какие настройки branch protection делают этот сценарий невозможным?

Глубина в базе знаний

  • git reflog
  • Force push
  • Branch protection rules
tags: troubleshooting, force-push, recovery

#git-detached-head-explain

juniorчасто

Я в detached HEAD. Что это и как выйти безопасно?

Что отвечать

Detached HEAD - это когда HEAD указывает прямо на коммит, а не на ветку. Бывает после `git checkout <sha>`, `git checkout v1.2.3`, во время interactive rebase. Опасно тем что коммиты которые сделаешь в этом состоянии не привязаны к ветке - после `git checkout main` они станут dangling и через gc исчезнут. Выход безопасный: `git switch -c new-branch` (или `git checkout -b new-branch`) - создаст ветку прямо здесь и привяжет HEAD к ней.

Что хотят услышать

Кандидат должен: - объяснить «HEAD указывает на SHA, не на ref» - и почему это нормальное состояние, не баг - назвать типичные причины: checkout тега, checkout SHA из bisect, посреди rebase - сказать что коммиты в detached HEAD не теряются сразу - они в reflog HEAD, восстанавливаются если не упустить gc - дать безопасный выход: `git switch -c branch` (или `git checkout -b`) - привязывает HEAD к новой ветке прямо здесь - упомянуть что `git switch -` возвращает на предыдущую ветку (как `cd -` в shell)

Подводные камни

  • ✗ Сделать коммиты в detached HEAD и потом `git switch main` - коммиты остаются доступны только через `git reflog HEAD`
  • ✗ Думать что detached HEAD это сломанное состояние - валидное, иногда нужное
  • ✗ Использовать `git checkout <sha>` без понимания - попадаешь в detached, не понимая почему

Follow-up

  • ? Как восстановить коммиты сделанные в detached HEAD после `git switch main`?
  • ? Зачем bisect использует detached HEAD?
  • ? Что покажет `cat .git/HEAD` в detached vs нормальном состоянии?

Глубина в базе знаний

  • Detached HEAD
  • git reflog
tags: troubleshooting, detached, head

#git-merge-abort-vs-continue

intermediateчасто

Merge упал в конфликт. Что выбрать: abort или continue, и как принять решение?

Что отвечать

`git merge --abort` если: конфликтов больше чем ожидал, не понимаешь что приехало, не уверен в стратегии resolve. Возвращает в состояние до merge, безопасно. `git merge --continue` (или просто `git add` + `git commit`) когда: конфликты разрулил, проверил `git status` (нет файлов с маркерами), запустил локальные тесты, всё ок. Не спеши с continue - merge-коммит остаётся в истории навсегда.

Что хотят услышать

Senior должен: - назвать `git merge --abort` как safe default при неуверенности - дать checklist перед continue: `git status` (никаких файлов в "Unmerged paths"), `grep -r '<<<<<<<'` (нет ли забытых маркеров), локальные тесты прошли - сказать что `git merge.conflictStyle diff3` даёт блок `||||||| base` в маркерах - часто помогает увидеть исходное состояние - упомянуть `git checkout --ours <file>` / `--theirs <file>` для случая когда хочешь полностью одну из сторон без построчного разбора - назвать `git rerere` для long-running веток с повторяющимися конфликтами - запоминает resolve и применяет автоматом

Подводные камни

  • ✗ Закоммитить файл с `<<<<<<<` маркерами - попадёт в историю
  • ✗ Сделать `git commit` без `git add` после resolve - не подхватит изменения
  • ✗ Использовать `--ours`/`--theirs` не понимая что во время rebase их семантика инвертирована

Follow-up

  • ? Что покажет `git status` посреди merge с конфликтом?
  • ? Чем `git checkout --ours` во время merge отличается от во время rebase?
  • ? Зачем `merge.conflictStyle diff3`?

Глубина в базе знаний

  • git merge
  • Стратегии merge PR (GitHub)
  • Auto-merge для PR
tags: troubleshooting, merge, conflict

#git-huge-file-bloat-repo

seniorиногда

Кто-то закоммитил 2GB видеофайл год назад. Репо вырос до 5GB. Как выкинуть?

Что отвечать

`git filter-repo --strip-blobs-bigger-than 100M` (или `--path huge.mp4 --invert-paths` для конкретного файла) перепишет историю удалив большие blob'ы из всех коммитов. SHA коммитов меняются, нужен force-push всех веток и тегов, все разработчики переклонируют. Затем `git gc --prune=now --aggressive` чтобы физически удалить blob'ы. На будущее: `git lfs` для больших бинарников и pre-receive hook на сервере с лимитом размера.

Что хотят услышать

Senior должен: - назвать `git filter-repo` (не filter-branch), как стандартный инструмент 2026 - сказать что filter-repo это переписывание истории → force-push → координация с командой - объяснить что просто `git rm huge.mp4` + коммит не уменьшит репо - blob останется в истории и в clone - назвать LFS как **профилактику**: большие файлы хранятся в отдельном backend'е, в коммите только pointer (~130 байт) - упомянуть `git count-objects -vH` для проверки размера до и после, и `git rev-list --objects --all | git cat-file --batch-check='%(objectsize) %(objectname)' | sort -nr | head` для поиска топ-N самых больших blob'ов

Подводные камни

  • ✗ Сделать `git rm huge.mp4` + коммит и думать что репо уменьшится - blob остался в истории
  • ✗ Использовать filter-branch вместо filter-repo - устарел, медленный, баговый
  • ✗ Запустить filter-repo без бэкапа - если что-то пойдёт не так, откатить нечем
  • ✗ Не настроить LFS после чистки - история повторится через месяц

Follow-up

  • ? Как найти топ-10 самых больших blob'ов в истории?
  • ? Чем `git lfs` отличается от обычного blob'а?
  • ? Какой pre-receive hook отрежет коммит с файлом > 100MB?

Глубина в базе знаний

  • git filter-repo: переписывание истории
  • Packfile
  • Force push
tags: troubleshooting, repo-size, filter-repo

#git-index-corrupted

seniorредко

`fatal: index file corrupt` при любой команде. Что делать?

Что отвечать

`.git/index` это бинарный кэш staged-состояния, его можно пересобрать из tree'а HEAD без потери данных. Workflow: `rm .git/index` (либо переместить как backup) → `git reset` (без аргументов, пересоздаст index из HEAD) → `git status` чтобы увидеть что в working tree отличается от HEAD. Working tree и `.git/objects/` не трогаются. Если индекс восстановился - можешь заново `git add` всё что планировал коммитить.

Что хотят услышать

Senior должен: - назвать что index это **производное**, не источник правды - безопасно удалить и пересобрать из HEAD - дать конкретные команды: `rm .git/index` → `git reset` (= `git reset --mixed HEAD`) → `git status` - сказать что working tree не пострадает - там твои файлы как есть, изменения сохранятся (потом `git add` снова) - упомянуть что corruption обычно от kill'а Git'а посреди write (питание, OOM, kill -9) или от bad disk - назвать `git fsck --full` как способ проверить остальной репозиторий на повреждения после corrupted index

Подводные камни

  • ✗ Удалить весь `.git/` вместо `.git/index` - снесёшь репо целиком
  • ✗ Запустить `git reset --hard` думая что это лечит - --hard перетрёт working tree
  • ✗ Не сделать `git fsck` после восстановления - если диск битый, повреждения могут быть и в objects

Follow-up

  • ? Что покажет `git fsck --full` после восстановления index?
  • ? Чем `git reset` без флагов отличается от `git reset --hard`?
  • ? Когда index может повредиться от штатной работы (без kill)?

Глубина в базе знаний

  • git status
  • git reflog
tags: troubleshooting, index, corruption
Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки