The changelog merges by union, so a sibling merge no longer costs a hand-resolved rebase - #461
Conversation
Every merge of one open PR turned the others DIRTY on CHANGELOG.md (four hand-resolved rebases on 2026-08-30), and a DIRTY PR gets no CI run. .gitattributes now declares CHANGELOG.md merge=union: git keeps both sides' bullets instead of raising a conflict, so a rebase onto main goes through untouched — verified on the #458 and #459 rebases with the same attribute set locally. The rule that keeps union safe (add on top of your category, never rewrite existing lines in passing) stands in the file's header, CLAUDE.md and copilot-instructions.md.
There was a problem hiding this comment.
🟡 Changes recommended
Multiple docs currently state “never conflict / no longer conflict” as an absolute, but union merges can still duplicate lines and may not be honored by GitHub’s mergeability check, so the wording should be softened to avoid a misleading guarantee.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR configures Git’s built-in merge=union driver for CHANGELOG.md to reduce churn and manual conflict resolution when multiple PRs add [Unreleased] entries, and documents the accompanying “add-only” rule across the repo’s contributor guidance.
Changes:
- Add
CHANGELOG.md merge=unionto.gitattributesto make concurrent changelog bullet additions merge without conflicts in local Git merges/rebases. - Document the “add on top, don’t rewrite existing lines” rule in
CHANGELOG.md,CLAUDE.md, and.github/copilot-instructions.md. - Add a
[Unreleased]changelog entry describing the change.
File summaries
| File | Description |
|---|---|
.gitattributes |
Declares CHANGELOG.md merge=union and explains the safe-usage rule. |
CHANGELOG.md |
Documents the union-merge behavior and adds an [Unreleased] entry about the change. |
CLAUDE.md |
Updates contributor guardrails to mention the union merge behavior and the add-only rule. |
.github/copilot-instructions.md |
Mirrors the guardrail update for Copilot-driven contributions. |
Review details
Suppressed comments (1)
CHANGELOG.md:32
- This changelog entry claims sibling PRs "no longer conflict" and that rebases go through "untouched". Union merges can still yield duplicated lines (and GitHub’s DIRTY/CLEAN check may not apply the driver), so the entry should describe this as a conflict-reduction measure for local merges/rebases rather than a guaranteed end to conflicts.
- **The changelog merges by union — sibling PRs no longer conflict in it.**
Every merge of one open PR used to turn the others `DIRTY` on
`CHANGELOG.md` (four rebases with hand-resolved conflicts on 2026-08-30
alone), and a DIRTY PR gets no CI run. `.gitattributes` now declares
`CHANGELOG.md merge=union`: git keeps both sides' bullets instead of
- Files reviewed: 4/4 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Review on #461: no absolute "never conflict" — a local merge or rebase resolves itself, GitHub's own mergeability check may still flag the PR until then, and a line changed on both sides appears twice; the header, the entry, CLAUDE.md and copilot-instructions.md say so in one voice.
|
Agreed — reworded in one voice across the header, the entry, |
There was a problem hiding this comment.
🟢 Approval recommended
The change is a small, well-scoped Git attribute/workflow documentation update with no functional runtime impact and consistent documentation updates across the repo.
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 0 new
- Review effort level: Lite
… the release cut — sibling merges stop conflicting (#462) * Changelog fragments: one file per PR under changelog.d/, folded in at the release cut Every PR used to add its bullets under [Unreleased] of the one shared CHANGELOG.md, and every sibling merge conflicted the others exactly there. The union merge driver (#461) heals the local rebase, but GitHub's mergeability check ignores merge drivers and a branch that moves changelog lines came out of the rebase duplicated. Removing the shared spot is the fix: a PR adds changelog.d/<slug>.md in the changelog's own format and touches nothing else. tools/changelog (stdlib only): `check [--base REF]` is the CI gate — a fragment per PR, or a release cut, or data-only, and no bullet written into [Unreleased] directly; `preview` prints the pending section; `release X.Y.Z --title …` folds the fragments newest-first under the new heading, bumps pyproject.toml, uv.lock and CITATION.cff and deletes the fragments. New CI job "Changelog (fragment)", skipped by the skip-changelog label. Rules moved in CHANGELOG header, CLAUDE.md, copilot-instructions, the open-pr gate, .gitattributes, werkzeuge.md, the glossary and sprachregelung §4. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012TVu1uouGhsjKCEVhWBinX * Add the PR reference to the fragment Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012TVu1uouGhsjKCEVhWBinX * The gate's git calls fail loudly An unfetched base ref made `git diff` fail, which read as an empty diff and let the PR pass — the one silent pass the gate must not have (Copilot finding on #462). The gate's calls are now required and raise with git's stderr; only the fragment-date lookup stays best-effort. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012TVu1uouGhsjKCEVhWBinX --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
What
.gitattributesdeclaresCHANGELOG.md merge=union. Two PRs that each add bullets under[Unreleased]no longer conflict: git keeps both sides (ours first, then theirs) instead of raising a conflict, so a rebase ontomaingoes through untouched.The one thing union cannot judge is a line that BOTH sides changed — it would appear twice. The rule that keeps union safe therefore stands in three places (the file's header,
CLAUDE.md,.github/copilot-instructions.md): add a new bullet on top of its category, never rewrite existing lines in passing.Why
Every merge of one open PR turned the others
DIRTYonCHANGELOG.md— four hand-resolved rebases on 2026-08-30 alone — and a DIRTY PR gets no CI run at all (GitHub cannot build the merge commit). Owner's ask: „könnten wir das irgendwie selbstheilen machen".Verified
With the same attribute set locally (
.git/info/attributes) the rebases of #458 and #459 ontomainafter the #457 merge went through with zero conflicts; the resulting[Unreleased]holds every bullet exactly once (checked by count), gates green on both.Open question — one thing this cannot promise
Whether GitHub's own mergeability check honours
merge=union(it applies its own merge when computing DIRTY/CLEAN; built-in drivers may or may not be respected). If it does, sibling PRs simply stay CLEAN after a merge. If it does not, the PR still shows a conflict in the UI, but the local rebase is one command and needs no hands — still self-healing from our side. The next sibling merge will tell; if GitHub ignores it, the robust next step is changelog fragments (changelog.d/<pr>.md, assembled at release time), which touch no shared file at all.