如何修复损坏的git存储库?

我把我的回购,我把我的Ubuntu的一个文件夹克隆到一台新的机器,我得到这个:

christopher@christopher-laptop:~/source/personal$ git clone ~/Ubuntu\ One\ Side\ Work/projects.git/ Cloning into 'projects'... done. fatal: unable to read tree 29a422c19251aeaeb907175e9b3219a9bed6c616 christopher@christopher-laptop:~/source/personal$ 

所以我试着看看这样的问题,其中大部分都是运行git fsck --full ,然后当我尝试的时候得到这个。

 christopher@christopher-laptop:~/Ubuntu One Side Work/projects.git$ git fsck --full Checking object directories: 100% (256/256), done. Checking objects: 100% (447/447), done. broken link from commit 235ae1f48701d577d71ebd430344a159e5ba4881 to commit 984c11abfc9c2839b386f29c574d9e03383fa589 broken link from tree 632a9cf0ef9fccea08438b574e2f1c954f4ff08b to blob 25a742dff0a403b2b3884f2ffddf63eb45721fac broken link from tree 632a9cf0ef9fccea08438b574e2f1c954f4ff08b to blob dd4e97e22e159a585b20e21028f964827d5afa4e broken link from tree 632a9cf0ef9fccea08438b574e2f1c954f4ff08b to tree 29a422c19251aeaeb907175e9b3219a9bed6c616 broken link from tree 632a9cf0ef9fccea08438b574e2f1c954f4ff08b to tree 8084e8e04d510cc28321f30a9646477cc50c235c broken link from tree 774b5b4157b4caae1c6cad96c8eaf5d4eba2c628 to blob a0daa0c1567b55d8de2b4d7a3bc010f58c047eab broken link from tree 774b5b4157b4caae1c6cad96c8eaf5d4eba2c628 to blob e9052d35bfb6d30065b206fc43f4200a04d5281b broken link from tree 774b5b4157b4caae1c6cad96c8eaf5d4eba2c628 to blob 1a3a5e4dd2502ac121c22f743c4250e254a94eeb broken link from tree 4aa336dc1a5838e8918e03b85580069d83f4ad09 to tree 8cc55ec952dc192a233e062201d1e7e873ac3db0 broken link from tree e5674a91a53e15575a1f3bf5786bc5cc719fb483 to blob 4a994e1e7bb7ce28dcec98bad48b9a891d7dec51 broken link from tree e5674a91a53e15575a1f3bf5786bc5cc719fb483 to blob ac033bf9dc846101320c96a5ce8aceb8c96ec098 broken link from tree 252ab84542264e1589576b6ee51e7a31e580a0e2 to tree 2069041cd5950e529e2991d37b7290ec021d90d4 broken link from tree 2d4964aa4d4f5d8c7228518ce72ef6a63f820c6d to blob d83690e1b9a6bdd8a08754b38231799acefcb2ab broken link from tree c7192e82fc581bd6448bda1a25e8729bdac5f4ff to blob 30d54d47ae82add1917ca173d42e58b396df580b broken link from tree 7c66306901fc71389623286936cef172d4ffe408 to blob bc7e05d705401273b1df4e939de0f540597c0931 broken link from tree 0940f5fd227d4c84d6e6749d872db50a4522ae3a to tree 923767594ac22023e824948d65622fe5b407d1a1 broken link from tree 8eadcd2a971e8357d24f0d80f993d2963452209f to blob 2598bde3dc8cb80ee49510b8159344004b88645f broken link from tree ffa302dd0d969172ef23caeefe856ab2f57a4e4d to blob d6925fa431be1ac585bf9a481e98f75107a6e6fb broken link from tree 7045b8870a49ce30a2027537a96d73d162bda773 to blob 25688652dea26f61f576ca1b52b9d1a18fbfd01d broken link from tree 37e4705d34bd440ce681ae32ae9a180a13256d72 to tree 246f564d4cee53339b8a4244f3173b61caa518eb missing blob d6925fa431be1ac585bf9a481e98f75107a6e6fb missing blob ac033bf9dc846101320c96a5ce8aceb8c96ec098 missing tree 29a422c19251aeaeb907175e9b3219a9bed6c616 missing tree 8084e8e04d510cc28321f30a9646477cc50c235c missing blob 30d54d47ae82add1917ca173d42e58b396df580b missing tree 8cc55ec952dc192a233e062201d1e7e873ac3db0 missing blob e9052d35bfb6d30065b206fc43f4200a04d5281b dangling tree 4b26e95db542c72ac4a22ec25abe38fb2de79752 missing blob d83690e1b9a6bdd8a08754b38231799acefcb2ab missing blob 25a742dff0a403b2b3884f2ffddf63eb45721fac missing tree 923767594ac22023e824948d65622fe5b407d1a1 missing blob 25688652dea26f61f576ca1b52b9d1a18fbfd01d missing blob 2598bde3dc8cb80ee49510b8159344004b88645f dangling tree 3a683869f1bb0c1634de75700c316b3b36570dbd dangling blob 4098d30843380d798a811f1aa9a02994f0dbbb27 missing tree 2069041cd5950e529e2991d37b7290ec021d90d4 missing blob 4a994e1e7bb7ce28dcec98bad48b9a891d7dec51 missing blob 1a3a5e4dd2502ac121c22f743c4250e254a94eeb missing blob a0daa0c1567b55d8de2b4d7a3bc010f58c047eab dangling tree 6c7b5162aa7a303fa3fe8dc393c5da564e309521 missing commit 984c11abfc9c2839b386f29c574d9e03383fa589 missing blob bc7e05d705401273b1df4e939de0f540597c0931 missing blob dd4e97e22e159a585b20e21028f964827d5afa4e missing tree 246f564d4cee53339b8a4244f3173b61caa518eb dangling commit a01f5c1e5315dc837203d6dee00d3493be9c5db9 

这看起来非常糟糕。 当我做一个git log | head git log | head我得到这个

 christopher@christopher-laptop:~/Ubuntu One Side Work/projects.git$ git log | head error: Could not read 984c11abfc9c2839b386f29c574d9e03383fa589 fatal: Failed to traverse parents of commit 235ae1f48701d577d71ebd430344a159e5ba4881 commit 2fb0d2d0643b445440f01b164f11ee9ee71fca48 Author: christopher <christopher@christopher.christopher> Date: Wed Aug 7 15:51:42 2013 -0400 finishing chapter 7 

这里的其他问题已经说了看./git/refs/heads/master 。 这是一个裸回购和refs/heads/存在,但refs/heads/master没有。 HEAD在光秃秃的回购说ref: refs/heads/master虽然

packed-refs确实这样说

 # pack-refs with: peeled 2fb0d2d0643b445440f01b164f11ee9ee71fca48 refs/heads/master 

还有其他问题build议运行git reflog ,当我运行时没有输出显示。

所以我真的不知道该怎么做。 应该采取什么策略? 是否有可能在8月7日将头部重置为最后一次提交

编辑:

做一个git日志,并进入屏幕输出的底部显示:

 commit 996e03b949aea176238e3c7a8452700bbb987ac9 Author: christopher <christopher@christopher> Date: Wed Jul 3 23:00:44 2013 -0400 many many changes error: Could not read 984c11abfc9c2839b386f29c574d9e03383fa589 fatal: Failed to traverse parents of commit 235ae1f48701d577d71ebd430344a159e5ba4881 

这似乎阻止了git prune的工作

TL; DR

Git并不像你想象的那样保存历史。 它基于祖先链计算运行时的历史。 如果您的祖先缺less斑点,树木或提交,那么您可能无法完全恢复您的历史。

从备份还原丢失的对象

您可以尝试的第一件事是从备份还原丢失的项目。 例如,查看是否有作为.git/objects/98/4c11abfc9c2839b386f29c574d9e03383fa589存储的提交的备份。 如果是这样,你可以恢复它。

你可能也想看看git-verify-pack和git-unpack-objects在提交已经被打包的情况下,并且你想把它放回一个松散的对象来进行仓库手术。

手术切除

如果您无法从备份中replace丢失的项目,则可以删除缺less的历史logging。 例如,您可能会检查您的历史logging或引用日志来查找提交984c11abfc9c2839b386f29c574d9e03383fa589的祖先。 如果你发现一个完整的,那么:

  1. 将你的Git工作目录复制到某个临时目录。
  2. 做一个硬重置到未损坏的提交。
  3. 将当前文件复制回Git工作树,但请确保不要复制.git文件夹!
  4. 提交当前的工作树,并尽最大努力将其视为所有缺失历史的压缩提交。

如果有效,你当然会失去干预的历史。 在这一点上,如果你有一个工作历史日志,那么修剪你的历史和所有不可访问的提交和对象的reflog是一个好主意。

完全恢复和重新初始化

如果您的存储库仍然损坏,那么希望您有一个可以恢复的未损坏的备份或克隆。 如果没有,但是你当前的工作目录包含有效的文件,那么你总是可以重新初始化Git。 例如:

 rm -rf .git git init git add . git commit -m 'Re-initialize repository without old history.' 

这是激烈的,但它可能是唯一的select,如果您的存储库的历史是真正不可恢复的。 因人而异。

如果你绝望,你可以试试这个:

 git clone ssh://me@my.git.server/path/to/project destination --depth=1 

它会得到你的数据,但你会失去历史。 我试了我的回购试验和错误,并且--depth=10工作,但是--depth=50给了我失败。

作为CodeGnome的最后一个选项的替代scheme,如果只有本地repo被破坏,并且您知道远程的url,则可以使用它来重新设置.git以匹配远程(将${url}replace${url}远程url ):

 mv -v .git .git_old && # remove old git git init && # initialise new repo git remote add origin "${url}" && # link to old repo git fetch && # get old history git reset origin/master --mixed # force update to old history 

这会使你的工作树完好无损,只会影响git的簿记。
最近我也为这个目的做了一个bash脚本 (附录A),这个操作包含了一点安全性。

注意:

如果你的repo有子模块,这个过程会把它搞乱,到目前为止唯一的解决scheme是删除它们,然后使用git submodule update --init (或者重新克隆回购,但是看起来激烈了) 。

附录A – 完整的脚本

 #!/bin/bash # Author: Zoey Llewellyn "Zobean" Hewll # # Usage: fix-git [REMOTE-URL] # If a remote is not supplied, it will be read from .git/config # # For when you have a corrupted local repo, but a trusted remote. # This script replaces all your history with that of the remote. # If there is a .git, it is backed up as .git_old, removing the last backup. # This does not affect your working tree. # # This does not currently work with submodules! # You will have to delete them first # and re-clone them after (with `git submodule update --init`) # This will abort if a suspected submodule is found # # Error codes: # 1: If a url is not supplied, and one cannot be read from .git/config # 4: If the url cannot be reached # 5: If a git submodule is detected if [[ "$(find -name .git -not -path ./.git | wc -l)" -gt 0 ]] ; then echo "It looks like this repo uses submodules" >&2 echo "You will need to remove them before this script can safely execute" >&2 echo "Then use \`git submodule update --init\` to re-clone them" >&2 exit 5 fi if [[ $# -ge 1 ]] ; then url="$1" else if ! url="$(git config --local --get remote.origin.url)" ; then echo "Unable to find remote 'origin': missing in '.git/config'" >&2 exit 1 fi fi url_base="$(echo "${url}" | sed -E 's;^([^/]*://)?([^/]*)(/.*)?$;\2;')" echo "Attempting to access ${url_base} before continuing" if ! wget -p "${url_base}" -O /dev/null -q --dns-timeout=5 --connect-timeout=5 ; then echo "Unable to reach ${url_base}: Aborting before any damage is done" >&2 exit 4 fi echo echo "This operation will replace the local repo with the remote at:" echo "${url}" echo echo "This will completely rewrite history," echo "but will leave your working tree intact" echo -n "Are you sure? (y/N): " read confirm if ! [ -t 0 ] ; # i'm open in a pipe then # print the piped input echo "${confirm}" fi if echo "${confirm}"|grep -Eq "[Yy]+([Ee]+[Ss]+)*" ; # it looks like a yes then if [[ -e .git ]] ; then # remove old backup rm -vrf .git_old | tail -n 1 && # backup .git iff it exists mv -v .git .git_old fi && git init && git remote add origin "${url}" && git config --local --get remote.origin.url | sed 's/^/Added remote origin at /' && git fetch && git reset origin/master --mixed else echo "Aborting without doing anything" fi 

我面临着同样的问题,所以我用备份的版本replace了“.git”文件夹,它仍然不能正常工作,因为.gitconfig文件已损坏。 我的笔记本电脑上的BSOD损坏了它。 我用下面的代码replace它,sourcetree恢复了我所有的存储库。

 [user] name = *your username* email = *your email address* [core] autocrlf = true excludesfile = C:\\Users\\*user name*\\Documents\\gitignore_global.txt 

我不知道这是否会帮助任何人,但这只是另一个解决scheme,为我工作。

如果你有一个远程configuration,你有/不关心丢失一些unpushed代码,你可以做:

 git fetch && git reset --hard 

你可以尝试在你的新机器上的克隆回购,如“ Git – 如何从缺less的blob恢复 ”:

 git reflog --all --expire=now git gc --prune=<date> 

用' now 'replace<date> ,然后回到8月7日,以删除对这些丢失的blob的引用。
但是这意味着放弃与这些承诺有关的工作。

对于同步文件夹(Ubuntu One),只存储一个包 ,而不是一个完整的回购。
一个包只是一个文件。

在我的情况下,我从源代码已经在我的电脑中创build存储库,并出现错误。 我删除了.git文件夹,并再次做了一切,它的工作:)

这里有一个脚本(bash),用于通过@CodeGnome自动执行第一个解决scheme,从备份中恢复(从损坏的回购的顶层运行)。 备份不需要完整,只需要有缺失的对象。

 git fsck 2>&1 | grep -e missing -e invalid | awk '{print $NF}' | sort -u | while read entry; do mkdir -p .git/objects/${entry:0:2} cp ${BACKUP}/objects/${entry:0:2}/${entry:2} .git/objects/${entry:0:2}/${entry:2} done 

在尝试本页所述的任何修复之前,我build议您制作一个副本,并仅在此副本上进行操作。 然后最后如果你能修复它,把它与原来的比较,以确保你没有在修复过程中丢失任何文件。

另一个替代我的工作是重置git头和索引到以前的状态使用:

git reset --keep

您也可以通过打开Git GUI并select每个“分阶段更改”并单击“Unstage the change”来手动执行相同操作。 当所有东西都暂停时,你现在应该能够压缩你的数据库,检查你的数据库并提交。

我也尝试了下面的命令,但是它们并不适合我,但是根据具体的问题,它们可能适合您:

 git reset --mixed git fsck --full git gc --auto git prune --expire now git reflog --all 

最后,为了避免这种同步损坏你的git索引的问题(DropBox,SpiderOak或任何其他云盘可能发生这种情况),可以执行以下操作:

  1. 通过使用: git bundle create my_repo.git --all把你的.git文件夹转换成一个“捆绑”的git文件 ,那么它应该和以前一样工作,但是因为一切都在一个文件中,所以你不会冒险同步损坏你的git回购了。
  2. 禁用即时同步 :SpiderOak允许您设置检查更改为“自动”(这意味着它是尽快监测文件更改,由于操作系统通知)的调度。 这是不好的,因为只要您正在进行更改,它就会开始上传更改,然后下载更改,这样可能会抹去刚才所做的最新更改。 解决此问题的一个解决scheme是将更改监视延迟设置为5分钟或更长时间。 这也解决了即时保存笔记应用程序(如Notepad ++)的问题。