5

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 恢复的信息。我的下意识反应是 run git fetch,但返回时没有输出,因为它认为没有什么新东西要获取。

我试过 unpacking .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的提交的 id(恰好是)。HEAD^我是否正确假设此存储库中的最后两个提交是不可恢复的,我需要重新创建这些提交的内容?在这种情况下,我是否做出了正确的决定?

4

2 回答 2

8

尝试 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 提交没问题,那么您只是缺少历史记录,并且至少应该涵盖最近的状态。

于 2014-10-07T04:04:58.343 回答
2

所以我的假设是我只是缺少一些可以从 GitHub 恢复的信息。

通常是正确的,但如果您可以确定断开链接的确切来源,这将有所帮助。

这就是将提出 Git 2.10(2016 年第三季度)的内容:

git fsck --name-objects

请参阅Johannes Schindelin ( )的提交 90cf590提交 1cd772c提交 7b35efd提交 993a21b(2016 年 7 月 17 日) 。(由Junio C Hamano 合并——提交 9db3979中,2016 年 7 月 25 日)dscho
gitster

fsck:可选地显示更多有用的信息,以了解断开的链接

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


三年后,git fsck 在 Git 2.25(2020 年第一季度)中进行了重构:随着时间的推移,围绕对象解析和“git fsck”中使用的低级对象访问积累的粗糙代码和逻辑已被清理。

这反过来又修复了 fsck 如何装饰其条目。

See commit b2f2039 , commit c5b4269 , commit 103fb6d , commit f648ee7 , commit cc57900 , commit 7854399 , commit b8b00f1 , commit 6da40b2 , commit 3837025 , commit f597937 , commit 5afc4b1 , commit 82ef89b , commit 7339029 , commit d40bbc1 , commit a59cfb3 , commit 23a173a , commit 2175a0c提交 ec65231提交 1de6007提交 78d5014提交 12736d2提交 c78fe00(2019 年 10 月 18 日)和提交 228c78f(2019 年 10 月 25 日),由Jeff King ( peff)提交。
(由Junio C Hamano 合并gitster——提交 0e07c1c中,2019 年 12 月 1 日)

fsck: 统一对象名称代码

签字人:杰夫·金

提交90cf590f53 (" fsck: optional show more useful info for broken links", 2016-07-17, Git v2.10.0-rc0 -- merge列在批次 #7中) 添加了一个用于装饰对象名称的系统。代码分为builtin/fsck.c(给出初始名称)和fsck.c(在遍历对象图时添加到名称)。
这会导致一些重复,其中两个站点具有几乎相同describe_object()的功能(不同之处在于 inbuiltin/fsck.c使用缓冲区的循环数组以允许在单个 中进行多次调用printf)。

让我们object_namefsck.

这让我们可以放弃重复,并使接口边界更加清晰(这将使我们在未来的补丁中更多地重构实现)。

我们将作为新 API 的薄包装器留下describe_object()builtin/fsck.c因为它依赖于静态全局来使其许多调用者更短一些。

我们还将把裸add_decoration()调用转换builtin/fsck.cput_object_name().

这修复了两个小错误

  1. 我们泄漏了许多小字符串。add_decoration() 有一种最后一胜的方法:它将装饰更新为新字符串并返回旧字符串。但是我们忽略了返回值,泄漏了旧字符串。
    这很容易触发,因为我们查看 reflog:任何 ref 的尖端都将通过查看实际 ref 以及最新的 reflog 条目来描述。
    所以我们最终总是会泄漏其中一个字符串。

  2. 最后一胜的方法给了我们糟糕的名字。
    例如,我们首先查看所有 refs,然后查看所有 reflogs。因此,我们可能会用“”覆盖它,
    而不是看到“ ”。 我们通常最好使用我们找到的名字。refs/heads/masterHEAD@{12345678}

确实,t1450 中的测试期待这个丑陋的HEAD@{}名字。
在这个补丁之后,我们已经切换到使用fsck_put_object_name()'s first-one-wins 语义,并且我们输出更人性化的“ refs/tags/julius”(并且测试会相应地更新)。

于 2016-07-26T19:02:18.210 回答