Synchronize tags - #3
Merged
Merged
Conversation
pytooling-claude
Bot
force-pushed
the
claude/synchronize-tags
branch
from
September 10, 2026 21:13
cc480f0 to
6d194ff
Compare
'gh repo sync' knows branches only, so a fork drifts behind its upstream in releases even while its branches are current - 'ghdl/ghdl' has 46 tags, 'Paebbels/ghdl' has 19. A configuration line gains an optional fourth field, colon separated, listing tag names or regular expressions: '<upstream>=<fork>:<branches>[:<tagPatterns>]'. A line without it behaves exactly as before, and a line may carry tag patterns without any branch. Patterns are matched against the whole tag name with 'grep -P', joined into one alternation because GNU grep rejects several '-e' patterns together with '-P'. A matching tag missing from the fork is created pointing at the same object. A tag that moved in the upstream repository is reported as an error and left alone - rewriting it would discard whatever the fork's tag points at - and the run continues. Tags are never deleted. 'created-tags' is a new output parameter. Co-Authored-By: Patrick Lehmann <Paebbels@gmail.com> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RnpaXYDwfNwnJrQew78j3f
pytooling-claude
Bot
force-pushed
the
claude/synchronize-tags
branch
from
September 10, 2026 21:18
6d194ff to
519062f
Compare
Paebbels
reviewed
Sep 10, 2026
Paebbels
reviewed
Sep 10, 2026
Review feedback: 🏷️ meant both "a tag was created" and "here is some information about tags", and ❌ meant both "a branch failed to synchronize" and "a tag moved". 🏷️ now marks a created tag only. 🟰 reports the tags that already point at the same object as upstream, ℹ️ the two cases with nothing to do (the upstream has no tags, no tag matched), and ☢️ a tag that moved upstream - in the log and in the 'Not synchronized' list, which required each entry of that list to carry its own symbol instead of a hard-coded ❌. The README gains a table of the symbols. Co-Authored-By: Patrick Lehmann <Paebbels@gmail.com> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RnpaXYDwfNwnJrQew78j3f
Review feedback: a moved tag reported two SHAs and nothing else, so a reader couldn't tell which of the two is
newer without looking both up by hand.
Both sides are resolved through 'GET /repos/<owner>/<repo>/commits/<tag>', which dereferences an annotated tag -
the tag ref's object SHA is the tag object there, and that endpoint rejects it. The report names the commit each
tag points at and that commit's date:
☢️ v1.0.0 — moved in 'OSVVM/OSVVM'
↪ fork: 90e6af7 2024-03-11 14:22:05 UTC
↪ upstream: d3d07ba 2025-07-02 09:41:18 UTC
The error annotation carries the full SHAs and both dates. When the two resolve to the same commit, the tag object
itself was recreated, and the report says so rather than leaving two identical lines unexplained. A lookup that
fails falls back to the tag refs without a date, so the moved tag is still reported.
The timestamp is reformatted with parameter expansion rather than 'date', which parses this input only in its GNU
flavour.
Co-Authored-By: Patrick Lehmann <Paebbels@gmail.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RnpaXYDwfNwnJrQew78j3f
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
New Features
Tags are synchronized.
gh repo syncknows branches only, so a fork drifts behind its upstream in releaseseven while its branches are current. Measured on the repositories this action will run against:
ghdl/ghdlhas46 tags,
Paebbels/ghdlhas 19 — among the 27 missing arev1.0.0rc1,v0.36-rc1andv0.35rc2.An optional fourth field carries the tag patterns:
<upstream>=<fork>:<branches>[:<tagPatterns>]. A line without it behaves exactly as before, so every existingconfiguration file keeps working untouched. As the third line shows, the branch list may be empty when tag
patterns are given — a fork followed for its releases only.
A pattern is a fixed name or a regular expression, matched against the whole tag name. Both forms in one
list, comma separated.
What happens per matching tag of the upstream:
🏷️ v2.1.0 — created from OSVVM/OSVVM@a1b2c3d🟰 12 tag(s) already up to date)The moved case reads:
☢️ v1.0.0 — moved in 'OSVVM/OSVVM' (fork 90e6af7, upstream d3d07ba)and the annotation carries both SHAs. It is deliberately not rewritten:
git push --forceon a tag discardswhatever the fork's tag points at, and that is not a decision an unattended nightly job should make. Deleting the
tag in the fork lets the next run recreate it.
created-tagsis a new output parameter and a new line in the summary. Tags are never deleted from a fork, anda tag existing only in the fork is left untouched.
Changes
The patterns of one line are joined into a single alternation —
(p1)|(p2)— rather than passed as several-earguments. Not cosmetic: GNU grep refuses the latter.This container's
grepis ugrep, which accepts multiple-ehappily — so the naive form passes here and failson every GitHub runner. Checked against
/usr/bin/grep(GNU grep 3.11) before committing.grep -Pis probed once, and only reported when a line actually configures tags — a repository thatsynchronizes branches only needs nothing beyond
gh.The parser reads the fourth field, and rejects a line with neither branches nor tags. Splitting is on the first
colon after the fork name, so a colon inside a pattern survives.
Each kind of message has its own symbol (from review): 🏷️ marks a created tag only, 🟰 the tags already pointing
at the same object, ℹ️ the two nothing-to-do cases, and ☢️ a tag that moved upstream — in the log and in the
Not synchronized:list, which needed each entry of that list to carry its own symbol instead of a hard-coded ❌.The README gains a table of the whole vocabulary.
Documentation
README.mdgains a Tag Synchronization section: whyghcan't do it, the pattern syntax with the PCRE note(and the trap that a "fixed name" is still a regex —
v1.0matchesv1x0), the three per-tag outcomes, and whatthe action never does. The line-format table gains the fourth element, the worked
PLC2example now carries a tagpattern, the sample log shows both new lines, and
Dependenciesnames thegrep -Prequirement.Unit Tests
check-outputsverifiescreated-tags, and both verification jobs assert it. TheValidfixture now contains twolines with tag patterns — one of them without any branch — which proves in CI that the new field parses and that
a three-field line is unaffected: the branch counts are unchanged at 4 synchronized, 2 skipped.
against a stub
ghservinggit/matching-refs/tags:nightlyleft alone, and thePOSTcarryingref=refs/tags/v1.0.0withthe upstream SHA,
POSTat all,gh repo syncnevercalled,
Others
GET /repos/<owner>/<repo>/git/matching-refs/tagsreturns the ref and the object SHA per tag, and the SHAs of tags present in both
ghdl/ghdlandPaebbels/ghdlallagree — so the "moved" case is genuinely rare, and comparing the ref's object is the right test. Note that the object
compared is the annotated tag object where there is one, not the commit it points at.
Related Issues and Pull-Requests
action.yml; whichevermerges second rebases.
forceupdate a moved tag. It would need care — it's the oneoperation in this action that can lose something.
🤖 Generated with Claude Code