-
Release v0.28.0
StableSome checks failedchangelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 7schangelog-body-check / check (pull_request) Successful in 0scheck-self-bootstrap / check (pull_request) Has been skippedfragment-check / changelog fragment-kind (pull_request) Successful in 6sfragment-check / check (pull_request) Successful in 0smanifest-check / manifest-vs-tag consistency (pull_request) Successful in 8smanifest-check / check (pull_request) Successful in 0sregister-check / register-drift check (pull_request) Successful in 6sregister-check / check (pull_request) Successful in 0stests / bats (pull_request) Successful in 1m51stests / shellcheck (pull_request) Successful in 7scheck-self-bootstrap / check (push) Failing after 4srelease / decide + act (push) Successful in 6srelease / release (push) Successful in 0stests / bats (push) Successful in 1m51stests / shellcheck (push) Successful in 12smirror-on-cut / mirror-1 (release) Successful in 1smirror-on-cut / mirror (release) Successful in 0sreleased this
2026-07-06 21:12:56 +02:00 | 1234 commits to main since this releasev0.28.0 tightens release-note hygiene and release-cut reliability. Register-check now covers commit subjects and composed text. CHANGELOG output is normalized and readability-gated. Orphan-check handles breaking-change footers and legitimate prep-PR merges. Codeberg mirroring is decoupled from the cut workflow.
Added
Per-line exemption for
register-check. Files scanned byregister-checksometimes legitimately use pattern words in adopter-relevant contexts — a role title in a doc, a program name in a script. A trailing# register-check: allowmarker suppresses that one line's match (<!-- register-check: allow -->in Markdown and HTML). No action required. Scrubbing the pattern remains first-resort;.register-allowlistat file scope is second-resort; the line marker is the last resort. The--stdinscan called fromrelease-prep.shignores markers, so composed content stays gated. Closes #396.Register-check now scans commit subjects and composed CHANGELOG content. Chamber-name attributions in commit subjects used to ride into
CHANGELOG.mdpast the file-scan gate. The compose step read subjects the file scan never touched. Two new modes close the gap.--git-log RANGEscans commit subjects at PR review time.--stdinscans arbitrary text and runs fromrelease-prep.shon the composed section before it lands inCHANGELOG.md, catching drift from any source. Recommended for adopters using commit-subject → CHANGELOG composition (cc_list_commits_since/cc_categorize_commits_since): setcheck_commit_subjects: 'true'on thereusable-register-check.ymlinput. Fragments-only adopters can leave the default ('false'). Closes #403.Fragment authors can hard-wrap paragraphs without breaking the rendered CHANGELOG.
release-prep.shnow normalizes compiled sections before they transition intoCHANGELOG.md. Blank lines stay paragraph boundaries. Structural markdown — lists, headers, blockquotes, fenced code — passes through verbatim. Continuation lines within a paragraph join with a single space. A hyphen-word rejoin heuristic catches breaks inside hyphenated words. If a residual[a-z]- [a-z]pattern survives, the step fails loud on the offending source so the fragment can be fixed before release-prep ships. No action required. Hard-wrapping fragments at ~72 columns continues to work. Closes #420.CHANGELOG bodies get a readability check.
changelog-body-checknow flags long sentences, deep parenthetical nesting, and long paragraphs on newly-composed sections before the release-prep PR reaches operator eyes. Defaults: sentence fails at 30 words (warns at 25), paragraph fails at 100 words (warns at 75), parenthetical nesting fails above depth 2. Historical sections stay out of scope — the check targets the newest version block only. Recommended for adopters wanting different thresholds: override via new inputs onreusable-changelog-body-check.yml—sentence_max_words,sentence_warn_words,paren_depth_max,paragraph_max_words,paragraph_warn_words. Author-side guidance lives indocs/conventions.md"Writing adopter-facing prose". Closes #421.Changed
Orphan-check now catches
BREAKING CHANGE:body-footer commits. Arefactor:orchore:commit whose body carries aBREAKING CHANGE:footer is bump-worthy per conventional-commits. The pre-fix range-walk inrelease-decide.shkeyed only on the subject and false-skipped them.release-decide.shnow delegates release-relevance tocc_bump_level_from_subjectinscripts/lib/conventional-commits.sh. The helper handles subject-levelfeat!/fix!markers AND body-levelBREAKING CHANGE:footers, so orphan-check uses the same rules as the release-cut bump logic. Any future addition to the bump-worthy type set (for example,perf:) propagates automatically. No action required. Closes #424.check-self-bootstrapdocstrings clarify their scope. The script and workflow headers now open with "Pin-drift detection, NOT content validation." A red on a PR that touches a compose-script means the mechanism is firing correctly. The pinned ref needs to advance to catch main up at the next cut. It does not mean something is wrong with the code. Content-quality gates (shellcheck, bats, register-check) are named explicitly so a reader triaging a failure knows where content-questions live. No action required. Closes #432.Fixed
Orphan-check no longer false-fires on a legitimate cut — v1.0.0 must-fix follow-up to #417. Release-toolkit's own v0.27.0 cut on PR#406 tripped
release-decide.shwith the exact fail-loud the detector was designed to emit. The detector's signature —semver_compare(CHANGELOG_TOP, manifest.last_released) == 1— matches both an orphan-post-cancellation AND a legitimate cut-in-progress. Both have CHANGELOG advanced, manifest not yet updated, and no tag yet. The distinguisher is action-context, not signature.release-decide.shnow readsHEAD_SUBJECTearly and matches it againstPREP_SUBJECT_RE. When HEAD IS a prep-PR merge commit AND the version it cuts equalsCHANGELOG_TOP, the check skips — that is the legitimate cut-about-to-fire path. Any other HEAD shape (a bystander push after a cancelled cut) still fires the fail-loud. Both prep-merge subject styles are handled:chore(release): prepare vX.Y.Z(merge / rebase) andchore(release): vX.Y.Z(squash-merge using the PR title). Three new regression tests lock the behavior. No action required. Closes #417.Codeberg mirror no longer runs inside the cut workflow. A new
.forgejo/workflows/mirror-on-cut.ymltriggers on therelease: publishedevent. It fires either on immediate-mode publication, or when the operator clicks Publish on a draft.The in-graph
mirror:job is removed fromrelease.yml. It combinedcontinue-on-error: truewith auses:job, which Forgejo Actions correctly rejects per the GitHub Actions schema. Mirror-outages, PAT-rotations, and Codeberg-side timeouts no longer cascade into cut-failure. Mirror-failure never touches the cut workflow's job graph.Adopter action required only if you fork the toolkit's workflow files and mirror to Codeberg from your own copy. Move the mirror job into a separate
release: published-triggered workflow rather than amirror:job insiderelease.yml. Thereusable-mirror-to-codeberg.ymldocstring shows the new pattern. Closes #427.Removed
None.
Deprecated
None.
Upgrade
- Optional: set
check_commit_subjects: 'true'onreusable-register-check.ymlif you compose CHANGELOG entries from commit subjects. Default remains'false'for fragments-only adopters. See #403. - Optional: override readability thresholds via new inputs on
reusable-changelog-body-check.yml—sentence_max_words,sentence_warn_words,paren_depth_max,paragraph_max_words,paragraph_warn_words. Defaults follow the "Writing adopter-facing prose" convention. See #421. - Required if you fork the toolkit's workflow files and mirror releases to Codeberg from your own copy: move the mirror job into a separate
release: published-triggered workflow rather than an inlinemirror:job inrelease.yml. Toolkit-self's ownmirror-on-cut.ymlis a working example. See #427.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- Optional: set
-
v0.27.0
StableSome checks failedchangelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 4scheck-self-bootstrap / check (pull_request) Has been skippedchangelog-body-check / check (pull_request) Successful in 0sfragment-check / changelog fragment-kind (pull_request) Successful in 4sfragment-check / check (pull_request) Successful in 0smanifest-check / manifest-vs-tag consistency (pull_request) Successful in 5smanifest-check / check (pull_request) Successful in 0sregister-check / register-drift check (pull_request) Successful in 4sregister-check / check (pull_request) Successful in 0stests / bats (pull_request) Successful in 1m47stests / shellcheck (pull_request) Successful in 8scheck-self-bootstrap / check (push) Successful in 3srelease / decide + act (push) Failing after 5srelease / release (push) Failing after 0srelease / mirror (push) Failing after 0stests / bats (push) Successful in 1m47stests / shellcheck (push) Successful in 8sreleased this
2026-07-06 14:12:12 +02:00 | 1258 commits to main since this releasev0.27.0 hardens release-toolkit for real Forgejo and Codeberg adoption ahead of v1.0: bounded, retryable API calls with pagination; per-project
publish_modeoverrides; Codeberg proven end-to-end; stale docstring pins cleaned up; and protection against cut cancellation.Added
Forgejo API calls are now bounded and retryable: a 5s connect timeout and 30s total timeout on every call (env-tunable via
FORGEJO_API_CONNECT_TIMEOUT_S/FORGEJO_API_TIMEOUT_S), with exponential backoff on 429 / 5xx / network errors. Tag and PR-list lookups now paginate, fixing missed results on repos with more than one page of tags or PRs. Retries are safety-gated: 429 is retried on any method, but 5xx / network errors are retried only for idempotent methods — a POST / PATCH is not retried by default (the server may have partially applied it) unless you setFORGEJO_API_RETRY_UNSAFE=1(#334; v1.0.0 must-fix).You can now change
publish_modeper project without editing your workflow: setvars.RT_PUBLISH_MODEin Forgejo → Settings → Actions → Variables, or addpublish_mode:torelease-toolkit.yml. Precedence, highest first: repo variable → config file → workflowwith:input → thedraftdefault (#332). Invalid values fail loud with the resolution chain shown (#408; v1.0.0 must-fix).Integration docs now collect the per-project override options in one table, with worked examples for config-file, repo-variable, and one-off dispatch overrides (#409).
Changed
release-toolkit is now demonstrated end-to-end on Codeberg's shared runners: the tic-tac-toe companion demo runs the full flow from fresh-repo bootstrap through cut to a draft release. The README and integration docs now describe Codeberg as proven rather than assumed, link the demo, and add a short "Running on Codeberg" note covering how to enable Actions and Releases and the no-token fallback (#412).
Fixed
Reusable workflow docstring examples now use
@vX.Y.Zplaceholders instead of concrete pins that had drifted stale; the copy-paste-ready refs in the docs and examples stay pinned and are kept fresh by the post-cut version-ref hook (#407).Cut-cancellation recovery. If another push lands while a cut is queued, the cut can be cancelled after the CHANGELOG section moved but before the release tag exists — leaving an orphaned
## [vX.Y.Z]section that the next run would otherwise re-emit as a duplicate entry.Recommended: add the new
concurrencyblock from integration.md to your consumer workflow to prevent the cancellation. If you skip it, cuts stay safe — the toolkit fails loud on the state divergence — but an interrupted cut may need manual recovery.- Prevention (adopter-side): the consumer wiring template in
docs/integration.mdnow includes a workflow-levelconcurrency:block (group: release-cut-${{ github.ref }},cancel-in-progress: false) that queues later pushes behind the in-flight cut. - Detection (toolkit-side):
release-decide.shfails loud whenCHANGELOG.md's top-most released section is ahead ofmanifest.last_released_version— the orphan signature — and lists two recovery options (finish the pending release and update the manifest, or move the section back under[Unreleased]). Auto-heal is out of scope for v1.0.0.
Closes #417.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- Prevention (adopter-side): the consumer wiring template in
-
Release v0.26.0
StableSome checks failedchangelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 4schangelog-body-check / check (pull_request) Successful in 0scheck-self-bootstrap / check (pull_request) Has been skippedfragment-check / changelog fragment-kind (pull_request) Successful in 4sfragment-check / check (pull_request) Successful in 0smanifest-check / manifest-vs-tag consistency (pull_request) Successful in 5smanifest-check / check (pull_request) Successful in 0sregister-check / register-drift check (pull_request) Successful in 4sregister-check / check (pull_request) Successful in 0stests / bats (pull_request) Successful in 1m33stests / shellcheck (pull_request) Successful in 8scheck-self-bootstrap / check (push) Failing after 3srelease / decide + act (push) Successful in 6srelease / release (push) Successful in 0stests / bats (push) Successful in 1m34stests / shellcheck (push) Successful in 12srelease / mirror (push) Successful in 2sreleased this
2026-07-05 16:46:34 +02:00 | 1278 commits to main since this releaseAdded
CI test suite as required merge gate — new
.forgejo/workflows/tests.ymlruns fullbats tests/+shellcheck --severity=warningon every PR + push:main. ADR-0001 named shellcheck as CI gate; this workflow implements it. One pre-existing SC1010 false-positive inscripts/lib/forgejo-api.sh(jq variable nameddo) fixed by rename tomerge_do(#330).docs/SECURITY.md— new page documenting the release-toolkit trust boundary + the audit-scope gap between consumer-pinning and secondary-checkout script execution. Honest disclosure of the current state; architectural fix targets v1.1.0 (#336).docs/VERSIONING.md— new page memorializing the v1.0.0 SemVer stability contract: v1.x preserves backward compat on workflow inputs, config schema, published script CLI, and documented behavior contracts; breaking changes require v2.0.0; deprecation cycle spans a minor before removal; tag immutability commitment; post-v1.0.0 cadence shift to boring/settled infrastructure (#338).New
docs/cold-read-adopter.mdbrings the full-project adopter-simulation cold-read prompt in-repo (previously BookStack-only) — the prompt used to prime outside-model reviews of the whole toolkit.docs/cold-read-prompt.mdis renamed todocs/cold-read-changelog.md(distinguisher-leads naming, matching its# Changelog Cold-Read Promptheading); inbound references updated (#366).Mechanized pre-merge register grep-gate (
scripts/register-check.sh+reusable-register-check.yml). Case-insensitive sweep acrossscripts/+.forgejo/+tests/+docs/+changelog.d/+README.md+CHANGELOG.md+AGENTS.mdfor chamber-name attribution- invented-jargon vocabulary. Fails PR merges on hits; extensible
pattern list (bash array) +.register-allowlistfor load-bearing exceptions. Closes #392.
Empirical rationale: manual per-round sweeps don't stay closed under continued PR throughput. Round-4 alone saw n≥3 same-day re-seedings across concurrent-authorship PRs — careful authors crediting reviewers inline is the recurring failure mode. Manual sweep as a discipline is falsified at this cadence; CI grep-gate is the fix by construction.
Adopter wiring: drop
.forgejo/workflows/register-check.ymlinvokingfrankenbit/release-toolkit/.forgejo/workflows/reusable-register-check.yml@v1.0.0on yourpull_request: branches: [main]trigger. Allow-list at.register-allowlist(glob patterns; directory-prefixdir/for recursive allow) opts out load-bearing exceptions like compiled-changelog historical records or maintainer archaeology.Changed
Adopter-visible header comments tightened — top-of-file comment blocks in
reusable-mirror-to-codeberg.ymland toolkit-self'srelease.ymlscrubbed of internal-review vocabulary ("substrate-of-record", "dogfoods its own new mechanic") + shortened. Consumer wiring pattern + design references preserved; canonical vocabulary in ADRs untouched. Set J adopter-hygiene sweep (#313).BREAKING (v1.0.0-blocking):
publish_modedefault flipped fromimmediateback todraft. Cold-read finding: README advertised "gates every release behind a human" but v0.10.0 immediate-default let the merge of the rolling PR publish directly, no Gate-3 click. The fix restoresdraftas the default so the advertised safety property holds by default. Adopters who value frictionless CI cadence over the per-cut Gate-3 opt in viapublish_mode: 'immediate'at the workflow_call layer. Adopters currently relying on the immediate-default must explicitly opt in when bumping to this release. (#332)docs/integration.md— tighten the version-file-basename scope note: the two#252refs (now closed as superseded) point at the broader-ecosystem tracker #337, which covers TOML (pyproject/Cargo), Maven, Helm, and other release-please-shaped ecosystems. Also names a workable escape hatch for unlisted ecosystems today (version_files: []+ consumer hook).docs/integration.md— new Token Decision Matrix (3 yes/no questions → adopter's token setup with minimum scope), Sample failure modes section naming the 4 concrete errors adopters actually hit (Repository not found,push_whitelist pre-flight FAIL, case-sensitive push-denied,mergeable=blockedon manifest PR), Bot user provisioning step-by-step for path α (Forgejo user + collaborator + PAT scope + whitelist + secret), and a concretesecrets: inheritwiring example. Retires the "token model is complicated" trust-dent surfaced by external cold-read round 2 (#356).README.md+docs/integration.md— new Runner requirements section naming explicitly what the toolkit assumes: Debian/Ubuntu-family runner withapt-get+sudofor install-on-demand ofyq. Per-requirement table names root cause + what to do if your runner is non-Debian / rootless / ephemeral (pre-bakeyq+jq+curlso the install step is a no-op). Configurable install commands + auto-skip logic named as v1.1.0+ target. Retires the "workflow installs deps with apt-get/sudo, not universally safe" trust-dent surfaced by external cold-read round 2 (#357).docs/integration.md— new Tag creation section documenting the mechanism explicitly: Forgejo release API creates the tag viatag_name+target_commitish(nogit tag && git push --tags); tag points at the rolling-PR merge commit; idempotency behavior enumerated (same-tag-same-commit skips; same-tag-different-commit fails loud; same-tag-on-Forgejo-missing-local skips via pre-check); cross-variant status per Forgejo/Codeberg/Gitea. Retires the "delegated tag creation needs proof" trust-dent surfaced by external cold-read round 2 (#359).scripts/release-decide.sh+scripts/lib/conventional-commits.sh+docs/integration.md+README.md+examples/README.md+ tests — BREAKING for the fresh-repo failure surface, no regression for repos with a real anchor: fresh consumer repo (no manifest, no stable tag) now bootstraps from a virtualv0.0.0anchor and walks from the initial commit (#368). First cut producesv0.1.0(anyfeat:since root),v0.0.1(onlyfix:), ormode=noop(onlychore:/docs:/refactor:— chore isn't release-relevant per conventional-commits; adopter adds afeat:/fix:or drops abump/*label to force the cut). SUPERSEDES the #355 Option B fail-loud path shipped in v0.25.0: adopters no longer need to manually tagv0.0.0before the first cut.cc_list_commits_sincegains a--rootsentinel so the virtual-anchor bump-walk stays root-inclusive even when a prerelease tag exists (prerelease v-tags matchedgit describe --match 'v*'and would silently drop the root feat: from the bump walk despite step-2 seeing it). Afeat!:/BREAKING CHANGEat root bumps tov1.0.0by default; setpre_v1_breaking_to_minor: truefor the pre-1.0 opt-in that downgrades tov0.1.0. Advanced adopters can still hand-write.release-toolkit-manifest.json; that path is unchanged.docs/VERSIONING.md+docs/SECURITY.md— retire the "as of v1.0.0" / "target v1.1.0" future-tense-in-current-adopter-surface leaks external cold-read round 3 flagged. VERSIONING.md rewritten to describe current pre-1.0 state (Option A) + a "will commit at v1.0.0" preamble frames the effective-at-v1.0.0 sections without ambiguity. SECURITY.md's architectural-fix section labeled "Planned for v1.1.0" with an explicit callout that it describes not-yet-shipped work (Option B — preserves the fix-target framing). Example pin swapped from@v1.0.0(aspirational) →@v0.25.0(current). Tag-immutability section reframed as "already active" (the discipline was already in force pre-1.0, not a v1.0.0 addition). Adopters reading v0.25.0 docs no longer confuse future contract with current guarantee (#369).Adopter-facing docs read register-clean — internal review-process language (per-reviewer attributions,
ratifyceremony) scrubbed fromCHANGELOG.md+docs/adr/*.md, so the project no longer reads as internally process-driven. Technical content and issue/ADR anchors are preserved and the documented cold-read editorial discipline is kept + glossed; only the internal-review narration is removed. Third register-audit delta after #352 + #362 (#372).README.md+docs/integration.md— new Positioning section declaring release-toolkit Codeberg-primary (source, releases, and tags at codeberg.org/frankenbit/release-toolkit) and targeting Forgejo Actions as its CI runtime, with a runtime-compatibility list (Forgejo Actions tested; Gitea Actions untested; Codeberg where a runner is available). This is the definitive answer to the adopter positioning question external cold-read raised (rounds 2–4): where the project lives (Codeberg) and what CI runtime it targets (Forgejo Actions) are stated as separate facts so neither is ambiguous. The maintainers develop on a self-hosted Forgejo and mirror code + releases to Codeberg (#358, #397).Fixed
examples/README.md+examples/{go,node}-project/.forgejo/workflows/*.yml— bumped stale@v0.16.0pins to the current released tag@v0.25.0, closing the trust-dent surfaced by external cold-read round 2 (adopters landing on stale copy-paste refs). Extendedscripts/hooks/update-doc-version-refs.shto walkexamples/**/*.yml+examples/README.mdon every future cut so the drift can't recur; the hook silently no-ops when a consumer doesn't have anexamples/directory (#311).Mirror workflow: empty-TAG_NAME guard as Forgejo-agnostic first-check. Forgejo Actions doesn't reliably honor
needs.<reusable-call-job>.outputsin a job-levelif:gate (empirical: mirror fired on non-cut push:main events), causing spurious workflow failures on every non-cut push despiteif: mode == 'cut'. Script-level guard exits cleanly on empty TAG_NAME + sidesteps the outputs-based gating question; wrong-commit class was already closed by the tag-guard (#322).SemVer parser now enforces the full SemVer 2.0.0 grammar — leading zeros in numeric identifiers, empty prerelease/build identifiers, and leading/trailing dots are rejected at parse time. Previous regex accepted these invalid values and then crashed on bump (bash-octal interpretation of
1.2.08→08: value too great for base). Base-10 arithmetic (10#$var) added tosemver_bumpas belt-and-suspenders. 20 new test cases cover every invalid-input class from the cold-read finding (#329).Squash-merge cut detection —
PREP_SUBJECT_REinrelease-decide.shnow accepts bothchore(release): prepare vX.Y.Z(merge/rebase style) andchore(release): vX.Y.Z(Forgejo squash-merge style using PR title). Layer 2 branch-source-check remains the belt-and-suspenders gate. Adopters following standard Git squash-merge conventions were silently losing their release cut before this fix (#331).Token docs cleanup — removed all references to the unimplemented
release_token(path β) that shipped in docs but never wired in the workflow. Rewrote the no-token path (γ) section: dedicated PAT (path α) is operationally required for repos with required-checks branch protection, not merely optional. Path (γ) fits only repos wheremainaccepts unrestricted merges. Docs now match actual workflow behavior (#333).Config schema version now enforced against supported set —
config_validateinscripts/lib/config.shmaintainsSUPPORTED_SCHEMA_VERSIONS=(1)and rejects unsupported versions with a clear error naming what's supported. Previously any integer passed (version: 999silently accepted). Forward-compat: when schema v2 arrives, add 2 to the array. +4 test cases (#335).scripts/repin.shno longer defaultsREPIN_REVIEWERto an internal reviewer username. The default is now empty and the PR review-request is skipped when unset, so an adopter runningrepin.shno longer opens a re-pin PR requesting review from a user that doesn't exist in their repo. SetREPIN_REVIEWER=<user>to request a specific reviewer. (#340)README.md+docs/integration.md+docs/SECURITY.md+docs/events-logging.md+docs/VERSIONING.md+docs/migration/tmux-tell.md+ ADRs 0001/0002/0003 — v1.0.0 pre-cut Cold-Read delta (#353): quick-startpublish_modeexample dropped so the reusable'sdraftdefault applies (was contradicting the "gates every release" claim, same class as #332); ADR-0003 now records the v1.0.0 supersession — the 2026-06-26 immediate-default amendment is retired, and the default-record matches the shipped code; adopter-facing docs no longer citeAGENTS.md(maintainer doc) — replaced with public references to the CI gate + inlined content; ADRs no longer linkalcatraz-infra#65(cross-repo private tracker) — replaced with plain-prose "initial architecture proposal";docs/VERSIONING.mdglosses paths α/γ +mode = noop|update|cutwith links to ADR-0007 / ADR-0004;docs/migration/tmux-tell.mdreframed as a pointer + tmux-tell-specific notes (drops "Status: stub" language).scripts/release-decide.sh+README.md+docs/integration.md+examples/README.md— BREAKING for docs-honesty, no behavior regression: fresh consumer repo (no.release-toolkit-manifest.jsonAND no stablevX.Y.Ztag) previously failed with a terseFATAL: no stable vX.Y.Z tag found; docs implied fresh repos "just worked" — external cold-read round 2 named this as the biggest trust-dent for first-user experience (#355). Fixed by (a) making the error actionable — names the exactgit tag -a v0.0.0 && git push origin v0.0.0command, points at the docs section, mentions the manifest hand-write escape hatch — and (b) documenting the anchor requirement upfront: new "Bootstrapping a new consumer repo" section indocs/integration.mdnaming both anchor options; README quick-start now has a "step 0" for the tag;examples/README.mdpost-copy checklist ends with the bootstrap command. Behavior unchanged: no code path that previously succeeded now fails; only the failure surface (message + docs coverage) improved..forgejo/workflows/reusable-release.yml+scripts/lib/forgejo-api.sh+scripts/lib/config.sh+docs/integration.md— layered default-branch resolution replaces the hardcoded"main"at the manifest follow-up PR path. Newresolve_default_branchhelper in forgejo-api.sh walks 6 fallback layers: (1)RT_DEFAULT_BRANCHenv var, (2)default_branch:field inrelease-toolkit.yml, (3)TOOLKIT_DEFAULT_BRANCH_HINTenv var (workflow YAML passes${{ github.event.repository.default_branch }}), (4) Forgejo APIGET /repos/{owner}/{repo}, (5)git symbolic-ref refs/remotes/origin/HEAD, (6) fail-loud with actionable error naming all 5 preceding layers. Newconfig_get_default_branchin config.sh exposes layer 2. Adopters on non-maindefault branches (trunk/master/develop/custom) previously hit a silent-corruption class: manifest PR opened against a nonexistent branch or one with unrelated content. Full docs indocs/integration.md § Default branch (#370). Regression tests cover all 6 layers (#370).scripts/lib/forgejo-api.sh+scripts/setup-bump-labels.sh— keep theFORGEJO_TOKENout of curl's argv (visible via/proc/<pid>/cmdline+pson some systems). All 6 previously-argv-exposing curl invocations refactored to use a 0600-mode auth config file (install -m600,-K "$auth_config"), matching the pattern already established inreusable-mirror-to-codeberg.yml:184-193. New shared helper_forgejo_auth_config_newin the lib consolidates the mktemp+install+write dance across the 3 lib callsites;setup-bump-labels.shinlines the same shape at script start with atrapcleanup. Closes the argv-vs-config-file inconsistency between the two curl surfaces on the same substrate (#371)..forgejo/workflows/reusable-release.yml+scripts/release-prep.sh+scripts/repin.sh+scripts/manifest-precheck.sh— semantic-class sweep for hardcoded default-branch references missed by #370's literal-mainsweep. Path-α direct-push (2 sites) +git_push_authedhelper (1 site) + repin PR base + manifest-precheck remote-read: all now useresolve_default_branch(6-layer chain) orRT_DEFAULT_BRANCHenv var. Adopters on non-maindefault branches (trunk/master/develop/custom) no longer hit silent-corruption at any push callsite. Newtests/hardcoded-defaults-sweep.bats(7 grep-guards) locks the class-axis so future edits can't reintroduce the anti-patterns (#379).scripts/release-decide.sh+docs/integration.md—.release-toolkit-manifest.jsonanchor precedence rule for thelast_released_shavslast_released_tagdisagreement class. When both fields are set AND the local tag exists AND its SHA disagrees withlast_released_sha,release-decide.shnow fails loud with an actionable error naming both SHAs + three resolution options (tag authoritative / manifest authoritative / re-bootstrap by deleting manifest). Shallow clones and tags-pruned setups where the tag isn't local are treated as "cannot verify" — the check is skipped rather than erroring, so those adopters aren't blocked. Docs section explains the three divergence scenarios (force-push after cut / manual tag surgery / cross-repo mirror desync) + why v1.0.0 ships fail-loud rather than silent-manifest-wins (#380)..forgejo/workflows/reusable-release.yml+scripts/release-prep.sh— allgit -c http.extraheader="Authorization: token $TOKEN" pushargv-token exposures refactored to write the extraheader to amktemp+chmod 600config file scoped viaGIT_CONFIG_GLOBAL. Same semantic class as #371 (curl argv-token → config file) and alcatraz-infra#89 (token in git remote URL): grep-sweep-missed-sibling because those sweeps targeted their specific literal patterns, not the semantic class of "token visible outside process env." Token now stays in the mode-0600 file + env (process-owned), never in argv — invisible tops auxww+ auditd audit logs. Regression test intests/hardcoded-defaults-sweep.bats(grep-guard ongit -c ... http.extraheaderpattern) locks the class-axis (#381).scripts/draft-release.shheader comment (lines 1-8) refreshed to describe current v1.0.0 behavior:publish_modedefault isdraft(per #332) notimmediateas the pre-#332 header claimed; the "cut path merges to main" phrasing now points at the consumer's resolved default branch (per #370) rather than hardcodingmain(#383).docs/integration.md § Dry-run previewrewritten to accurately describe the three-script dry-run flow (release-decide.sh/release-prep.sh/draft-release.sh) — what mutates locally (release-prep.sh transitions CHANGELOG + bumps version_files in place), what emits summaries (draft-release.sh Forgejo APIMETHOD POST / URL / BODY), what skips (git remote writes + Forgejo API calls). Corrects the pre-fix "still needs an origin remote" note: origin is NOT needed for the git-log walk (release-decide.sh readslast_released_shafrom the LOCAL manifest + walks LOCAL history); origin IS used for OWNER/REPO derivation (dry-run substitutesOWNER/REPOplaceholder if missing) + Forgejo API calls (dry-run summarizes). Remote-less clones work for dry-run (#385).- security+workflow: semantic-class sweep for hardcoded-main + argv-token (#379 + #381) (#386)
- workflow: move #370 env vars to correct step + wire config_get + docstrings
- tests: preserve v0.10.0+ default marker in mutation-guard fixture
Internal
Docs reclassify —
docs/cold-read/,docs/drift-audit-*, anddocs/walkthrough-*moved todocs/internal/. Adopter-facing rootdocs/now contains only canonical adopter documentation (integration, conventions, operations, architecture, adr, migration); maintainer audits + walkthrough artifacts live underdocs/internal/with a bucket-README explaining the split (#312).Workflow comments scrubbed of internal incident-history — the
.forgejo/workflows/*.ymldocblocks and inline comments no longer carry accumulated bug-archaeology (probe-iteration logs, dated cross-repo incident recoveries, version-specific cut-failure narration, internal review-vocabulary). Load-bearing invariants and issue/ADR anchors are kept; only the narration is removed, so the reusable workflows read as auditable machinery rather than internal history (#340).Script, workflow, and test comment blocks scrubbed of internal review-role attributions (per-reviewer names + short hex-id tags). Round-3 (#372) closed the prose surface (README + docs/ + ADRs + CHANGELOG); this closes the sibling code-comment surface —
scripts/*.sh+.forgejo/workflows/*.yml+tests/*.bats— that an adopter reads when auditing the toolkit. Load-bearing technical invariants and issue/ADR anchors are kept; only the attribution narration is removed, with no behavior change (one test fixture genericized behavior-preservingly, mutation-verified green). (#384)AGENTS.md(contributor pre-flight doc) scrubbed of internal review-role attributions + invented-jargon — the last manual surface in the register-audit sweep (sibling to #384). Per-reviewer name+hex attributions removed from the disciplines (the guidance content is kept), the historical convergence-arc section trimmed of its internal narration (catch-count table + forward-going guidance kept), and a functional reviewer-identity default genericized. Round-3 held this doc as maintainer-surface; round-4 external reached it, so it's covered now (#391).docs/internal/— moved the point-in-time maintainer archaeology (the 2026-06-27 consumer-walkthrough audit and documentation-drift audit) out of the source tree to the maintainers' internal wiki, and cleaned the remainingcold-read/framework of internal-review-role names so a source-tree browser sees a neutral external-doc-review framework. Part of the Codeberg-primary shift: source-tree visibility is now the adopter-facing surface, so point-in-time internal-process artifacts are archived off-tree while the activecold-read/maintainer tool stays in-repo, provenance preserved (#398).Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- invented-jargon vocabulary. Fails PR merges on hits; extensible
-
Release v0.25.0
Stablereleased this
2026-07-03 12:44:58 +02:00 | 1342 commits to main since this releaseAdded
Codeberg-mirror reusable workflow —
.forgejo/workflows/reusable-mirror-to-codeberg.ymlpublishes each cut's release to the Codeberg mirror. Toolkit-self wires it inrelease.ymlas aneeds: releasejob gated onmode == 'cut'. Idempotent (GET-before-POST) + warn-not-fail on Codeberg errors (#309).Historical mirror script for Codeberg (dev-tool). One-shot migration of existing releases to
codeberg.org/FrankenBit/release-toolkitviascripts/dev-tools/migrate-releases-to-codeberg.sh. Idempotent + rate-limit-aware + order-preserving (#310).Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
Source code (ZIP)
-
Release v0.24.0
StableAll checks were successfulchangelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 4scheck-self-bootstrap / check (pull_request) Has been skippedchangelog-body-check / check (pull_request) Successful in 0sfragment-check / changelog fragment-kind (pull_request) Successful in 4sfragment-check / check (pull_request) Successful in 0smanifest-check / manifest-vs-tag consistency (pull_request) Successful in 5smanifest-check / check (pull_request) Successful in 0scheck-self-bootstrap / check (push) Successful in 4srelease / decide + act (push) Successful in 6srelease / release (push) Successful in 0sreleased this
2026-07-03 10:49:44 +02:00 | 1347 commits to main since this releaseChanged
check-self-bootstrapnow skips onrelease-prep/*rolling PRs. The rolling PR is the surface where "the mechanism that would fix the drift IS the drift" — the check fires genuine content-differences that aren't actionable AT that PR (the next cut resolves them via #283 auto-re-pin). Regular feature PRs andpush:mainkeep firing the check unchanged; only release-bot'srelease-prep/head branches are exempted. Per operator directive: zero-failing-runs on release PRs as a general goal. Closes #304.Fixed
- ci: harden #304 rolling-PR exemption per Surveyor 41ce
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
Release v0.23.0
StableSome checks failedchangelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 4schangelog-body-check / check (pull_request) Successful in 0scheck-self-bootstrap / check (pull_request) Failing after 3sfragment-check / changelog fragment-kind (pull_request) Successful in 4sfragment-check / check (pull_request) Successful in 0smanifest-check / manifest-vs-tag consistency (pull_request) Successful in 5smanifest-check / check (pull_request) Successful in 0scheck-self-bootstrap / check (push) Failing after 4srelease / decide + act (push) Successful in 6srelease / release (push) Successful in 0sreleased this
2026-07-02 23:41:14 +02:00 | 1354 commits to main since this releasePost-v0.22.0 correctness fix: retire the release-notes sidecar so edits to
CHANGELOG.mdactually reach the Forgejo release page.Removed
BREAKING:
.release-toolkit-release-notes.mdsidecar retired — CHANGELOG.md is the single source of truth for the release-body content. The v0.5.0-introduced sidecar (fed by fragmentsummary:frontmatter) was preferred bydraft-release.shover the CHANGELOG section, so edits toCHANGELOG.mdwere silently ignored on the release page.draft-release.shnow always reads the CHANGELOG section.release-prep.shno longer writes a sidecar and deletes any legacy committed sidecar on the first post-#301 cut so the file stops shipping stale content.summary:frontmatter on fragments becomes inert (safe to leave or strip). Closes #301.Upgrade
If your repo has committed a
.release-toolkit-release-notes.mdfile from a pre-v0.23.0 cut, delete it:git rm .release-toolkit-release-notes.md && git commit -m "chore: drop retired sidecar per release-toolkit#301"draft-release.shignores the file post-v0.23.0, so leaving it in place is a no-op (not an error). Nothing else needed to upgrade.Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
Source code (ZIP)
-
Release v0.22.0
StableAll checks were successfulchangelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 4schangelog-body-check / check (pull_request) Successful in 0scheck-self-bootstrap / check (pull_request) Successful in 3sfragment-check / changelog fragment-kind (pull_request) Successful in 4sfragment-check / check (pull_request) Successful in 0smanifest-check / manifest-vs-tag consistency (pull_request) Successful in 5smanifest-check / check (pull_request) Successful in 0scheck-self-bootstrap / check (push) Successful in 3srelease / decide + act (push) Successful in 6srelease / release (push) Successful in 0sreleased this
2026-07-02 21:31:16 +02:00 | 1359 commits to main since this releasePost-v0.21.0 stabilization: consumer-wrapper discovery unified, CC-bullet dedup extended to scope-as-issue-ref shape, and the toolkit-self body-linter dogfood wrapper lands.
Added
Toolkit-self dogfood wrapper for the Cold-Read body linter — new
.forgejo/workflows/changelog-body-check.ymlinvokes the toolkit's ownreusable-changelog-body-check.ymlon every PR that touchesCHANGELOG.md. Structural + formatting issues on the toolkit's own CHANGELOG now fail PR CI before merge, exactly like consumers do once they wire the reusable in. Same shape asfragment-check.yml's dogfood wrapper (#281). Closes #290.Fixed
Consumer-wrapper discovery unified into a single source of truth — extracted to
scripts/lib/wrappers.sh::discover_consumer_wrappersand consumed by all three surfaces (check-self-bootstrap.sh,scripts/repin.sh,reusable-release.yml's runtime auto-re-pin loops). Before, each surface carried its own hardcoded wrapper list; a new wrapper (e.g.,fragment-check.ymlin #278,changelog-body-check.ymlin #290) required updating each list, and a missed update produced silent single-ref-alignment drift post-cut. Closes #295.changelog_dedup_cc_by_fragment_refsnow catches scope-as-issue-ref bullets — commits withfix(#NNN): ...scope-format subjects (which produce- **#NNN**: ...bullets) are now suppressed when a matching fragment exists, alongside the existing(#NNN)trailer format. Closes #293.Removed / Deprecated
None.
Upgrade
No action required to upgrade.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
Source code (ZIP)
-
Release v0.21.0
StableSome checks failedcheck-self-bootstrap / check (pull_request) Failing after 3sfragment-check / changelog fragment-kind (pull_request) Successful in 4sfragment-check / check (pull_request) Successful in 0smanifest-check / manifest-vs-tag consistency (pull_request) Successful in 6smanifest-check / check (pull_request) Successful in 0scheck-self-bootstrap / check (push) Failing after 3srelease / decide + act (push) Successful in 7srelease / release (push) Successful in 0sreleased this
2026-07-02 17:23:13 +02:00 | 1369 commits to main since this releaseChangelog tooling + release automation: mechanical Cold-Read body linter, fragment template + brevity docs, auto re-pin of toolkit-self wrappers post-cut, and observability fields for cut-timing.
Added
Cold-Read body linter — new
reusable-changelog-body-check.ymlreusable workflow +scripts/changelog-body-check.sh. Runs 6 mechanical checks on the newest version-block inCHANGELOG.mdat PR time: version header + date, standard sections present, forward-reference detection, body length ceiling (5000 chars), bullet/prose consistency, duplicate section headers. Consumers wire it into theirpull_requestworkflow same shape asfragment-check.yml. Toolkit-self dogfood wiring deferred to #290. Closes #282 Layer 1.Fragment template + brevity docs — new
changelog.d/.template.mdstarter template +docs/conventions.md### Fragment brevitysection. Codifies "outcome + required action in 1-3 sentences" as the human-side density guidance; complements the automated linter. Closes #282 Layer 2.Auto re-pin of toolkit-self consumer wrappers —
reusable-release.ymlnow auto-re-pinsrelease.yml+manifest-check.yml+fragment-check.ymlto the just-cut tag as part of post-cut bookkeeping. Bundled with the bake-reset commit so both land atomically. Obsoletes the manual re-pin PR thatcheck-self-bootstrap.yml(#124) previously fired as a reminder for. External consumers are unaffected — the auto-re-pin targets toolkit-self only;if [[ -f ... ]]guard skips non-existent files. Closes #283.cut_complete.ms_total+path— thecut_completeJSON event now carriesms_total(total cut wall-clock in integer milliseconds) andpath(thealpha/gammapush-path). Off the workflow path (directdraft-release.shinvocation, or platformdatelacking%N) both fields degrade to empty — the same graceful-degradation contract asapi_call'sms. Completes the JSON-logging taxonomy from #159. (Part 2 of #204.)Changed
check-self-bootstrap.ymlscope narrowed — now fires only when the auto re-pin (#283) fails, not as a "human forgot" reminder. Consumers who relied on this check as a manual-re-pin nudge should transition to the auto re-pin flow;check-self-bootstrap.ymlstays as a substrate-failure fail-safe.docs/integration.mdpost-#172 migration note — corrected to reflect empirically-observed Forgejo behavior: undeclared inputs toworkflow_callreusables are silently ignored. The lazy-leave shape (bump@<ref>past #172, forget to droptoolkit_ref:) runs cleanly. Dropping the stale input is a hygiene fix, not a correctness fix. Closes #250.Fixed
Fragment-check baked ref stuck at
mainfor v0.20.0 consumers — v0.20.0 shippedreusable-changelog-fragment-check.ymlwithBUILD_BAKED_TOOLKIT_REF: 'main'becausereusable-release.yml's three runtime bake-reset loops (added in #278) only listed the two pre-existing reusables. Impact for consumers pinning@v0.20.0on the fragment-check wrapper:.release-toolkitscripts checked out atmain(the baked value) rather thanv0.20.0— substrate drift class. Upgrade action: re-pin fragment-check to@v0.21.0(the normal post-cut re-pin) to resolve. Extendedtests/workflows.batsbake-marker guard now walksreusable-release.yml's runtime loops so the class can't reintroduce. (Fold-in from #283 work.)Auto re-pin loops corrupted external consumer wrappers — without a toolkit-self gate, the auto re-pin (new in #283) would rewrite
release.yml/manifest-check.yml/fragment-check.ymlon any external consumer's checkout, breaking their pin state and their next CI run's reusable resolution. Both path-α and path-γ auto re-pin loops are now gated onif [[ -f .forgejo/workflows/reusable-release.yml ]](the toolkit-self detection). Caught pre-merge; no external consumer was affected in the wild.Cold-Read linter dogfood wrapper mis-scoped pre-cut — the toolkit-self dogfood wrapper for the Cold-Read body linter was dropped from #289 because the pre-v0.21.0 window has no consistent pin target (
@mainbreaks single-ref-alignment;@v0.21.0-rc.Ndoesn't yet contain the reusable). Deferred to #290 (post-v0.21.0-cut fold), same pattern as #281.Internal
update-doc-version-refs.shself-git addremoved —release-prep.sh's #236 auto-stage sweeps hook-modified tracked files, so the belt-and-suspenders self-stage from #251 is redundant. Closes #253.Removed / Deprecated
None.
Upgrade
No action required for consumers on
@v0.20.0unless the Fragment-check baked-ref bug (see Fixed) applies — re-pinfragment-check.ymlto@v0.21.0in that case. The Cold-Read body linter and fragment template are opt-in.Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
Source code (ZIP)
-
Release v0.20.0
StableSome checks failedcheck-self-bootstrap / check (pull_request) Failing after 3smanifest-check / manifest-vs-tag consistency (pull_request) Successful in 5smanifest-check / check (pull_request) Successful in 0scheck-self-bootstrap / check (push) Failing after 3srelease / decide + act (push) Successful in 6srelease / release (push) Successful in 0sreleased this
2026-07-02 12:10:58 +02:00 | 1385 commits to main since this releaseFirst-cut reliability hardening. Every issue that surfaced on the first external toolkit-driven cut (tmux-tell) is now fixed at the substrate. Upgrade is a pin bump — fragment-check wiring is opt-in, everything else is transparent.
Added
Push-whitelist pre-flight on path-α cuts.
draft-release.shnow probes the consumer's default-branch protection before doing any work. Fails fast + names the missing identity ifrelease-botisn't onpush_whitelist_usernames, instead of the late mid-cutNot allowed to push to protected branchrejection that leaves the manifest desynced. Only fails on a definitive misconfig; warns-and-proceeds otherwise.docs/integration.mdnames it as a path-α precondition.reusable-changelog-fragment-check.yml+scripts/fragment-check.sh. Consumers wire it into theirpull_requestworkflow to fail-loud on unknown-kind fragments (e.g..documentation.md) before merge, instead of at the next cut. See docs/integration.md § fragment-check.yml for the consumer stanza. Closes #271.Changed
docs/operations.mdgained an annualrelease-botPAT rotation-cadence section. No action required on existing installs; consult before regenerating theRELEASE_TOOLKIT_TOKENActions secret. Closes #273.Fixed
External cuts no longer halt on the post-cut bake-reset step. The reusable's bake-reset blocks now guard
git commitwithgit diff --cached --quiet, so the empty-staging case (every external consumer — the bake-reset is toolkit-self-only by design) cleanly skips the commit + push instead of failing "nothing to commit" and cascading into the manifest never landing. This unblocks every external toolkit-driven cut. Toolkit-self behavior unchanged.forgejo_find_pr_by_headno longer mutates a random open PR. Forgejo'shead=query filter is empirically ignored, so.[0].numberwas picking whichever PR the API sorted first — releasing PATCHes onto a random open feature PR instead of the actual rolling PR. Now filters response client-side by exacthead.label/head.refmatch. No consumer-side change required. Closes #274.Rolling-PR prepare-commit push now authenticates with the path-α PAT. Previously it reused the
actions/checkoutsystem token, which Forgejo Actions' anti-recursion safeguard suppresses — so no CI ran on the rolling PR and its required checks could never satisfy. The push now injectsFORGEJO_TOKEN(theRELEASE_TOOLKIT_TOKENPAT) as an HTTPAuthorizationheader, mirroring the manifest push. Necessary but not sufficient — the consumer must still setRELEASE_TOOLKIT_TOKENto a real-user PAT (the documented path-α setup).release-decidedetects thechore(release): prepare vX.Y.Zcommit anywhere in the merged range, not only at HEAD. Previously, any commit landing on top of the prepare commit (a rebase nudge, a CHANGELOG dedupe) shifted HEAD off the prepare subject and the cut was silently skipped — the manifest stayed at the old version, no tag/release, stale rolling PR against the old baseline. The range scan is a full git-log walk. Existing Layer 2/3 safeguards still gate — a stale prepare commit in range falls through tomode=updateloudly. Squash-merge of the rolling PR is not yet covered; tracked as #259.Fragment vs conventional-commit duplicate suppressed at generation layer. When a fragment and a CC subject reference the same issue number,
release-prep.shnow suppresses the CC-subject bullet in favour of the fragment prose (richer wins). A[changelog-dedup]line is logged to stderr for auditability. Closes #258.release-prep.shPR body assembly now re-normalizes throughchangelog_merge_sectionsso any surviving duplicate### Kindheadings collapse to one section per kind. Belt-and-suspenders on top of the merge already done inchangelog_transition. Closes #272.Removed / Deprecated
None.
Upgrade
Pin your consumer wrapper's
uses:@<ref>tov0.20.0. Fragment-check wiring is opt-in (add.forgejo/workflows/fragment-check.ymlper docs/integration.md if you want the pre-merge gate). Everything else is transparent.Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
Source code (ZIP)
-
Release v0.19.0
Stablereleased this
2026-06-28 23:43:04 +02:00 | 1404 commits to main since this releaseChanged
config_validatenow rejects an unsupportedversion_filesbasename at config-load time. The version-file extraction layer (manifest-check read + release-prep write) keys on each entry's basename and handles onlyVERSIONandpackage.json; previously a config listing an unextractable basename (e.g.pyproject.toml,Cargo.toml) passed validation and then failed late at manifest-check or release-prep. The gate moves that failure to the earliest layer with a clear message naming the unsupported basename, the supported set, and a pointer to the TOML-support tracker (#252). Configs usingVERSION,package.json, orversion_files: [](tag-is-version mode) are unaffected.release-prep.shnow auto-stages tracked files thatpost_bump_hooksmodify, retiring the "hooks mustgit addtheir own changes" convention from #209. A hook just modifies tracked files; release-prep snapshots the content of every tracked file before the hook loop andgit adds any whose content changed, so the edits are committed with the cut. Existing self-staging hooks keep working unchanged (a secondgit addof the same change is idempotent).
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads