如何恢复HEAD ^树?

时间:2014-10-07 03:51:43

标签: git data-recovery git-fsck git-plumbing

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

我每次都遇到这个错误。 (请记住:它是--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^)的id。我是否正确假设此存储库中的最后两个提交是不可恢复的,我将需要重新创建这些提交的内容?我在这种情况下做出了正确的决定吗?

2 个答案:

答案 0 :(得分:6)

尝试使用git fetch-pack来恢复其他存储库中可用的丢失对象。以下说明。

为了恢复未被提交的提交,特别是HEAD ^ 1,我将从

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

您将获得已更改的所有树/ blob及其SHA(包括HEAD和HEAD ^ 1的更改)的列表。根据可用信息的数量,您可以重新创建所有缺失的树。但是,缺少blob更成问题。

使用git fetch-pack

故意破坏存储库

me@myvm:/scratch/corrupt/.git  (GIT_DIR!)$ cd objects/
me@myvm:/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
me@myvm:/scratch/corrupt/.git/objects  (GIT_DIR!)$ rm -rf 22

验证头部处于不良状态

me@myvm:/scratch/corrupt/.git/objects  (GIT_DIR!)$ cd ../../
me@myvm:/scratch/corrupt  (master)$ git status
fatal: bad object HEAD

恢复丢失的物品

me@myvm:/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
me@myvm:/scratch/corrupt  (master)$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

缺少对象恢复

me@myvm:/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
me@myvm:/scratch/corrupt  (master)$ 


me@myvm:/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将转储树,它会告诉您文件名和blob SHA。此时,您将尝试手动构造树并从可能的部分数据提交对象。如果你的HEAD提交没问题,那么你只缺少历史记录,至少应该覆盖最近的状态。

答案 1 :(得分:2)

  

所以我的假设是我只是遗漏了一些可以从GitHub中恢复的信息。

一般来说是正确的,但是如果您能够从中确定确切地说该断开的链接来自它,那将会有所帮助。

这就是Git 2.10(2016年第3季度)提出的建议:

git fsck --name-objects

commit 90cf590commit 1cd772ccommit 7b35efdcommit 993a21bJohannes Schindelin (dscho)(2016年7月17日)。{
(由Junio C Hamano -- gitster --合并于commit 9db3979,2016年7月25日)

  

fsck:可选择显示更多有用信息的链接

     

当“git fsck”报告链接断开(例如,树对象包含不存在的blob)时,包含对象和所引用对象的报告都以40-hex对象名称报告。登记/>   该命令学习了“--name-objects”选项,以显示现有引用中包含对象的路径(例如“HEAD~24^2:file.txt”)。