git 什么时候修剪对象:为什么 "git gc" 不删除提交?
When exactly does git prune objects: why is "git gc" not removing commits?
我正在学习一门 git 课程,想提一下丢失的 ref 直到 运行 宁 git gc
才真正丢失。但是验证了一下,发现不是这样的。即使在 运行ning git gc --prune=all --aggressive
之后,丢失的 refs 仍然存在。
显然我误会了什么。在课程中说错话之前,我想弄清楚我的事实!这是一个示例脚本,说明了效果:
#!/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;
此脚本将添加 10 个虚拟提交,重置为过去的 5 个提交并添加另外 10 个提交。就在重置之前,它将打印当前 HEAD 的哈希值。
我期望在运行宁git gc --prune=all
之后丢失CURRENT
中的对象。然而,我仍然可以 运行 git show
在那个散列上。
我明白在 运行 宁 git reset
并添加新提交之后,我基本上创建了一个新分支。但是我的原始分支不再有任何引用,所以它不会出现在 git log --all
中。它也不会被推送到我想的任何远程。
我对 git gc
的理解是删除那些对象。好像不是这样。
为什么? 什么时候 git gc
删除对象?
对于要 p运行ed 的对象,它必须满足 两个 条件。一个是 date/time 相关的:它一定是在 1 之前足够长的时间创建的,可以收集了。 "long enough ago" 部分是您使用 --prune=all
设置的部分:您正在覆盖正常的 "at least two weeks old" 设置。
第二个标准是你的实验哪里出了问题。要被 p运行ed,对象必须 也 是 unreachable。作为 ,您的每个表面上被放弃的提交(以及它们相应的树和 blob)实际上都通过 Git 的 "reflog" 条目被引用。
每个这样的提交都有两个 reflog 条目:一个用于 HEAD
,另一个用于 HEAD
本身在提交时引用的分支名称(在本例中, refs/heads/master
的 reflog,即分支 master
)。每个 reflog 条目都有自己的时间戳,并且 git gc
也会为您使 reflog 条目过期,尽管与对象过期的简单“14 天”默认设置相比,规则集更复杂。2
因此,git gc
可以首先删除所有保留旧对象的reflog条目,然后 p运行e 对象。只是这里没有发生。
要手动查看甚至删除引用日志条目,请使用 git reflog
。请注意 git reflog
显示 由 运行ning git log
和 -g
/ --walk-reflogs
选项的条目(加上一些额外的显示格式化选项)。您可以 运行 git reflog --all --expire=all
清除所有内容,尽管在手术刀可能更合适的情况下这是一个大棒。使用 --expire-unreachable
以获得更多选择性。有关详细信息,请参阅 the git log
documentation and of course the git reflog
documentation。
1一些 Unix-y 文件系统根本不存储文件创建 ("birth") 时间:[=27] 的 st_ctime
字段=]结构是inode变化时间,不是创建时间。如果有创建时间,则在 st_birthtime
或 st_birthtimespec
.3 但是,每个 Git 对象都是只读的,因此文件的创建时间也是它的修改时间。因此 st_mtime
, 始终可用,给出对象的创建时间。
2确切的规则在the git gc
documentation中有描述,但我认为默认情况下,30天不可到达提交和90天可到达提交 是一个不错的总结。不过,这里 reachable 的定义是不寻常的:它意味着 可以从引用的当前值到达,该引用日志持有旧值。 那是,如果我们正在查看 master
的 reflog,我们会找到 master
标识的提交(例如,1234567
),然后查看 master
的每个 reflog 条目(例如,master@{27}
) 可以从那个特定的提交到达(再次1234567
)。
3这个特殊的名称混淆是由 POSIX 标准化人员给您带来的。 :-) st_birthtimespec
字段是一个 struct timespec
,它记录秒和纳秒。
我正在学习一门 git 课程,想提一下丢失的 ref 直到 运行 宁 git gc
才真正丢失。但是验证了一下,发现不是这样的。即使在 运行ning git gc --prune=all --aggressive
之后,丢失的 refs 仍然存在。
显然我误会了什么。在课程中说错话之前,我想弄清楚我的事实!这是一个示例脚本,说明了效果:
#!/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;
此脚本将添加 10 个虚拟提交,重置为过去的 5 个提交并添加另外 10 个提交。就在重置之前,它将打印当前 HEAD 的哈希值。
我期望在运行宁git gc --prune=all
之后丢失CURRENT
中的对象。然而,我仍然可以 运行 git show
在那个散列上。
我明白在 运行 宁 git reset
并添加新提交之后,我基本上创建了一个新分支。但是我的原始分支不再有任何引用,所以它不会出现在 git log --all
中。它也不会被推送到我想的任何远程。
我对 git gc
的理解是删除那些对象。好像不是这样。
为什么? 什么时候 git gc
删除对象?
对于要 p运行ed 的对象,它必须满足 两个 条件。一个是 date/time 相关的:它一定是在 1 之前足够长的时间创建的,可以收集了。 "long enough ago" 部分是您使用 --prune=all
设置的部分:您正在覆盖正常的 "at least two weeks old" 设置。
第二个标准是你的实验哪里出了问题。要被 p运行ed,对象必须 也 是 unreachable。作为
每个这样的提交都有两个 reflog 条目:一个用于 HEAD
,另一个用于 HEAD
本身在提交时引用的分支名称(在本例中, refs/heads/master
的 reflog,即分支 master
)。每个 reflog 条目都有自己的时间戳,并且 git gc
也会为您使 reflog 条目过期,尽管与对象过期的简单“14 天”默认设置相比,规则集更复杂。2
因此,git gc
可以首先删除所有保留旧对象的reflog条目,然后 p运行e 对象。只是这里没有发生。
要手动查看甚至删除引用日志条目,请使用 git reflog
。请注意 git reflog
显示 由 运行ning git log
和 -g
/ --walk-reflogs
选项的条目(加上一些额外的显示格式化选项)。您可以 运行 git reflog --all --expire=all
清除所有内容,尽管在手术刀可能更合适的情况下这是一个大棒。使用 --expire-unreachable
以获得更多选择性。有关详细信息,请参阅 the git log
documentation and of course the git reflog
documentation。
1一些 Unix-y 文件系统根本不存储文件创建 ("birth") 时间:[=27] 的 st_ctime
字段=]结构是inode变化时间,不是创建时间。如果有创建时间,则在 st_birthtime
或 st_birthtimespec
.3 但是,每个 Git 对象都是只读的,因此文件的创建时间也是它的修改时间。因此 st_mtime
, 始终可用,给出对象的创建时间。
2确切的规则在the git gc
documentation中有描述,但我认为默认情况下,30天不可到达提交和90天可到达提交 是一个不错的总结。不过,这里 reachable 的定义是不寻常的:它意味着 可以从引用的当前值到达,该引用日志持有旧值。 那是,如果我们正在查看 master
的 reflog,我们会找到 master
标识的提交(例如,1234567
),然后查看 master
的每个 reflog 条目(例如,master@{27}
) 可以从那个特定的提交到达(再次1234567
)。
3这个特殊的名称混淆是由 POSIX 标准化人员给您带来的。 :-) st_birthtimespec
字段是一个 struct timespec
,它记录秒和纳秒。