我在git filter-branch
之后忘记了rm refs/original
,而做了git gc
,这样就清除了refs
。我还提交了新的repo,并希望保留这些提交。
提取的分支的大小为几千字节,但.git
的权重仍然为80 MB,就像过滤之前一样。
现在refs
是空的,我不能轻易删除refs/original
了。我怎样才能去掉原件?如果可能的话,我希望避免再次使用filter-branch
。
您的refs被打包(git gc
运行git pack-refs
)。这对refs本身没有任何改变,除了将每个refs放在单独的文件中,它们都在"打包"文件中。
你只需要删除refs/origina/
参考。理论上,在每一行上使用git update-ref -d
应该可以工作,但如果有很多行,可能更容易在编辑器中打开.git/packed-refs
并手动删除所有refs/original/
行。
您可能还需要清除refflogs。
git gc
运行git pack-refs
如果你开始删除refs,请确保使用Git 2.24+ (Q3 2019):"git pack-refs
"可能会丢失在运行时创建的refs,这正在得到纠正。
见commit a613d4f (31 Jul 2019) by孙超(sunchao
)。
(由孙超—sunchao
—在commit a613d4f中合并,2019年8月2日)
pack-ref:总是在获取锁文件后刷新
当一个已打包的ref被删除时,整个已打包的ref文件将被重写以省略不再存在的ref。
但是,如果另一个gc
命令正在运行并同时调用pack-refs --all
,有可能刚刚更新的ref会丢失新创建的提交。通过这些步骤,可以演示在新更新的ref上丢失提交:
# step 1: compile git without `USE_NSEC` option
Some kernel releases do enable it by default while some do
not. And if we compile git without `USE_NSEC`, it will be easier
demonstrated by the following steps.
# step 2: setup a repository and add the first commit
git init repo &&
(cd repo &&
git config core.logallrefupdates true &&
git commit --allow-empty -m foo)
# step 3: in one terminal, repack the refs repeatedly
cd repo &&
while true
do
git pack-refs --all
done
# step 4: in another terminal, simultaneously update the
# master with update-ref, and create and delete an
# unrelated ref also with update-ref
cd repo &&
while true
do
us=$(git commit-tree -m foo -p HEAD HEAD^{tree}) &&
git update-ref refs/heads/newbranch $us &&
git update-ref refs/heads/master $us &&
git update-ref -d refs/heads/newbranch &&
them=$(git rev-parse master) &&
if test "$them" != "$us"
then
echo >&2 "lost commit: $us"
exit 1
fi
# eye candy
printf .
done
虽然我们有打包的refs锁文件和松散的refs锁文件来避免更新冲突,但如果
packed-refs
文件的统计有效性不正确,一个ref会丢失它的新提交。
最好的前进路径就是总是在获取packed-refs
文件的锁文件后刷新。