Как восстановить объекты Git, поврежденные в результате сбоя жесткого диска?
-
03-07-2019 - |
Вопрос
У меня произошел сбой жесткого диска, в результате которого были повреждены некоторые файлы репозитория Git.При запуске git fsck --full
Я получаю следующий результат:
error: .git/objects/pack/pack-6863e0a0e4b4ded6090fac5d12eba6ca7346b19c.pack SHA1 checksum mismatch
error: index CRC mismatch for object 6c8cae4994b5ec7891ccb1527d30634997a978ee from .git/objects/pack/pack-6863e0a0e4b4ded6090fac5d12eba6ca7346b19c.pack at offset 97824129
error: inflate: data stream error (invalid code lengths set)
error: cannot unpack 6c8cae4994b5ec7891ccb1527d30634997a978ee from .git/objects/pack/pack-6863e0a0e4b4ded6090fac5d12eba6ca7346b19c.pack at offset 97824129
error: inflate: data stream error (invalid stored block lengths)
error: failed to read object 0dcf6723cc69cc7f91d4a7432d0f1a1f05e77eaa at offset 276988017 from .git/objects/pack/pack-6863e0a0e4b4ded6090fac5d12eba6ca7346b19c.pack
fatal: object 0dcf6723cc69cc7f91d4a7432d0f1a1f05e77eaa is corrupted
У меня есть резервные копии репозитория, но единственная резервная копия, включающая файл pack, уже повреждена.Поэтому я думаю, что мне нужно найти способ извлекать отдельные объекты из разных резервных копий и каким-то образом проинструктировать Git создать новый пакет только с правильными объектами.
Не могли бы вы, пожалуйста, дать мне подсказки, как исправить мой репозиторий?
Решение
В некоторых предыдущих резервных копиях ваши поврежденные объекты, возможно, были упакованы в другие файлы или еще оставались незакрепленными объектами.Таким образом, ваши объекты могут быть восстановлены.
Похоже, в вашей базе данных есть несколько плохих объектов.Таким образом, вы могли бы сделать это вручную.
Из - за git hash-object
, git mktree
и git commit-tree
не записывайте объекты, потому что они находятся в пакете, затем начните делать это:
mv .git/objects/pack/* <somewhere>
for i in <somewhere>/*.pack; do
git unpack-objects -r < $i
done
rm <somewhere>/*
(Ваши пакеты будут удалены из хранилища и снова распакованы в нем;теперь в базе данных есть только хорошие объекты)
Вы можете сделать:
git cat-file -t 6c8cae4994b5ec7891ccb1527d30634997a978ee
и проверьте тип объекта.
Если тип является blob:извлеките содержимое файла из предыдущих резервных копий (с помощью git show
или git cat-file
или git unpack-file
;тогда вы можете git hash-object -w
чтобы переписать объект в вашем текущем репозитории.
Если тип - дерево:вы могли бы использовать git ls-tree
чтобы восстановить дерево из предыдущих резервных копий;тогда git mktree
чтобы записать его снова в ваш текущий репозиторий.
Если тип является commit:то же самое с git show
, git cat-file
и git commit-tree
.
Конечно, я бы сделал резервную копию вашей оригинальной рабочей копии, прежде чем начинать этот процесс.
Кроме того, взгляните на Как восстановить поврежденный Blob-объект.
Другие советы
Баненгуск это наставляло меня на правильный путь.Для дополнительной справки я хочу опубликовать шаги, которые я предпринял, чтобы исправить повреждение моего репозитория.Мне посчастливилось найти все необходимые объекты либо в старых пакетах, либо в резервных копиях репозитория.
# Unpack last non-corrupted pack
$ mv .git/objects/pack .git/objects/pack.old
$ git unpack-objects -r < .git/objects/pack.old/pack-012066c998b2d171913aeb5bf0719fd4655fa7d0.pack
$ git log
fatal: bad object HEAD
$ cat .git/HEAD
ref: refs/heads/master
$ ls .git/refs/heads/
$ cat .git/packed-refs
# pack-refs with: peeled
aa268a069add6d71e162c4e2455c1b690079c8c1 refs/heads/master
$ git fsck --full
error: HEAD: invalid sha1 pointer aa268a069add6d71e162c4e2455c1b690079c8c1
error: refs/heads/master does not point to a valid object!
missing blob 75405ef0e6f66e48c1ff836786ff110efa33a919
missing blob 27c4611ffbc3c32712a395910a96052a3de67c9b
dangling tree 30473f109d87f4bcde612a2b9a204c3e322cb0dc
# Copy HEAD object from backup of repository
$ cp repobackup/.git/objects/aa/268a069add6d71e162c4e2455c1b690079c8c1 .git/objects/aa
# Now copy all missing objects from backup of repository and run "git fsck --full" afterwards
# Repeat until git fsck --full only reports dangling objects
# Now garbage collect repo
$ git gc
warning: reflog of 'HEAD' references pruned commits
warning: reflog of 'refs/heads/master' references pruned commits
Counting objects: 3992, done.
Delta compression using 2 threads.
fatal: object bf1c4953c0ea4a045bf0975a916b53d247e7ca94 inconsistent object length (6093 vs 415232)
error: failed to run repack
# Check reflogs...
$ git reflog
# ...then clean
$ git reflog expire --expire=0 --all
# Now garbage collect again
$ git gc
Counting objects: 3992, done.
Delta compression using 2 threads.
Compressing objects: 100% (3970/3970), done.
Writing objects: 100% (3992/3992), done.
Total 3992 (delta 2060), reused 0 (delta 0)
Removing duplicate objects: 100% (256/256), done.
# Done!
Сначала попробуйте выполнить следующие команды (при необходимости выполните еще раз).:
$ git fsck --full
$ git gc
$ git gc --prune=today
$ git fetch --all
$ git pull --rebase
И потом, у вас все еще есть проблемы, попробуйте, может:
удалите все поврежденные объекты, например
fatal: loose object 91c5...51e5 (stored in .git/objects/06/91c5...51e5) is corrupt $ rm -v .git/objects/06/91c5...51e5
удалите все пустые объекты, например
error: object file .git/objects/06/91c5...51e5 is empty $ find .git/objects/ -size 0 -exec rm -vf "{}" \;
проверьте сообщение "неработающая ссылка" с помощью:
git ls-tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8
Это сообщит вам, из какого файла был получен поврежденный большой двоичный объект!
возможно, вам действительно повезет восстановить файл, и это может быть версия, которую вы уже проверили в своем рабочем дереве:
git hash-object -w my-magic-file
опять же, и если он выводит отсутствующий SHA1 (4b945 ..), теперь все готово!
предполагая, что это была какая-то более старая версия, которая была сломана, самый простой способ сделать это - сделать:
git log --raw --all --full-history -- subdirectory/my-magic-file
и это покажет вам весь журнал для этого файла (пожалуйста, поймите, что дерево, которое у вас было, может не быть деревом верхнего уровня, поэтому вам нужно самостоятельно выяснить, в каком подкаталоге оно находилось), тогда теперь вы можете снова воссоздать отсутствующий объект с помощью hash-object .
чтобы получить список всех ссылок с отсутствующими коммит, деревьями или большими объектами:
$ git for-each-ref --format='%(refname)' | while read ref; do git rev-list --objects $ref >/dev/null || echo "in $ref"; done
Возможно, будет невозможно удалить некоторые из этих ссылок с помощью обычных команд branch -d или tag -d, поскольку они исчезнут, если git заметит повреждение.Поэтому вместо этого используйте команду git update-ref -d $ref .Обратите внимание, что в случае локальных ветвей эта команда может оставить устаревшую конфигурацию ветви в файле .git/config.Его можно удалить вручную (найдите раздел [ветка "$ref"]).
После того, как все ссылки будут очищены, в рефлоге все еще могут быть нарушенные коммиты.Вы можете очистить все рефлоги, используя git reflog expire --expire=now --all.Если вы не хотите потерять все свои рефлоги, вы можете выполнить поиск поврежденных рефлогов по отдельным ссылкам:
$ (echo HEAD; git for-each-ref --format='%(refname)') | while read ref; do git rev-list -g --objects $ref >/dev/null || echo "in $ref"; done
(Обратите внимание на добавленную опцию -g в git rev-list .) Затем используйте git reflog expire --expire=now $ref для каждого из них.Когда все неработающие ссылки и рефлоги исчезнут, запустите git fsck --full, чтобы проверить, что репозиторий чист.Болтающиеся предметы - это нормально.
Ниже вы можете ознакомиться с расширенным использованием команд, которые потенциально могут привести к потере ваших данных в вашем репозитории git, если их использовать неразумно, поэтому сделайте резервную копию, прежде чем случайно нанесете дальнейший ущерб вашему git.Попробуйте на свой страх и риск, если вы знаете, что делаете.
Чтобы вытащить текущую ветвь поверх вышестоящей ветви после выборки:
$ git pull --rebase
Вы также можете попробовать оформить заказ в новой ветке и удалить старую:
$ git checkout -b new_master origin/master
Чтобы найти поврежденный объект в git для удаления, попробуйте выполнить следующую команду:
while [ true ]; do f=`git fsck --full 2>&1|awk '{print $3}'|sed -r 's/(^..)(.*)/objects\/\1\/\2/'`; if [ ! -f "$f" ]; then break; fi; echo delete $f; rm -f "$f"; done
Для OSX используйте sed -E
вместо того, чтобы sed -r
.
Другая идея состоит в том, чтобы распаковать все объекты из файлов пакета, чтобы повторно создать все объекты внутри .git/objects, поэтому попробуйте выполнить следующие команды в вашем репозитории:
$ cp -fr .git/objects/pack .git/objects/pack.bak
$ for i in .git/objects/pack.bak/*.pack; do git unpack-objects -r < $i; done
$ rm -frv .git/objects/pack.bak
Если вышесказанное не помогло, вы можете попробовать выполнить rsync или скопировать объекты git из другого репозитория, например
$ rsync -varu git_server:/path/to/git/.git local_git_repo/
$ rsync -varu /local/path/to/other-working/git/.git local_git_repo/
$ cp -frv ../other_repo/.git/objects .git/objects
Чтобы исправить сломанную ветку при попытке оформления заказа, выполните следующие действия:
$ git checkout -f master
fatal: unable to read tree 5ace24d474a9535ddd5e6a6c6a1ef480aecf2625
Попробуйте удалить его и снова оформить заказ из восходящего потока:
$ git branch -D master
$ git checkout -b master github/master
В случае, если git переведет вас в обособленное состояние, проверьте master
и сольем в него отделившуюся ветку.
Другая идея состоит в том, чтобы рекурсивно перебазировать существующий мастер:
$ git reset HEAD --hard
$ git rebase -s recursive -X theirs origin/master
Смотрите также:
- Несколько приемов восстановления больших двоичных объектов, чтобы исправить поврежденный репозиторий.
- Как исправить сломанный репозиторий?
- Как удалить все неработающие ссылки из репозитория?
- Как исправить поврежденный репозиторий git?(см. ссылки)
- Как исправить поврежденный репозиторий git?(кундрум)
- Ошибка при использовании SourceTree с Git:Ошибка 'Summary' с кодом 128:фатальный:не удается прочитать дерево
- Восстановить Поврежденный репозиторий Git Bare
- Восстановление поврежденного репозитория git
- Как исправить ошибку git:объект поврежден
- Как диагностировать и исправить git fatal:не удается прочитать дерево
- Как справиться с этой ошибкой git
- Как исправить поврежденный репозиторий git?
- Как мне "перезаписать", а не "объединить" ветку с другой веткой в Git?
- Как полностью заменить главную ветку в git из другой ветки?
- Мерзавец:"Поврежденный незакрепленный предмет"
- Сброс Git = фатальный:не удается прочитать дерево
Вот шаги, которые я выполнил для восстановления из поврежденного blob-объекта.
1) Идентифицировать поврежденный большой двоичный объект
git fsck --full
error: inflate: data stream error (incorrect data check)
error: sha1 mismatch 241091723c324aed77b2d35f97a05e856b319efd
error: 241091723c324aed77b2d35f97a05e856b319efd: object corrupt or missing
...
Поврежденный сгусток - это 241091723c324aed77b2d35f97a05e856b319efd
2) Переместите поврежденный большой двоичный объект в безопасное место (на всякий случай).
mv .git/objects/24/1091723c324aed77b2d35f97a05e856b319efd ../24/
3) Получить родительский элемент поврежденного большого двоичного объекта
git fsck --full
Checking object directories: 100% (256/256), done.
Checking objects: 100% (70321/70321), done.
broken link from tree 0716831e1a6c8d3e6b2b541d21c4748cc0ce7180
to blob 241091723c324aed77b2d35f97a05e856b319efd
Родительский хэш равен 0716831e1a6c8d3e6b2b541d21c4748cc0ce7180.
4) Получаем имя файла, соответствующее поврежденному большому двоичному объекту
git ls-tree 0716831e1a6c8d3e6b2b541d21c4748cc0ce7180
...
100644 blob 241091723c324aed77b2d35f97a05e856b319efd dump.tar.gz
...
Найдите этот конкретный файл в резервной копии или в вышестоящем репозитории git (в моем случае это dump.tar.gz).Затем скопируйте его куда-нибудь внутри вашего локального репозитория.
5) Добавьте ранее поврежденный файл в базу данных объектов git
git hash-object -w dump.tar.gz
6) Празднуйте!
git gc
Counting objects: 75197, done.
Compressing objects: 100% (21805/21805), done.
Writing objects: 100% (75197/75197), done.
Total 75197 (delta 52999), reused 69857 (delta 49296)
Git checkout действительно может выбирать отдельные файлы из редакции.Просто дайте ему хэш фиксации и имя файла.Более подробная информация вот.
Я думаю, что самый простой способ безопасно исправить это - вернуться к самой новой незафиксированной резервной копии, а затем выборочно выбирать неповрежденные файлы из более новых коммитов.Удачи вам!
Вот две функции, которые могут помочь, если ваша резервная копия повреждена или у вас также есть несколько частично поврежденных резервных копий (это может произойти, если вы создаете резервные копии поврежденных объектов).
Запустите оба в репозитории, который вы пытаетесь восстановить.
Стандартное предупреждение:используйте только в том случае, если вы действительно в отчаянии и создали резервную копию своего (поврежденного) репозитория.Возможно, это ничего не решит, но, по крайней мере, должно подчеркнуть уровень коррупции.
fsck_rm_corrupted() {
corrupted='a'
while [ "$corrupted" ]; do
corrupted=$( \
git fsck --full --no-dangling 2>&1 >/dev/null \
| grep 'stored in' \
| sed -r 's:.*(\.git/.*)\).*:\1:' \
)
echo "$corrupted"
rm -f "$corrupted"
done
}
if [ -z "$1" ] || [ ! -d "$1" ]; then
echo "'$1' is not a directory. Please provide the directory of the git repo"
exit 1
fi
pushd "$1" >/dev/null
fsck_rm_corrupted
popd >/dev/null
и
unpack_rm_corrupted() {
corrupted='a'
while [ "$corrupted" ]; do
corrupted=$( \
git unpack-objects -r < "$1" 2>&1 >/dev/null \
| grep 'stored in' \
| sed -r 's:.*(\.git/.*)\).*:\1:' \
)
echo "$corrupted"
rm -f "$corrupted"
done
}
if [ -z "$1" ] || [ ! -d "$1" ]; then
echo "'$1' is not a directory. Please provide the directory of the git repo"
exit 1
fi
for p in $1/objects/pack/pack-*.pack; do
echo "$p"
unpack_rm_corrupted "$p"
done
Я решил эту проблему, добавив некоторые изменения, такие как git add -A и git commit снова.