v0.4.0 failed to mirror. The PAT scope was one cause and is fixed out of band;
this is the other one, which was not about #66 and would have failed at every
future release regardless.
What actually happened
On a tag-triggered run, actions/checkout materializes refs/tags/<tag> as a lightweight tag at the commit SHA — the annotated tag object Gitea holds is
never fetched. So:
run 2070 (mirror-github.yml@refs/tags/v0.4.0, head_sha = d2caa6d) pushed a lightweightv0.4.0 to GitHub and reported success
run 2076, on main with fetch-depth: 0, fetched the real annotated object
and was rejected with already exists trying to correct it — git will not clobber
an existing tag
v0.4.0 pointed at
Gitea
e138eeb — annotated tag object
GitHub
d2caa6d — the commit itself (lightweight)
The already exists line reads like harmless "tag is already there" noise. It was
not: the two remotes genuinely disagreed about what v0.4.0 was.
The fix
Re-fetch canonical tag objects from Gitea before pushing.
--force rewrites local tag refs only. It is not a force push and does not
weaken the deliberate non-force guarantee on main documented at the top of the
file — that push is untouched. The flag is required, not defensive: without it the
fetch is rejected with would clobber existing tag and the lightweight ref
survives to be mirrored again.
Verification
Against a scratch clone, simulating what checkout produces:
BEFORE fetch : d2caa6d… type=commit <- lightweight, what was being mirrored
t [tag update] v0.4.0 -> v0.4.0
AFTER fetch : e138eeb… type=tag <- annotated
peels to : d2caa6d… <- same commit, as expected
And without --force, confirming it is load-bearing:
YAML parses; triggers (push on main and v*) are unchanged.
Note on ordering
The GitHub tag was repaired by hand out of band, so the two remotes already agree
and v0.4.0 is annotated on both. Nothing on r-universe is affected — both refs
resolve to the same commit, so the published 0.4.0 does not rebuild.
Merging this pushes main, which triggers the mirror — that run is the real
end-to-end test of both fixes together. GitHub main is currently 2 commits
behind at d2caa6d; a green run should leave it at this branch's merge commit.
`v0.4.0` failed to mirror. The PAT scope was one cause and is fixed out of band;
this is the other one, which was **not** about #66 and would have failed at every
future release regardless.
## What actually happened
On a tag-triggered run, `actions/checkout` materializes `refs/tags/<tag>` as a
**lightweight** tag at the commit SHA — the annotated tag object Gitea holds is
never fetched. So:
- run **2070** (`mirror-github.yml@refs/tags/v0.4.0`, `head_sha = d2caa6d`) pushed a
*lightweight* `v0.4.0` to GitHub and reported success
- run **2076**, on `main` with `fetch-depth: 0`, fetched the *real* annotated object
and was rejected with `already exists` trying to correct it — git will not clobber
an existing tag
| | `v0.4.0` pointed at |
|---|---|
| Gitea | `e138eeb` — annotated tag object |
| GitHub | `d2caa6d` — the commit itself (lightweight) |
The `already exists` line reads like harmless "tag is already there" noise. It was
not: the two remotes genuinely disagreed about what `v0.4.0` was.
## The fix
Re-fetch canonical tag objects from Gitea before pushing.
`--force` rewrites **local** tag refs only. It is not a force push and does not
weaken the deliberate non-force guarantee on `main` documented at the top of the
file — that push is untouched. The flag is required, not defensive: without it the
fetch is rejected with `would clobber existing tag` and the lightweight ref
survives to be mirrored again.
## Verification
Against a scratch clone, simulating what checkout produces:
```
BEFORE fetch : d2caa6d… type=commit <- lightweight, what was being mirrored
t [tag update] v0.4.0 -> v0.4.0
AFTER fetch : e138eeb… type=tag <- annotated
peels to : d2caa6d… <- same commit, as expected
```
And without `--force`, confirming it is load-bearing:
```
! [rejected] v0.4.0 -> v0.4.0 (would clobber existing tag)
result: d2caa6d… type=commit <- unchanged
```
YAML parses; triggers (`push` on `main` and `v*`) are unchanged.
## Note on ordering
The GitHub tag was repaired by hand out of band, so the two remotes already agree
and `v0.4.0` is annotated on both. Nothing on r-universe is affected — both refs
resolve to the same commit, so the published 0.4.0 does not rebuild.
Merging this pushes `main`, which triggers the mirror — that run is the real
end-to-end test of both fixes together. GitHub `main` is currently 2 commits
behind at `d2caa6d`; a green run should leave it at this branch's merge commit.
v0.4.0 failed to mirror, and it would have failed at every future release.
On a tag-triggered run, checkout materializes refs/tags/<tag> as a LIGHTWEIGHT
tag at the commit SHA; the annotated tag object Gitea holds is never fetched.
Run 2070 therefore pushed a lightweight v0.4.0 to GitHub and reported success.
Run 2076, on main with fetch-depth 0, did fetch the real annotated object and
was rejected with "already exists" trying to correct it -- git will not clobber
an existing tag. Gitea had e138eeb (annotated), GitHub had d2caa6d (the commit).
Re-fetch canonical tag objects from Gitea before pushing. --force rewrites LOCAL
tag refs only; it is not a force push and does not weaken the non-force
guarantee on main. It is required: without it the fetch is rejected with "would
clobber existing tag" and the lightweight ref survives to be mirrored again.
Verified against a scratch clone -- lightweight d2caa6d becomes annotated
e138eeb, peeling back to the same commit; without --force the tag is unchanged.
The GitHub tag was repaired by hand out of band, so the two remotes already
agree; this stops it recurring.
jared
merged commit f7c606984f into main2026-08-11 10:03:44 -04:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
v0.4.0failed to mirror. The PAT scope was one cause and is fixed out of band;this is the other one, which was not about #66 and would have failed at every
future release regardless.
What actually happened
On a tag-triggered run,
actions/checkoutmaterializesrefs/tags/<tag>as alightweight tag at the commit SHA — the annotated tag object Gitea holds is
never fetched. So:
mirror-github.yml@refs/tags/v0.4.0,head_sha = d2caa6d) pushed alightweight
v0.4.0to GitHub and reported successmainwithfetch-depth: 0, fetched the real annotated objectand was rejected with
already existstrying to correct it — git will not clobberan existing tag
v0.4.0pointed ate138eeb— annotated tag objectd2caa6d— the commit itself (lightweight)The
already existsline reads like harmless "tag is already there" noise. It wasnot: the two remotes genuinely disagreed about what
v0.4.0was.The fix
Re-fetch canonical tag objects from Gitea before pushing.
--forcerewrites local tag refs only. It is not a force push and does notweaken the deliberate non-force guarantee on
maindocumented at the top of thefile — that push is untouched. The flag is required, not defensive: without it the
fetch is rejected with
would clobber existing tagand the lightweight refsurvives to be mirrored again.
Verification
Against a scratch clone, simulating what checkout produces:
And without
--force, confirming it is load-bearing:YAML parses; triggers (
pushonmainandv*) are unchanged.Note on ordering
The GitHub tag was repaired by hand out of band, so the two remotes already agree
and
v0.4.0is annotated on both. Nothing on r-universe is affected — both refsresolve to the same commit, so the published 0.4.0 does not rebuild.
Merging this pushes
main, which triggers the mirror — that run is the realend-to-end test of both fixes together. GitHub
mainis currently 2 commitsbehind at
d2caa6d; a green run should leave it at this branch's merge commit.