fix(prune): reclaim merged branches and size the volume for the clone #21
@@ -278,15 +278,29 @@ the obvious order, because a snapshot is hardlinked to everything cloned from
|
|||||||
it, so removing one frees almost no real bytes while costing every future PR
|
it, so removing one frees almost no real bytes while costing every future PR
|
||||||
its warm start.
|
its warm start.
|
||||||
|
|
||||||
**A branch is dead in two ways, and the second is the one that reclaims
|
**A branch is dead in two ways, and neither signal makes the other
|
||||||
anything here.** Gitea keeps a PR's branch after the merge unless the repo
|
redundant.** The first is that the branch is gone from origin. The second is
|
||||||
opts into delete-on-merge, so `git ls-remote` reports merged branches forever
|
|
||||||
and "gone from origin" fires for almost nothing. The second signal is
|
|
||||||
ancestry: a branch still on origin whose tip is an ancestor of a protected
|
ancestry: a branch still on origin whose tip is an ancestor of a protected
|
||||||
branch's tip holds no commit that branch does not, so its cache will never be
|
branch's tip holds no commit that branch does not, so its cache will never be
|
||||||
read again and goes in the same pass. On zemyna's volume that is the
|
read again and goes in the same pass.
|
||||||
difference between reclaiming nothing and reclaiming a 40 GB directory per
|
|
||||||
merged PR (gitdan-actions#20).
|
**Turn delete-on-merge on** (`default_delete_branch_after_merge`, per repo) —
|
||||||
|
it is the setting this scheme is cheapest under, because a deleted branch is
|
||||||
|
decidable from `ls-remote` alone, with no checkout, no objects and no walk.
|
||||||
|
The ancestry signal is what covers the rest, and the rest is not a corner:
|
||||||
|
|
||||||
|
- **Every branch merged before the setting was turned on.** They stay on
|
||||||
|
origin forever; nothing retroactively deletes them. zemyna carried 48 of
|
||||||
|
them at the time the setting was enabled, and ancestry is the only thing
|
||||||
|
that reclaims a cache dir belonging to any of them.
|
||||||
|
- **Every merge the deletion declines or fails.** Gitea's delete is
|
||||||
|
best-effort and silent: it declines for a protected branch and for one
|
||||||
|
another open PR still uses, and an API merge that omits the flag — which
|
||||||
|
`tea pulls merge` does — simply never asks.
|
||||||
|
- **Repos that have not enabled it**, which is the default.
|
||||||
|
|
||||||
|
That is the difference between reclaiming nothing and reclaiming a 40 GB
|
||||||
|
directory per merged PR on a full volume (issue 20).
|
||||||
|
|
||||||
Ancestry is answered from the commits in the job's own checkout, so it is only
|
Ancestry is answered from the commits in the job's own checkout, so it is only
|
||||||
answered where they are there to answer it — and "cannot tell" is never folded
|
answered where they are there to answer it — and "cannot tell" is never folded
|
||||||
|
|||||||
@@ -46,10 +46,10 @@
|
|||||||
# empty a tree its owner may still restore under a live cache name. Its
|
# empty a tree its owner may still restore under a live cache name. Its
|
||||||
# fixture is an OLD directory renamed a moment ago — production's shape,
|
# fixture is an OLD directory renamed a moment ago — production's shape,
|
||||||
# and what lets it tell the two timestamps apart.
|
# and what lets it tell the two timestamps apart.
|
||||||
# 15. A MERGED-BUT-UNDELETED BRANCH IS DEAD TOO. This forge keeps branches
|
# 15. A MERGED-BUT-UNDELETED BRANCH IS DEAD TOO. A branch the forge did not
|
||||||
# after merge, so `ls-remote` reports them forever and scenario 1's
|
# delete at merge stays on `ls-remote` forever, so scenario 1's signal
|
||||||
# signal never fires for them — which is how three 40 GB caches sat on a
|
# never fires for it — which is how three 40 GB caches sat on a full
|
||||||
# full volume until somebody removed them by hand (gitdan-actions#20). A
|
# volume until somebody removed them by hand (gitdan-actions#20). A
|
||||||
# branch whose tip is an ancestor of a protected branch's tip is pruned
|
# branch whose tip is an ancestor of a protected branch's tip is pruned
|
||||||
# like a deleted one; an unmerged branch beside it is not.
|
# like a deleted one; an unmerged branch beside it is not.
|
||||||
# 16. AND "CANNOT TELL" IS STILL NOT DEATH, at both granularities: a branch
|
# 16. AND "CANNOT TELL" IS STILL NOT DEATH, at both granularities: a branch
|
||||||
@@ -314,7 +314,7 @@ assert_log "may still be evicting it" "the deferral gives its actual reason"
|
|||||||
|
|
||||||
echo
|
echo
|
||||||
echo "=== 15: a merged-but-undeleted branch is dead too ==="
|
echo "=== 15: a merged-but-undeleted branch is dead too ==="
|
||||||
# This forge keeps a PR's branch after the merge, so `ls-remote` reports it
|
# A branch the forge did not delete at merge, which `ls-remote` then reports
|
||||||
# forever. Built the way that happens: a branch merged into dev with a merge
|
# forever. Built the way that happens: a branch merged into dev with a merge
|
||||||
# commit, still pushed, beside one branched at the same point and NOT merged.
|
# commit, still pushed, beside one branched at the same point and NOT merged.
|
||||||
git="git -c user.email=t@t -c user.name=t -c commit.gpgsign=false"
|
git="git -c user.email=t@t -c user.name=t -c commit.gpgsign=false"
|
||||||
|
|||||||
@@ -28,8 +28,9 @@
|
|||||||
# removed UNCONDITIONALLY, not gated on free space. A directory for a
|
# removed UNCONDITIONALLY, not gated on free space. A directory for a
|
||||||
# branch nothing will build again is pure loss; waiting for disk pressure
|
# branch nothing will build again is pure loss; waiting for disk pressure
|
||||||
# to notice means paying for it until then. Two signals make a branch
|
# to notice means paying for it until then. Two signals make a branch
|
||||||
# dead, and the second exists because the first alone is inert on a forge
|
# dead, and the second exists because the first alone is inert wherever
|
||||||
# that keeps branches after merge (gitdan-actions#20):
|
# a merged branch stays on origin — the default, and still the outcome
|
||||||
|
# whenever delete-on-merge declines or is not asked (gitdan-actions#20):
|
||||||
#
|
#
|
||||||
# DELETED — the branch is no longer on origin at all.
|
# DELETED — the branch is no longer on origin at all.
|
||||||
# MERGED — the branch is still on origin, but its tip is an ancestor
|
# MERGED — the branch is still on origin, but its tip is an ancestor
|
||||||
@@ -434,8 +435,11 @@ fi
|
|||||||
#
|
#
|
||||||
# True when the branch this directory belongs to is still on origin but every
|
# True when the branch this directory belongs to is still on origin but every
|
||||||
# commit it holds is already on a protected branch — a merged PR whose branch
|
# commit it holds is already on a protected branch — a merged PR whose branch
|
||||||
# the forge did not delete, which is the case zemyna hits on every merge and
|
# the forge did not delete, which the deleted-branch signal above can never
|
||||||
# which the deleted-branch signal above can never see.
|
# see. Enabling delete-on-merge narrows this to the branches merged before it
|
||||||
|
# was enabled, the ones its deletion declines (protected, or used by another
|
||||||
|
# open PR), and the merges that never ask (an API merge without the flag);
|
||||||
|
# see README's eviction section.
|
||||||
#
|
#
|
||||||
# Memoised per tip because target-<key> and snapshot-<key> share one branch,
|
# Memoised per tip because target-<key> and snapshot-<key> share one branch,
|
||||||
# and because the "cannot tell" warning belongs to the branch rather than to
|
# and because the "cannot tell" warning belongs to the branch rather than to
|
||||||
|
|||||||
Reference in New Issue
Block a user