如何修复损坏的 git 存储库?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18678853/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to fix corrupted git repository?
提问by TinyGrasshopper
I tried cloning my repository which I keep on my Ubuntu one folder to a new machine and I got this:
我尝试将我保存在 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$
So I tried looking at the many other questions like this that have been asked here and most of them say to run git fsck --full
and then I get this when I try that.
因此,我尝试查看此处提出的许多其他类似问题,其中大多数人说要运行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
That looks really bad. When I do a git log | head
I get this
那看起来真的很糟糕。当我做一个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 <[email protected]>
Date: Wed Aug 7 15:51:42 2013 -0400
finishing chapter 7
Other questions here have said to look at ./git/refs/heads/master
. It's a bare repo and refs/heads/
exists but refs/heads/master
does not. HEAD in the bare repo says ref: refs/heads/master
though
其他问题这里有说看./git/refs/heads/master
。这是一个裸仓库,refs/heads/
存在但refs/heads/master
不存在。裸仓库中的 HEAD 说ref: refs/heads/master
虽然
packed-refs
does say this though
packed-refs
不过确实这么说
# pack-refs with: peeled
2fb0d2d0643b445440f01b164f11ee9ee71fca48 refs/heads/master
Still other questions have suggested running git reflog
and no output shows up when I run that.
还有其他问题建议运行git reflog
,当我运行时没有显示输出。
So I really have no idea what to do here. What strategy should be taken? Is it possible to reset head to this last commit on Aug 7
所以我真的不知道在这里做什么。应该采取什么策略?是否可以将 head 重置为 8 月 7 日的最后一次提交
EDIT:
编辑:
Doing a git log and going to the bottom of the screen output shows this:
执行 git log 并转到屏幕输出的底部显示以下内容:
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
That seems to be preventing the git prune from working
这似乎阻止了 git prune 工作
回答by Zoey Hewll
As an alternative to CodeGnome's last option, if only the local repo is corrupted, and you know the url to the remote, you can use this to re-set your .git
to match the remote (replacing ${url}
with the remote url):
作为 CodeGnome 的最后一个选项的替代方案,如果只有本地 repo 损坏,并且您知道远程的 url,您可以使用它来重新设置您的.git
以匹配远程(替换${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
This leaves your working tree intact, and only affects git's bookkeeping.
I also recently made a bash script for this very purpose(Appendix A), which wraps a bit of safety around this operation.
这会使您的工作树完好无损,并且只会影响 git 的簿记。
我最近也为此目的制作了一个 bash 脚本(附录 A),它为这个操作包装了一些安全性。
Note:
笔记:
If your repo has submodules, this process will mess them up somehow, and the only solution I've found so far is deleting them and then using git submodule update --init
(or re-cloning the repo, but that seems toodrastic).
如果你的仓库有子模块,这个过程会以某种方式把它们弄乱,到目前为止我发现的唯一解决方案是删除它们然后使用git submodule update --init
(或重新克隆仓库,但这似乎太激烈了)。
Appendix A - Full script
附录 A - 完整脚本
#!/bin/bash
# Author: Zoey Llewellyn "Zobean" Hewll
#
# Usage: fix-git [REMOTE-URL]
# Must be run from the root directory of the repository.
# 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!
# This will abort if a suspected submodule is found.
# You will have to delete them first
# and re-clone them after (with `git submodule update --init`)
#
# 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=""
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;^([^/]*://)?([^/]*)(/.*)?$;;')"
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]+[EeSs]*" ; # 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
回答by Todd A. Jacobs
TL;DR
TL; 博士
Git doesn't really store history the way you think it does. It calculateshistory at run-time based on an ancestor chain. If your ancestry is missing blobs, trees, or commits then you may not be able to fully recover your history.
Git 并没有像你想象的那样存储历史。它在运行时根据祖先链计算历史。如果您的祖先缺少斑点、树或提交,那么您可能无法完全恢复您的历史记录。
Restore Missing Objects from Backups
从备份中恢复丢失的对象
The first thing you can try is to restore the missing items from backup. For example, see if you have a backup of the commit stored as .git/objects/98/4c11abfc9c2839b386f29c574d9e03383fa589
. If so you can restore it.
您可以尝试的第一件事是从备份中恢复丢失的项目。例如,查看您是否将提交的备份存储为.git/objects/98/4c11abfc9c2839b386f29c574d9e03383fa589
. 如果是这样,您可以恢复它。
You may also want to look into git-verify-packand git-unpack-objectsin the event that the commit has already been packed up and you want to return it to a loose object for the purposes of repository surgery.
如果提交已经被打包并且您想将它返回到一个松散的对象以进行存储库手术,您可能还想查看git-verify-pack和git-unpack-objects。
Surgical Resection
手术切除
If you can't replace the missing items from a backup, you may be able to excise the missing history. For example, you might examine your history or reflog to find an ancestor of commit 984c11abfc9c2839b386f29c574d9e03383fa589. If you find one intact, then:
如果您无法从备份中替换丢失的项目,则可以删除丢失的历史记录。例如,您可以检查您的历史记录或 reflog 以查找提交 984c11abfc9c2839b386f29c574d9e03383fa589 的祖先。如果你发现一个完好无损,那么:
- Copy your Git working directory to a temporary directory somewhere.
- Do a hard reset to the uncorrupted commit.
- Copy your current files back into the Git work tree, but make sure you don't copy the .git folder back!
- Commit the current work tree, and do your best to treat it as a squashed commit of all the missing history.
- 将您的 Git 工作目录复制到某个地方的临时目录。
- 对未损坏的提交进行硬重置。
- 将您当前的文件复制回 Git 工作树,但请确保不要将 .git 文件夹复制回!
- 提交当前的工作树,并尽最大努力将其视为所有缺失历史记录的压缩提交。
If it works, you will of course lose the intervening history. At this point, if you have a working history log, then it's a good idea to prune your history and reflogs of all unreachable commits and objects.
如果它有效,你当然会失去中间的历史。在这一点上,如果您有一个工作历史日志,那么最好修剪所有无法访问的提交和对象的历史和引用日志。
Full Restores and Re-Initialization
完全恢复和重新初始化
If your repository is still broken, then hopefully you have an uncorrupted backup or clone you can restore from. If not, but your current working directory contains valid files, then you can always re-initialize Git. For example:
如果您的存储库仍然损坏,那么希望您有一个可以从中恢复的未损坏的备份或克隆。如果没有,但您当前的工作目录包含有效文件,那么您始终可以重新初始化 Git。例如:
rm -rf .git
git init
git add .
git commit -m 'Re-initialize repository without old history.'
It's drastic, but it may be your only option if your repository history is truly unrecoverable. YMMV.
这很严重,但如果您的存储库历史确实无法恢复,这可能是您唯一的选择。天啊。
回答by campkeith
Here's a script (bash) to automate the first solution by @CodeGnome to restore from a backup (run from the top level of the corrupted repo). The backup doesn't need to be complete, it only needs to have the missing objects.
这是一个脚本 (bash),用于自动执行 @CodeGnome 的第一个解决方案以从备份中恢复(从损坏的存储库的顶层运行)。备份不需要完整,它只需要包含丢失的对象。
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
回答by user5169648
If you have a remote configured and you have / don't care about losing some unpushed code, you can do :
如果您配置了遥控器并且您/不关心丢失一些未推送的代码,则可以执行以下操作:
git fetch && git reset --hard
回答by gaborous
Before trying any of the fixes described on this page, I would advise to make a copy of your repo and work on this copy only. Then at the end if you can fix it, compare it with the original to ensure you did not lose any file in the repair process.
在尝试此页面上描述的任何修复之前,我建议您制作一份您的存储库副本并仅在此副本上工作。然后最后如果可以修复,请与原始文件进行比较,以确保在修复过程中没有丢失任何文件。
Another alternative which worked for me was to reset the git head and index to its previous state using:
另一种对我有用的替代方法是使用以下方法将 git head 和 index 重置为其以前的状态:
git reset --keep
git reset --keep
You can also do the same manually by opening the Git GUI and selecting each "Staged changes" and click on "Unstage the change". When everything is unstaged, you should now be able to compress your database, check your database and commit.
您也可以通过打开 Git GUI 并选择每个“暂存更改”并单击“取消暂存更改”来手动执行相同操作。当一切都未暂存时,您现在应该能够压缩您的数据库,检查您的数据库并提交。
I also tried the following commands but they did not work for me, but they might for you depending on the exact issue you have:
我还尝试了以下命令,但它们对我不起作用,但它们可能适合您,具体取决于您遇到的确切问题:
git reset --mixed
git fsck --full
git gc --auto
git prune --expire now
git reflog --all
Finally, to avoid this problem of synchronization damaging your git index (which can happen with DropBox, SpiderOak, or any other cloud disk), you can do the following:
最后,为了避免这个同步损坏你的 git 索引的问题(这可能发生在 DropBox、SpiderOak 或任何其他云盘上),你可以执行以下操作:
- Convert your
.git
folder into a single "bundle" git fileby using:git bundle create my_repo.git --all
, then it should work just the same as before, but since everything is in a single file you won't risk the synchronization damaging your git repo anymore. - Disable instantaneous synchronization: SpiderOak allows you to set the scheduling for checking changes to "automatic" (which means that it is as soon as possible, being monitoring file changes thanks to the OS notifications). This is bad because it will start to upload changes as soon as you are doing a change, and then download the change, so it might erase the latest changes you were just doing. A solution to fix this issue is to set the changes monitoring delay to 5 minutes or more. This also fixes issues with instant saving note taking applications (such as Notepad++).
.git
使用:将您的文件夹转换为单个“捆绑”git 文件git bundle create my_repo.git --all
,然后它应该像以前一样工作,但是由于所有内容都在一个文件中,因此您不会再冒同步损坏您的 git 存储库的风险。- 禁用即时同步:SpiderOak 允许您将检查更改的调度设置为“自动”(这意味着它是尽快,由于操作系统通知正在监视文件更改)。这很糟糕,因为它会在您进行更改后立即开始上传更改,然后下载更改,因此它可能会删除您刚刚进行的最新更改。解决此问题的解决方案是将更改监控延迟设置为 5 分钟或更长时间。这也解决了即时保存笔记应用程序(例如 Notepad++)的问题。
回答by alberto56
If you are desperate you can try this:
如果你很绝望,你可以试试这个:
git clone ssh://[email protected]/path/to/project destination --depth=1
It will get your data, but you'll lose the history. I went with trial and error on my repo and --depth=10
worked, but --depth=50
gave me failure.
它会获取您的数据,但您会丢失历史记录。我对我的回购进行了反复试验并成功了--depth=10
,但--depth=50
失败了。
回答by AspiringCanadian
I was facing the same issue, so I replaced the ".git" folder with a backed up version and it still wasn't working because .gitconfig file was corrupted. The BSOD on my laptop corrupted it. I replaced it with the following code and sourcetree restored all my repositories.
我遇到了同样的问题,所以我用备份版本替换了“.git”文件夹,但它仍然无法工作,因为 .gitconfig 文件已损坏。我的笔记本电脑上的 BSOD 损坏了它。我用以下代码替换了它,sourcetree 恢复了我所有的存储库。
[user]
name = *your username*
email = *your email address*
[core]
autocrlf = true
excludesfile = C:\Users\*user name*\Documents\gitignore_global.txt
I don't know if this will help anybody, but this is just another solution that worked for me.
我不知道这是否会帮助任何人,但这只是另一种对我有用的解决方案。
回答by Carolina
In my case, I was creating the repository from source code already in my pc and that error appeared. I deleted the .git folder and did everything again and it worked :)
就我而言,我正在从我的电脑中已经存在的源代码创建存储库,并且出现了该错误。我删除了 .git 文件夹并再次执行了所有操作,并且成功了 :)
回答by AlejandroVD
I tried moving away the object files with 0 bytes and fetching them again from the remote, and it worked:
我尝试用 0 字节移开目标文件并从远程再次获取它们,并且它起作用了:
find . -type f -size 0 -exec mv {} /tmp \;
git fetch
It fetched the missing objects from the remote and allowed me to continue working without reinitializing the whole repo.
它从远程获取丢失的对象并允许我继续工作而无需重新初始化整个存储库。
回答by Gesthemene
I wanted to add this as a comment under Zoey Hewil's awesome answerabove, but I don't currently have enough rep to do so, so I have to add it here and give credit for her work :P
我想在 Zoey Hewil上面的精彩回答下添加这个作为评论,但我目前没有足够的代表来这样做,所以我必须在这里添加它并赞扬她的工作:P
If you're using Poshgit and are feeling exceptionallylazy, you can use the following to automatically extract your URL from your git config and make an easy job even easier. Standard caveats apply about testing this on a copy/backing up your local repo first in case it blows up in your face.
如果您正在使用 Poshgit 并且感觉特别懒惰,您可以使用以下命令从您的 git 配置中自动提取您的 URL,让工作变得更加轻松。标准警告适用于首先在副本/备份您的本地存储库上测试它,以防它在您面前爆炸。
$config = get-content .git\config
$url = $config -match " url = (?<content>.*)"
$url = $url.trim().Substring(6)
$url
move-item -v .git .git_old;
git init;
git remote add origin "$url";
git fetch;
git reset origin/master --mixed