Как я могу восстановить HEAD ^ дерево?

tl; dr: можно восстановить дерево HEAD^, если оно удалено и не было нажато заранее, и если все остальное не повреждено?

Я случайно удалил часть своего .git. Я не совсем уверен, чего не хватает.

Узнав, что git push не работает, я запустил git fsck:

Checking object directories: 100% (256/256), done.
Checking objects: 100% (1265/1265), done.
broken link from  commit f3419f630546ba02baf43f4ca760b02c0f4a0e6d
              to    tree 29616dfefd2bff59b7fb3177e99b4a1efc7132fa
broken link from  commit ccfe9502e24d2b5195008005d83155197a2dca25
              to    tree 0580c3675560cbfd3f989878a9524e35f53f08e9
broken link from  commit ccfe9502e24d2b5195008005d83155197a2dca25
              to  commit 0bca9b3a9f1dd9106922f5b4ec59cdc00dd6c049
broken link from    tree 6d33d35870281340c7c2f86c6d48c8f133b836bb
              to    blob 226d8a10a623acd943bb8eddd080a5929f3ccb2c
broken link from  commit db238d4a52ee8f18a04c038809bc6587d7643438
              to    tree 0b69ab3f6940a04684ee8c0c423ae7da89de749c
missing tree 0580c3675560cbfd3f989878a9524e35f53f08e9
dangling commit 05512f9ac09d932e7d9a11d490c8a2f117c0ca11
missing tree 29616dfefd2bff59b7fb3177e99b4a1efc7132fa
dangling commit 578464dde7d7b8628f77e536b4076cfa491d7602
missing blob 5d351b568abb734605ca4bf446e13cfd87ca9ce8
missing tree 0b69ab3f6940a04684ee8c0c423ae7da89de749c
missing commit 0bca9b3a9f1dd9106922f5b4ec59cdc00dd6c049
dangling blob d53a9d0f3364b648edbc4beede022e4594a84c35
missing blob 23db34f729a88c5f5f7fe6e281921f1334f493d1
dangling commit 8dcbde55462ca0c29e0ca339a49db95b43188ef1
dangling blob e59b25b9675625d0e6b8abfa37e955ab46493fd9
missing blob 226d8a10a623acd943bb8eddd080a5929f3ccb2c
dangling commit 85fdaaa579cf1ae2a8874e3e1f3c65d68b478179
dangling commit 075e9d72e90cc8bf3d960edd8376aaae0847f916
missing blob 83fec2ff8cfcaaa06c96917b6973ace96301e932
dangling commit a88e18e1c102d909361738fd70137b3f4a1c7496
dangling blob 9c6f61e0acffe2a1f5322cd2b72c181e95e9de75
dangling commit ca9fe0dd3123a731fc310b2a2285b00ef673de79

Итак, мое предположение заключается в том, что я просто пропускаю некоторую информацию, которую можно восстановить из GitHub. Моя реакция на коленный рефлекс заключалась в том, чтобы запустить git fetch, но он возвращается без вывода, потому что он не считает, что ничего нового не приносит.

Я попробовал распаковать .git/objects/pack/pack-ea43d1db155e4502c2250ec1d4608843715c8b1f.pack несколько способов, но он никогда не работал. Например:

% git clone --mirror git://github.com/strugee/dots.git # returns bare repo
Cloning into bare repository 'dots.git'...
remote: Counting objects: 1331, done.
remote: Compressing objects: 100% (23/23), done.
remote: Total 1331 (delta 12), reused 0 (delta 0)
Receiving objects: 100% (1331/1331), 402.31 KiB | 197.00 KiB/s, done.
Resolving deltas: 100% (454/454), done.
Checking connectivity... done.
% ls dots.git
config  description  HEAD  hooks  info  objects  packed-refs  refs
% mkdir git-tmp; cd git-tmp
% git init
% git unpack-objects < ../dots.git/objects/pack/pack-ea43d1db155e4502c2250ec1d4608843715c8b1f.pack
error: inflate: data stream error (incorrect data check)
error: inflate returned -3

Я получал эту ошибку каждый раз. (Имейте в виду: это a --mirror, так что это точная копия того, что GitHub имеет - правильно? Как это могло быть повреждено тогда?)

В конце концов я понял, что мне действительно не нужно распаковывать пакетный файл. Я мог бы просто скопировать его обратно в исходное репо, и Git подберет его просто отлично. Итак:

% cd ../configs
% cp ../dots.git/objects/pack/pack-ea43d1db155e4502c2250ec1d4608843715c8b1f.* .git/objects/pack/

И это, казалось, делало трюк. Главным образом.

% git fsck
Checking object directories: 100% (256/256), done.
Checking objects: 100% (2596/2596), done.
broken link from  commit db238d4a52ee8f18a04c038809bc6587d7643438
              to    tree 0b69ab3f6940a04684ee8c0c423ae7da89de749c
dangling commit 05512f9ac09d932e7d9a11d490c8a2f117c0ca11
dangling commit 578464dde7d7b8628f77e536b4076cfa491d7602
missing blob 5d351b568abb734605ca4bf446e13cfd87ca9ce8
missing tree 0b69ab3f6940a04684ee8c0c423ae7da89de749c
dangling blob d53a9d0f3364b648edbc4beede022e4594a84c35
dangling commit 8dcbde55462ca0c29e0ca339a49db95b43188ef1
dangling commit 85fdaaa579cf1ae2a8874e3e1f3c65d68b478179
dangling commit 075e9d72e90cc8bf3d960edd8376aaae0847f916
missing blob 83fec2ff8cfcaaa06c96917b6973ace96301e932
dangling commit a88e18e1c102d909361738fd70137b3f4a1c7496
dangling commit ca9fe0dd3123a731fc310b2a2285b00ef673de79

Как вы можете видеть, исправлено все, кроме одного, отсутствующего. Как оказалось, db238d - это идентификатор фиксации (который бывает HEAD^), который я еще не нажал. Правильно ли я предполагаю, что последние два фиксации в этом репозитории неустранимы, и мне нужно будет воссоздать содержимое этих коммитов? Я принял правильные решения в этом сценарии?

Ответ 1

Попробуйте git fetch -pack для восстановления отсутствующих объектов, доступных из другого репозитория. Инструкции ниже.

Для восстановления нечистых коммитов, в частности HEAD ^ 1, я начинал с

git diff-tree -r HEAD~2^{tree} HEAD^{tree}

Вы получите список всех измененных деревьев /blobs и их SHA (которые будут включать изменения от HEAD и HEAD ^ 1). В зависимости от того, сколько информации доступно, вы можете воссоздать часть отсутствующего дерева. Однако недостающие капли более проблематичны.

Использование git fetch-pack

Умышленно поврежденный репозиторий

[email protected]:/scratch/corrupt/.git  (GIT_DIR!)$ cd objects/
[email protected]:/scratch/corrupt/.git/objects  (GIT_DIR!)$ ll
total 20
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:03 20
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:03 22
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:03 25
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:03 info
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:03 pack
[email protected]:/scratch/corrupt/.git/objects  (GIT_DIR!)$ rm -rf 22

Проверить головку в плохом состоянии

[email protected]:/scratch/corrupt/.git/objects  (GIT_DIR!)$ cd ../../
[email protected]:/scratch/corrupt  (master)$ git status
fatal: bad object HEAD

восстановить отсутствующие объекты

[email protected]:/scratch/corrupt  (master)$ git fetch-pack --all $(git config --get remote.origin.url)
error: refs/heads/master does not point to a valid object!
error: refs/remotes/origin/HEAD does not point to a valid object!
error: refs/remotes/origin/master does not point to a valid object!
error: refs/heads/master does not point to a valid object!
error: refs/remotes/origin/HEAD does not point to a valid object!
error: refs/remotes/origin/master does not point to a valid object!
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
22ecde746be79c65b27a5cf1dc421764d8ff6e17 HEAD
22ecde746be79c65b27a5cf1dc421764d8ff6e17 refs/heads/master
[email protected]:/scratch/corrupt  (master)$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

отсутствующие объекты восстановлены

[email protected]:/scratch/corrupt  (master)$ ll .git/objects/
total 20
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:03 20
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:05 22
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:03 25
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:03 info
drwxrwxr-x 2 andrewc warp 4096 Oct  7 06:03 pack
[email protected]:/scratch/corrupt  (master)$ 


[email protected]:/scratch/corrupt  (master)$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

Если вы попадете в состояние, в котором вы можете найти сломанный древовидный объект и сломанный объект blob, вы можете вручную восстановить их. Вы можете git cat-file -p BLOB_SHA для любого blob, это сбрасывает содержимое. Если вы можете выяснить, просматривая содержимое, что этот файл может помочь вам восстановить файл. Аналогично git cat-file -p TREE_SHA будет выгружать дерево, в котором будут указаны имена файлов и SHAP. На этом этапе вы попытаетесь вручную построить дерево и перенести объекты из предположительно частичных данных. Если ваша запись HEAD завершена, вам просто не хватает истории и, по крайней мере, нужно иметь последнее состояние.

Ответ 2

Итак, мое предположение заключается в том, что я просто пропускаю некоторую информацию, которую можно восстановить из GitHub.

Как правило, это правда, но это помогает, если вы можете определить, откуда именно находится эта неработающая ссылка.

Вот что предложит Git 2.10 (Q3 2016):

git fsck --name-objects

См. commit 90cf590, commit 1cd772c, commit 7b35efd, commit 993a21b (17 июля 2016 г.) Йоханнес Шинделин (dscho).
(слияние Junio ​​C Hamano - gitster - в commit 9db3979, 25 июля 2016 г.

fsck: необязательно показать более полезную информацию для неработающих ссылок

Когда "git fsck" сообщает о некорректной ссылке (например, в дереве-объекте содержится blob, который не существует), как содержащий объект, так и объект, на который ссылаются, были отправлены с именами объектов с 40 шестью. Команда узнала опцию "--name-objects", чтобы показать путь к содержащему объекту из существующих ссылок (например, "HEAD~24^2:file.txt" ).