When exactly does git prune objects: why is “git gc” not removing commits?

风格不统一 提交于 2019-12-03 12:40:00

For an object to be pruned, it must meet two criteria. One is date/time related: it must have been created1 long enough ago to be ripe for collection. The "long enough ago" part is what you are setting with --prune=all: you're overriding the normal "at least two weeks old" setting.

The second criterion is where your experiment is going wrong. To be pruned, the object must also be unreachable. As twalberg noted in a comment, each of your ostensibly-abandoned commits (and hence their corresponding trees and blobs) is actually referenced, through Git's "reflog" entries.

There are two reflog entries for each such commit: one for HEAD, and one for the branch name to which HEAD itself referred at the time the commit was made (in this case, the reflog for refs/heads/master, i.e., branch master). Each reflog entry has its own time-stamp, and git gc also expires reflog entries for you, although with a more complex set of rules than the simple "14 days" default for object expiry.2

Hence, git gc could first delete all reflog entries that are keeping the old object around, then prune the object. It just is not happening here.

To view, or even delete, reflog entries manually, use git reflog. Note that git reflog displays entries by running git log with the -g / --walk-reflogs option (plus some additional display formatting options). You can run git reflog --all --expire=all to clear everything out, though this is a bludgeon when a scalpel may be more appropriate. Use --expire-unreachable for a bit more selectivity. For more about this, see the git log documentation and of course the git reflog documentation.


1Some Unix-y file systems do not store file creation ("birth") time at all: the st_ctime field of a stat structure is the inode change time, not the creation time. If there is a creation time, it is in st_birthtime or st_birthtimespec.3 However, every Git object is read-only, so the file's creation time is also its modification time. Hence st_mtime, which is always available, gives the creation time for the object.

2The exact rules are described in the git gc documentation, but I think By default, 30 days for unreachable commits and 90 days for reachable commits is a decent summary. The definition of reachable here is unusual, though: it means reachable from the current value of the reference for which this reflog holds old values. That is, if we're looking at the reflog for master, we find the commit that master identifies (e.g., 1234567), then see if each reflog entry for master (e.g., master@{27}) is reachable from that particular commit (1234567 again).

3This particular name confusion is brought to you by the POSIX standardization folks. :-) The st_birthtimespec field is a struct timespec, which records both seconds and nanoseconds.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!