我正在开发一个git课程,并且想提一下,在跑步之前,丢失的裁判并没有真正丢失git gc.但验证这一点,我发现事实并非如此.即使在运行git gc --prune=all --aggressive丢失的裁判后仍然存在.
显然我误解了一些东西.在说出不正确的课程之前,我想直截了当地说明事实!这是一个示例脚本说明了效果:
#!/bin/bash
git init
# add 10 dummy commits
for i in {1..10}; do
date > foo.txt
git add foo.txt
git commit -m "bump" foo.txt
sleep 1
done;
CURRENT=$(git rev-parse HEAD)
echo HEAD before reset: ${CURRENT}
# rewind
git reset --hard HEAD~5
# add another 10 commits
for i in {1..10}; do
date > foo.txt
git add foo.txt
git commit -m "bump" foo.txt
sleep 1
done;
Run Code Online (Sandbox Code Playgroud)
这个脚本将添加10个虚拟提交,重置为过去的5个提交,并添加另外10个提交.在重置之前,它将打印它当前HEAD的哈希值.
我希望CURRENT在跑步后失去对象git gc --prune=all.然而,我仍然可以git show在那个哈希上运行.
我知道在运行git reset和添加新提交之后,我基本上创建了一个新分支.但我的原始分支不再有任何参考,所以它没有出现git log --all.它也不会被推到任何遥控器我想.
我的理解git gc是删除那些对象.似乎并非如此.
为什么?而当究竟git gc删除对象?
tor*_*rek 17
对于要修剪的对象,它必须符合两个标准.一个是相关的日期/时间:它必须已创建1足够长的时间以前是成熟的收藏."足够久以前"的部分就是你所设定的--prune=all:你正在压倒正常的"至少两周"的环境.
第二个标准是您的实验出错的地方.要修剪,对象也必须无法访问.正如twalberg在评论中指出的那样,通过Git的"reflog"条目实际引用了每个表面上被放弃的提交(以及它们相应的树和blob).
每个这样的提交有两个reflog条目:一个用于HEAD,一个用于HEAD在提交时自己引用的分支名称(在这种情况下,reflog用于refs/heads/master,即分支master).每个reflog条目都有自己的时间戳,并且git gc还会为您过期reflog条目,尽管规则的集合比对象到期的简单"14天"默认值更复杂.2
因此,git gc 可以先删除所有保留旧对象的reflog条目,然后修剪该对象.这不是发生在这里.
要手动查看甚至删除reflog条目,请使用git reflog.请注意,通过使用/ 选项运行来git reflog 显示条目(以及一些其他显示格式选项).你可以跑去清理所有东西,虽然这可能是一个大棒,当一把手术刀可能更合适.使用了多一点的选择性.想了解更多,请参阅的文件,当然该文档.git log-g--walk-reflogsgit reflog --all --expire=all--expire-unreachablegit loggit reflog
1某些Unix-y文件系统根本不存储文件创建("生成")时间:结构的st_ctime字段stat是inode更改时间,而不是创建时间.如果有创建时间,则为st_birthtime或st_birthtimespec.3 但是,每个Git对象都是只读的,因此文件的创建时间也是其修改时间.因此st_mtime,这是始终可用,给人的创建时间为对象.
2确切的规则中所描述的git gc文档,但我认为在默认情况下,30天为不可达的提交和可达提交90天是一个体面的摘要.但是,这里可达的定义是不寻常的:它意味着可以从此reflog包含旧值的引用的当前值到达. 也就是说,如果我们正在寻找的引用日志的master,我们发现触犯该master标识(例如1234567),然后看是否每个引用日志条目master(如master@{27})可达来自特定提交(1234567再次).
3这个特殊的名称混淆是由POSIX标准化人员带给你的.:-) st_birthtimespec字段是a struct timespec,记录秒和纳秒.