Олег Марков
Проверка связности и целостности репозитория в Git с помощью git fsck
Введение
Проверка связности в Git — это способ убедиться, что все объекты в репозитории находятся в целостном и согласованном состоянии. Команда git fsck как раз и отвечает за эту задачу. Она просматривает внутреннюю структуру хранилища Git, проверяет объекты (коммиты, деревья, блобы, теги) и их связи, а также указывает на проблемы.
Git в обычной работе довольно надежен, но в реальных проектах встречаются ситуации, когда проверка связности становится необходимой:
- сбой диска или файловой системы;
- повреждение
.gitкаталога после ручных правок; - проблемы при переносе репозитория (scp, rsync, флешки);
- некорректная работа сторонних инструментов, которые лезут внутрь
.git; - подозрение на потерю коммитов после rebase, filter-repo или агрессивного gc.
Здесь я покажу вам, как команда git fsck устроена изнутри и как вы можете использовать ее для диагностики и частично для восстановления репозитория.
Что делает git fsck и как он работает
Логика работы git fsck
Давайте разберемся, что именно проверяет git fsck:
Целостность объектов
- каждый объект Git — это сжатый файл, идентифицируемый SHA-1 (или SHA-256 в новых режимах);
- git fsck сверяет хеш содержимого с именем файла;
- если хеш не совпадает, объект считается поврежденным.
Связность графа объектов
- каждый коммит ссылается на родительские коммиты и корневое дерево;
- дерево (tree) содержит ссылки на блобы и поддеревья;
- аннотированный тег (tag) ссылается на объект (часто коммит);
- git fsck проверяет, что все эти ссылки указывают на существующие объекты.
Достижимость объектов
- по умолчанию git хранит и "висящие" объекты (dangling) — те, на которые нет ссылок;
- git fsck может показать их, а также выделить объекты, которые "потеряны" (lost and found).
Таким образом, проверка связности — это и проверка целостности данных, и проверка корректности графа объектов.
Базовый запуск git fsck
Обычный вызов выглядит так:
git fsck
Что здесь происходит:
- Git обходит все объекты, достижимые из ссылок (
refs/heads,refs/tags,refs/remotes,HEADи т.д.); - проверяет хеш, структуру и ссылки;
- выводит только найденные проблемы, если они есть.
Если ошибок нет, команда чаще всего завершится без вывода. Это нормально и означает, что репозиторий выглядит консистентным.
Основные типы сообщений git fsck
Теперь давайте посмотрим, какие сообщения вы можете увидеть и как их читать.
Самые частые категории
Вы можете встретить такие типы сообщений:
dangling— "висящие" объекты, на которые никто не ссылается;missing— отсутствующие объекты, на которые кто-то ссылается;corrupt— поврежденные объекты (например, не распаковываются или имеют неверную структуру);bad— некорректные ссылки внутри объектов (например, ссылка на несуществующий родительский коммит);unreachable— объекты, недостижимые из каких-либо ссылок, если вы используете специальный режим.
Примеры типичных сообщений
dangling commit
$ git fsck
dangling commit 9f1e3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0
Что это значит:
- Git нашел коммит, который не достижим ни из одной ветки или тега;
- чаще всего это "потерянный" результат rebase, amend или merge, который вы переписали.
Такой коммит пока не является ошибкой. Git просто сообщает, что он "висячий" и, возможно, будет удален в будущем сборщиком мусора.
missing blob
$ git fsck
missing blob 1234567890abcdef1234567890abcdef12345678
broken link from tree 9f1e3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0
to blob 1234567890abcdef1234567890abcdef12345678
Смотрите, что здесь происходит:
- у вас есть дерево, которое ссылается на blob с указанным хешем;
- но файла для этого blob в хранилище нет;
- это уже серьезная проблема: один из файлов в истории фактически потерян.
corrupted object
$ git fsck
error: object 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0 is corrupted
fatal: object 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0 is corrupted
Такое сообщение говорит о том, что файл в .git/objects:
- либо не распаковывается как корректный zlib-поток;
- либо имеет неверный формат заголовка;
- либо хеш содержимого не совпадает с именем файла.
Здесь уже нужна более аккуратная работа по восстановлению.
Ключевые опции git fsck
Теперь давайте посмотрим на основные флаги команды, которые помогут вам получить более подробную информацию и адаптировать проверку под свои задачи.
--full
git fsck --full
Эта опция:
- включает полный проход по всем объектам;
- дополнительно проверяет объекты в pack-файлах (
.pack); - иногда на больших репозиториях работает заметно дольше, но дает более надежный результат.
Совет: если вы подозреваете аппаратную или файловую проблему (битые блоки, неустойчивое хранилище), лучше запускать именно --full.
--unreachable
git fsck --unreachable
С этой опцией Git показывает объекты, которые недостижимы из каких-либо ссылок и даже не являются висячими с точки зрения стандартной логики.
Пример вывода:
unreachable blob 5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4
unreachable commit 9f1e3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0
Когда это полезно:
- для анализа "мусора" после массовых переписей истории;
- если вы готовитесь к агрессивному
git gc --prune, и хотите понять, что может быть потеряно; - при аудите репозитория, чтобы увидеть действительно все объекты.
--no-reflogs и --reflog
Git fsck по умолчанию учитывает reflog — историю перемещений ссылок (например, HEAD@{1}, HEAD@{2} и т.д.). Это влияет на то, какие объекты будут считаться достижимыми.
--no-reflogsотключает использование reflog:git fsck --no-reflogsВ этом случае некоторые старые коммиты, до которых можно добраться только через reflog, могут стать
unreachable.--reflog(в некоторых версиях Git) наоборот явно говорит учитывать reflog, но это поведение часто уже включено по умолчанию.
Практический пример:
Если вы хотите увидеть, какие объекты действительно доступны только через reflog (и, значит, скорее всего будут удалены при чистке), вы можете:
git fsck --no-reflogs --unreachable
--lost-found
Флаг --lost-found позволяет сохранить найденные "потерянные" объекты (коммиты, блобы) в специальную структуру ссылок.
Команда:
git fsck --lost-found
Что делает Git:
- объекты, которые не достижимы, но все еще существуют в хранилище, попадают в
.git/lost-found/; - коммиты сохраняются в
.git/lost-found/commit/; - блобы — в
.git/lost-found/other/.
Теперь давайте посмотрим на практический пример использования.
Практические сценарии использования git fsck
Сценарий 1. Проверка репозитория после сбоя диска
Представьте, что у вас был сбой питания или проблемы с дисковой подсистемой, и вы подозреваете повреждение .git.
Действия:
- Остановитесь и не делайте push с текущего репозитория.
- Сделайте резервную копию всего каталога проекта (включая
.git). Запустите полную проверку:
git fsck --full --strict--strictусиливает некоторые проверки корректности.
Проанализируйте вывод:
- если нет ошибок
missingилиcorrupt, скорее всего история в порядке; - если есть проблемные объекты, посмотрите, какие ветки или теги на них ссылаются.
- если нет ошибок
Обратите внимание:
Команда git fsck ничего не меняет в репозитории. Она только читает и анализирует данные. Это безопасная операция с точки зрения изменения истории.
Сценарий 2. Поиск "потерянных" коммитов после rebase
Частая ситуация: вы сделали git rebase, коммиты "пропали" из ветки, и вы боитесь, что потеряли работу. На самом деле Git часто оставляет старые коммиты как dangling.
Давайте разберемся на примере:
# вы были на ветке feature
git rebase main
# что-то пошло не так, часть коммитов не видна
Теперь:
git fsck --lost-found
Git может вывести что-то вроде:
dangling commit 9f1e3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0
И создаст файл:
.git/lost-found/commit/9f1e3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0
Теперь вы можете посмотреть этот коммит:
git show 9f1e3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0
Если это тот самый "потерянный" коммит, вы можете восстановить его, создав новую ветку:
git branch recovered-commit 9f1e3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0
Комментарий к коду:
# Создаем новую ветку recovered-commit, указывая нужный коммит
git branch recovered-commit 9f1e3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0
# Теперь можно перейти на нее и продолжать работу
git checkout recovered-commit
Так вы восстановите доступ к результатам работы, которые казались потерянными.
Сценарий 3. Проверка репозитория перед архивированием или миграцией
Если вы собираетесь:
- заархивировать репозиторий как эталонный;
- перенести его на другой сервер;
- переключиться с одного сервера Git на другой (например, с GitLab на GitHub),
полезно перед этим прогнать тест на связность.
Шаги:
# полная проверка с учетом всех pack-файлов
git fsck --full
# опционально - просмотр unreachable объектов
git fsck --full --unreachable
Если вы видите только dangling или unreachable без missing и corrupt, это обычно не критично. Git часто оставляет "мусор" после переписей истории, и его в любом случае со временем удалит git gc.
Как интерпретировать dangling и unreachable объекты
Эти типы сообщений часто пугают, хотя на самом деле нередко являются нормальной частью жизни репозитория.
Dangling объекты
dangling — это объекты, до которых нельзя добраться ни через ветки, ни через теги, но которые еще не были удалены сборщиком мусора.
Когда они появляются:
- вы сделали
git commit --amend— старый коммит стал dangling; - вы переписали ветку через
git rebase— старые коммиты стали dangling; - вы удалили ветку, но сборщик мусора еще не сработал.
Нужно ли что-то с ними делать:
- обычно — нет. Это "запасная" история, которая со временем будет удалена;
- если вы подозреваете, что что-то важное потеряли, стоит пройтись по таким объектам и посмотреть содержимое.
Для просмотра:
# пример - показываем содержимое висячего коммита
git show 9f1e3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0
Комментарий:
# git show выводит:
# - сообщение коммита
# - автора
# - дату
# - изменения (diff)
git show <hash>
Если вы находите полезный коммит среди dangling, восстановите его, создав ветку.
Unreachable объекты
unreachable — это объекты, до которых нельзя добраться ни через ссылки, ни через reflog (если он учитывается).
Такие объекты:
- часто остаются после очень агрессивных переписей истории;
- могут быть остатками старых pack-файлов;
- вскоре будут помечены на удаление при
git gc --prune.
Смотрите, как это выглядит:
git fsck --unreachable
unreachable commit 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0
Вы все еще можете показать такой объект:
git show 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0
Но если вы не создадите новых ссылок на него (ветки, тега), со временем он исчезнет после сборки мусора.
Как устранять найденные проблемы
Теперь давайте посмотрим, что можно сделать, если git fsck нашел действительно серьезные ошибки — missing или corrupt.
Случай 1. Есть удаленный репозиторий (origin) с корректной историей
Это наиболее частый и самый удобный сценарий решения.
Шаги:
- Убедитесь, что удаленный репозиторий жив и содержит нужную историю.
Склонируйте его заново в другое место:
git clone <url> repo-clean cd repo-clean git fsck --fullЕсли новый клон проходит проверку без ошибок, можно:
- либо продолжить работу в нем;
- либо аккуратно заменить "сломанный" локальный
.gitэтим новым.
Обычно проще просто перейти на новый клон. Так вы гарантированно избавитесь от локальных повреждений.
Случай 2. Повреждены только локальные ветки или экспериментальные изменения
Иногда повреждение касается только вашей локальной работы, а история в origin в порядке. В этом случае логика такая:
- найти, какие именно ветки ссылаются на поврежденные объекты;
- сохранить то, что еще можно сохранить;
- принудительно обновить ветки с origin.
Можно сделать так:
# сохраняем локальные изменения в виде патчей
git format-patch origin/main..HEAD -o backup-patches
# жестко сбрасываемся к origin/main
git fetch origin
git reset --hard origin/main
# пробуем применить патчи
git am backup-patches/*.patch
Комментарии:
# git format-patch создает файлы-патчи для всех коммитов,
# которые есть локально, но отсутствуют в origin/main
git format-patch origin/main..HEAD -o backup-patches
# git reset --hard origin/main полностью переписывает
# локальную ветку main согласно состоянию на сервере
git reset --hard origin/main
Если git fsck ругался только на объекты в этих локальных коммитах, после такого сброса проблемы могут исчезнуть.
Случай 3. Нет удаленного репозитория или он тоже поврежден
Здесь ситуация сложнее, и часто приходится вручную копировать объекты из других клонов или из архивов.
Возможные шаги:
- Найти другие копии репозитория (у коллег, в CI, в старых архивах).
Сравнить объекты, которых не хватает:
git fsck # запомнить хеши missing объектовВ другом (исправном) клоне найти эти объекты:
# в исправном репозитории ls .git/objects/12/34567890abcdef1234567890abcdef12345678Скопировать соответствующие файлы в
.git/objectsповрежденного репозитория, сохранив структуру каталогов.
Важно:
Такой подход требует аккуратности и понимания внутренней структуры Git. Если вы не уверены, лучше создать новый репозиторий, импортировать туда код и по возможности восстановить историю через патчи.
Связка git fsck и git gc
Команда git gc (garbage collect) отвечает за:
- упаковку свободных объектов в pack-файлы;
- удаление недостижимых объектов, которые старше определенного возраста.
Как они связаны с git fsck:
git fsckпомогает диагностировать проблемы до запускаgit gc;- если у вас есть полезные dangling-объекты (например, "потерянные" коммиты), лучше сначала их найти и сохранить;
- после агрессивного
git gc --prune=nowмногие dangling и unreachable объекты будут полностью уничтожены.
Поэтому разумная стратегия:
- При малейшем подозрении на потерю истории:
- сразу запускать
git fsck; - использовать
--lost-foundдля сохранения подозрительных объектов.
- сразу запускать
- Только после этого — запускать
git gc(если это вообще необходимо).
Как проверять удаленный репозиторий
Иногда вы хотите проверить не только локальный клон, но и сам удаленный репозиторий. Например, если у вас есть bare-репозиторий на сервере.
Там вы можете:
cd /path/to/bare-repo.git
git fsck --full
Если репозиторий "голый" (bare), структура та же, только нет рабочей директории.
В случае хостингов (GitHub, GitLab, Bitbucket):
- обычно у них есть внутренние проверки целостности;
- но вы можете дополнительно убедиться, сделав новый клон и прогнав
git fsckуже на нем.
Заключение
Команда git fsck — это ваш инструмент диагностики внутреннего состояния репозитория. Она:
- проверяет целостность объектов и соответствие их содержимого хешу;
- анализирует связность графа коммитов, деревьев, тегов и blob-объектов;
- помогает находить висячие, недостижимые, отсутствующие и поврежденные объекты;
- часто становится последним рубежом при попытке восстановить "потерянную" историю.
Смотрите, на практике важно:
- не пугаться
danglingиunreachable— это часто нормальные временные объекты; - очень внимательно относиться к сообщениям
missingиcorrupt— они говорят о реальной потере данных; - перед агрессивной чисткой (
git gc --prune) использоватьgit fsckи по возможности сохранить нужные объекты; - помнить, что наличие живого и целого удаленного репозитория почти всегда спасает ситуацию — новый клон часто проще любых "ремонтов" поврежденного
.git.
Когда вы понимаете, как git fsck видит ваш репозиторий изнутри, становится гораздо легче объяснять любые странности в истории, а также уверенно выполнять операции, которые потенциально меняют структуру коммитов.
Частозадаваемые технические вопросы по теме и ответы
Вопрос 1. Можно ли автоматически запускать git fsck в CI и есть ли смысл
Да, можно. Часто в больших компаниях делают периодическую проверку репозиториев. Пример для CI job:
# Запускаем подробную проверку
git fsck --full --strict
Если команда вернет ненулевой код возврата (есть ошибки), pipeline можно пометить как failed и отправить уведомления. Смысл есть для критичных репозиториев, где важна гарантия целостности (инфраструктура, финансы, безопасность).
Вопрос 2. Как посмотреть, какие ветки или теги ссылаются на поврежденный объект
Сначала фиксируем хеш проблемного объекта из вывода git fsck, затем выполняем:
git for-each-ref --contains <hash> --format="%(refname)"
Эта команда покажет все ссылки (ветки, теги), в истории которых присутствует этот объект. Так вы поймете, какие части истории затронуты повреждением.
Вопрос 3. Как отличить нормальные dangling объекты от действительно опасных
Полезно просмотреть несколько dangling-коммитов:
git fsck --no-reflogs --full
# затем для каждого dangling commit:
git show <hash>
Если вы видите там старые версии коммитов после rebase или amend, и эти версии давно не используются, их можно игнорировать. Если же внутри dangling-коммитов есть важные изменения, которых нет в ветках или тегах, создайте для них ветки, чтобы не потерять их при git gc.
Вопрос 4. Почему git fsck иногда показывает разные результаты на двух клонах одного репозитория
Причины обычно такие:
- разный набор reflog-записей (локальная история перемещений HEAD и веток);
- локальные незапушенные ветки и теги в одном клоне;
- разные запуски
git gc, которые уже удалили часть недостижимых объектов.
Если вы хотите максимально "сопоставимые" результаты, запускайте в обоих клонах:
git fsck --no-reflogs --unreachable --full
Так влияние reflog будет минимальным.
Вопрос 5. Можно ли ограничить проверку только частью истории или отдельной веткой
Да. Вместо проверки всех ссылок вы можете запустить git fsck только для reachable объектов из конкретного коммита или ветки. Для этого сначала создайте временную ссылку:
git update-ref refs/tmp/check <hash_или_ветка>
git fsck
git update-ref -d refs/tmp/check
Git будет считать объекты, достижимые из refs/tmp/check, частью проверяемого графа. Так вы можете локализовать проверку, если вас интересует конкретная ветка или диапазон истории.
Постройте личный план изучения Git до уровня Middle — бесплатно!
Git — часть карты развития Frontend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Бесплатные лекции
Все гайды по Git
Лучшие курсы по теме

Основы Git
Антон Ларичев
TypeScript с нуля
Антон Ларичев