it-swarm.com.de

Wie kann man Git-Objekte wiederherstellen, die durch einen Festplattenfehler beschädigt wurden?

Ich habe einen Festplattenfehler gehabt, der dazu geführt hat, dass einige Dateien eines Git-Repositorys beschädigt wurden. Beim Ausführen von git fsck --full erhalte ich folgende Ausgabe:

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

Ich habe Sicherungen des Repositorys, aber die einzige Sicherung, die die Packdatei enthält, hat diese bereits beschädigt. Ich denke, dass ich einen Weg finden muss, die einzelnen Objekte aus verschiedenen Sicherungen abzurufen, und Git irgendwie anweisen, ein neues Pack nur mit korrekten Objekten zu erstellen.

Können Sie mir bitte Hinweise geben, wie ich mein Repository reparieren kann?

88
Christian

In einigen früheren Sicherungen wurden Ihre fehlerhaften Objekte möglicherweise in andere Dateien gepackt oder sind noch lose Objekte. So können Ihre Objekte wiederhergestellt werden.

Es scheint, dass sich in Ihrer Datenbank einige fehlerhafte Objekte befinden. Sie können es also manuell tun.

Da git hash-object, git mktree und git commit-tree die Objekte nicht schreiben, da sie im Pack gefunden werden, beginnen Sie folgendermaßen:

mv .git/objects/pack/* <somewhere>
for i in <somewhere>/*.pack; do
  git unpack-objects -r < $i
done
rm <somewhere>/*

(Ihre Pakete werden aus dem Repository verschoben und erneut entpackt; nur die guten Objekte befinden sich jetzt in der Datenbank.)

Du kannst tun:

git cat-file -t 6c8cae4994b5ec7891ccb1527d30634997a978ee

und überprüfen Sie den Typ des Objekts.

Wenn der Typ blob ist: Rufen Sie den Inhalt der Datei aus vorherigen Sicherungen ab (mit git show oder git cat-file oder git unpack-file; dann können Sie git hash-object -w verwenden, um das Objekt in Ihr aktuelles Repository zu schreiben.

Wenn der Typ Baum ist: Sie können git ls-tree verwenden, um den Baum von vorherigen Sicherungen wiederherzustellen. dann git mktree, um es erneut in Ihr aktuelles Repository zu schreiben.

Wenn der Typ "Festschreiben" ist, gilt Folgendes: git show, git cat-file und git commit-tree.

Natürlich würde ich Ihre ursprüngliche Arbeitskopie sichern, bevor Sie diesen Vorgang starten.

Schauen Sie sich auch an So stellen Sie ein beschädigtes Blob-Objekt wieder her .

81
Daniel Fanjul

Banengusk brachte mich auf die richtige Spur. Zur weiteren Bezugnahme möchte ich die Schritte bekanntgeben, die ich unternommen habe, um die Repository-Beschädigung zu beheben. Ich hatte das Glück, alle benötigten Objekte entweder in älteren Packs oder in Repository-Backups zu finden.

# 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!
38
Christian

Probieren Sie zunächst die folgenden Befehle aus (ggf. erneut ausführen):

$ git fsck --full
$ git gc
$ git gc --Prune=today
$ git fetch --all
$ git pull --rebase

Und dann hast du noch die Probleme, probiere es:

  • entfernen Sie alle beschädigten Objekte, z.

    fatal: loose object 91c5...51e5 (stored in .git/objects/06/91c5...51e5) is corrupt
    $ rm -v .git/objects/06/91c5...51e5
    
  • entfernen Sie alle leeren Objekte, z.

    error: object file .git/objects/06/91c5...51e5 is empty
    $ find .git/objects/ -size 0 -exec rm -vf "{}" \;
    
  • Überprüfen Sie die Nachricht "Defekter Link" durch:

    git ls-tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8
    

    Hier erfahren Sie, aus welcher Datei der beschädigte Blob stammt!

  • um die Datei wiederherzustellen, können Sie wirklich Glück haben und es ist möglicherweise die Version, die Sie bereits in Ihrem Arbeitsbaum ausgecheckt haben:

    git hash-object -w my-magic-file
    

    wieder und wenn es die fehlende SHA1 (4b945 ..) ausgibt, sind Sie jetzt fertig!

  • angenommen, es war eine ältere Version, die defekt war, ist der einfachste Weg, dies zu tun:

    git log --raw --all --full-history -- subdirectory/my-magic-file
    

    daraufhin wird das gesamte Protokoll für diese Datei angezeigt (bitte beachten Sie, dass der Baum, den Sie zuvor hatten, möglicherweise nicht der oberste Baum ist. Sie müssen also selbst herausfinden, in welchem ​​Unterverzeichnis es sich befand). Nun können Sie den fehlendes Objekt mit Hash-Objekt wieder.

  • um eine Liste aller Refs mit fehlenden Commits, Bäumen oder Blobs zu erhalten:

    $ git for-each-ref --format='%(refname)' | while read ref; do git rev-list --objects $ref >/dev/null || echo "in $ref"; done
    

    Es ist möglicherweise nicht möglich, einige dieser Verweise mit den regulären Verzweigungs -d- oder Tag -d-Befehlen zu entfernen, da sie sterben, wenn git die Beschädigung bemerkt. Verwenden Sie also stattdessen den Installationsbefehl git update-ref -d $ ref. Beachten Sie, dass dieser Befehl bei lokalen Verzweigungen in .git/config eine veraltete Zweigkonfiguration hinterlassen kann. Sie kann manuell gelöscht werden (siehe Abschnitt [Zweig "$ ref"]).

  • Nachdem alle Refs sauber sind, kann es im reflog noch gebrochene Commits geben. Sie können alle Wiederherstellungen löschen, indem Sie git reflog auslaufen lassen --expire = now --all. Wenn Sie nicht alle Ihre Reflogs verlieren möchten, können Sie die einzelnen Refs nach defekten Reflogs durchsuchen:

    $ (echo HEAD; git for-each-ref --format='%(refname)') | while read ref; do git rev-list -g --objects $ref >/dev/null || echo "in $ref"; done
    

    (Beachten Sie die hinzugefügte Option -g für git rev-list.) Verwenden Sie dann git reflog expire --expire = jetzt $ ref für jeden dieser .. .. Wenn alle defekten Refs und Reflogs weg sind, führen Sie git fsck --full aus um zu überprüfen, ob das Repository sauber ist. Baumelnde Objekte sind in Ordnung.


Im Folgenden finden Sie eine erweiterte Verwendung von Befehlen, die möglicherweise zum Verlust Ihrer Daten in Ihrem git-Repository führen können, wenn sie nicht sinnvoll verwendet werden. Machen Sie daher ein Backup, bevor Sie versehentlich weitere Schäden an Ihrem git verursachen. Versuchen Sie es auf eigene Gefahr, wenn Sie wissen, was Sie tun.


So ziehen Sie den aktuellen Zweig nach dem Abrufen auf den vorgelagerten Zweig:

$ git pull --rebase

Sie können auch versuchen, einen neuen Zweig auszuchecken und den alten zu löschen:

$ git checkout -b new_master Origin/master

Führen Sie den folgenden Befehl aus, um das beschädigte Objekt in git zum Entfernen zu finden:

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

Verwenden Sie für OSX sed -E anstelle von sed -r.


Eine andere Idee ist, alle Objekte aus Packdateien zu entpacken, um alle Objekte in .git/objects neu zu generieren. Versuchen Sie daher, die folgenden Befehle in Ihrem Repository auszuführen:

$ 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

Wenn oben nichts hilft, können Sie versuchen, die Git-Objekte aus einem anderen Repo zu synchronisieren oder zu kopieren, z.

$ 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

So beheben Sie den beschädigten Zweig beim Auschecken:

$ git checkout -f master
fatal: unable to read tree 5ace24d474a9535ddd5e6a6c6a1ef480aecf2625

Versuchen Sie es erneut zu entfernen und aus dem Upstream zu überprüfen:

$ git branch -D master
$ git checkout -b master github/master

Falls Sie mit git in den freistehenden Zustand versetzt werden, checken Sie die Variable master aus und fügen Sie den abgetrennten Zweig ein.


Eine andere Idee ist, den vorhandenen Master rekursiv zu rebasieren:

$ git reset HEAD --hard
$ git rebase -s recursive -X theirs Origin/master

Siehe auch:

15
kenorb

Hier sind die Schritte, die ich befolgt habe, um ein beschädigtes Blob-Objekt wiederherzustellen.

1) Identifizieren Sie einen beschädigten Blob

git fsck --full
  error: inflate: data stream error (incorrect data check)
  error: sha1 mismatch 241091723c324aed77b2d35f97a05e856b319efd
  error: 241091723c324aed77b2d35f97a05e856b319efd: object corrupt or missing
  ...

Der beschädigte Blob ist 241091723c324aed77b2d35f97a05e856b319efd

2) Bringen Sie den beschädigten Blob an einen sicheren Ort (nur für den Fall)

mv .git/objects/24/1091723c324aed77b2d35f97a05e856b319efd ../24/

3) Holen Sie sich Elternteil von korrupten Blobs

git fsck --full
  Checking object directories: 100% (256/256), done.
  Checking objects: 100% (70321/70321), done.
  broken link from    tree 0716831e1a6c8d3e6b2b541d21c4748cc0ce7180
              to    blob 241091723c324aed77b2d35f97a05e856b319efd

Der übergeordnete Hash ist 0716831e1a6c8d3e6b2b541d21c4748cc0ce7180 .

4) Holen Sie den Dateinamen entsprechend dem beschädigten Blob

git ls-tree 0716831e1a6c8d3e6b2b541d21c4748cc0ce7180
  ...
  100644 blob 241091723c324aed77b2d35f97a05e856b319efd    dump.tar.gz
  ...

Suchen Sie diese bestimmte Datei in einem Backup oder im Upstream-git-Repository (in meinem Fall dump.tar.gz). Dann kopieren Sie es irgendwo in Ihr lokales Repository. 

5) Fügen Sie eine zuvor beschädigte Datei in die git-Objektdatenbank ein

git hash-object -w dump.tar.gz

6) Feiern Sie!

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)
2
Jonathan Maim

Im Folgenden finden Sie zwei Funktionen, die hilfreich sein können, wenn Ihre Sicherung beschädigt ist oder Sie einige teilweise beschädigte Sicherungen haben (dies kann passieren, wenn Sie die beschädigten Objekte sichern).

Führen Sie beide im Repo aus, das Sie wiederherstellen möchten.

Standardwarnung: Nur verwenden, wenn Sie wirklich verzweifelt sind und Ihr (beschädigtes) Repo gesichert haben. Dies löst möglicherweise nichts auf, sollte aber zumindest den Grad der Korruption hervorheben.

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

und

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
1
go2null

Git Checkout kann tatsächlich einzelne Dateien aus einer Revision heraussuchen. Geben Sie einfach den Commit-Hash und den Dateinamen an. Genauere Infos hier.

Ich denke, der einfachste Weg, dieses Problem sicher zu beheben, besteht darin, auf das neueste, nicht festgeschriebene Backup zurückzugreifen und anschließend unbeschädigte Dateien aus neueren Commits auszuwählen. Viel Glück!

1
Tim Lin

Ich habe dieses Problem behoben, um einige Änderungen wie git add -A und git commit erneut hinzuzufügen.

0
Dmitriy S