Skip to content

docs: recipes for rebasing, splitting and describing long-lived branches - #158

Merged
CybotTM merged 5 commits into
mainfrom
feat/retro-long-branch-rebase
Aug 10, 2026
Merged

docs: recipes for rebasing, splitting and describing long-lived branches#158
CybotTM merged 5 commits into
mainfrom
feat/retro-long-branch-rebase

Conversation

@CybotTM

@CybotTM CybotTM commented Aug 10, 2026

Copy link
Copy Markdown
Member

Summary

Five recipes from an eight-month-old merge request that was rebased onto a base 20 commits ahead and then split into eight MRs. Each one is a technique the session had to work out from scratch because the skill did not cover it.

Came from

/retro session on 2026-08-10: 3e729d81-7fec-4248-8f83-22e84ac39467
Findings: B16 (hard-won technique) x3, B18 (review-issue learning), A6 (user correction) x2, B15 (trigger-coverage gap)

  • Symptom: a 35-commit rebase with repeated conflicts and no end-state check; an earlier merge had silently reverted upstream work in four files and survived the rebase; the MR body carried four claims that no longer matched the diff, corrected twice by the user; two pipeline watchers ran ~40 minutes for a project whose CI was switched off; the skill never triggered despite the session being almost entirely rebase and MR work.
  • Cause: the skill covers rebase mechanics (interactive rebase, --onto, autosquash, rerere) but not how to know the result is correct, nor that a branch-favoured merge resolution is invisible afterwards. pull-request-workflow.md verifies behavioural claims but not that the body still matches the branch. merge-gate-watcher.md covers watchers whose event is late, not watchers whose event cannot occur.
  • Required behavior: build a reference merge and assert the rebased tree equals it; re-resolve suspect files against the true ancestor of the earlier merge; re-derive the PR body from git diff <target>...HEAD and delete sections for changes that no longer exist; confirm CI is enabled before arming a pipeline watch; verify a split by blob identity.
  • Verification: evals/evals.jsondetect_upstream_work_dropped_by_merge, rebase_long_branch_with_reference_merge, pr_body_must_match_current_diff, check_ci_enabled_before_watching_pipeline, verify_branch_split_by_blob_identity

Change

File Section
references/advanced-git.md reference merge for long rebases; detecting upstream work a merge dropped; blob-identity verification of a branch split
references/pull-request-workflow.md a long-lived PR body describes the branch it had, not the branch it has
references/merge-gate-watcher.md check the producer is switched on before arming the watcher
SKILL.md description gains "rebasing a long-lived branch onto a moved base or splitting one into several PRs"
evals/evals.json one scenario per new section

The reference-merge recipe uses git checkout <REF> -- <path> against a dirty tree, which advanced-git.md otherwise forbids. The new section says why this case is exempt (both sides of a conflicted file are committed objects) so the two do not read as contradicting each other.

Test plan

  • Build/Scripts/validate-skill.sh — 0 errors, 0 warnings
  • skill-repo/scripts/validate-evals.sh — 63 passed, 0 failed
  • tests/test_validate_git_command.py — 0 failures
  • pre-commit hooks ran on every commit (markdownlint, trailing whitespace, EOF)
  • SKILL.md at 497/500 words — noted in the commit so the next edit goes to a reference file
  • Reviewer check: the git merge-file --diff3 recipe reproduces on a branch with a Merge branch <base> commit

…nches

A /retro session on 2026-08-10 reviewed an eight-month-old merge request that
was rebased from 35 commits onto a base 20 commits ahead, then split into eight
MRs. Three techniques from it were not covered anywhere in the skill:

- Resolve a long rebase against a reference merge built once up front, and
  assert the final tree equals it. The assertion caught a duplicated
  autoload-dev block that Git had merged cleanly from two sides.
- Detect upstream work that an earlier "Merge branch <base>" dropped by
  resolving in favour of the branch. Nothing later surfaces it: from the next
  merge base the revert reads as an intentional branch edit. In the observed
  case four files silently lost an upstream phpstan commit and survived a
  faithful rebase.
- Verify a branch split by comparing blob ids per changed file rather than
  reading diffs, with a key-by-key parse for config files split by hunk.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
A body written months ago documents a state the branch has since left, and
nothing in the tooling notices. One MR reviewed in a /retro session on
2026-08-10 carried four false claims at once: a coverage-tool switch that had
been reverted, wrong image tags, wrong mutation thresholds, and a job marked
New that the target branch already had - which hid that the change also
lowered its memory limit from 2G to 512M.

Adds the rule to derive each claim from git diff <target>...HEAD, and to delete
the section for a change that no longer exists rather than rewording it into a
statement about something that does not change.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
… a watch

A watch whose event can never be produced is indistinguishable from one whose
event has not arrived yet. In a /retro session on 2026-08-10 two watchers ran
about 40 minutes for a merge request whose project had CI switched off, and the
status was reported as "no pipeline yet" instead of "no pipeline until someone
re-enables CI".

Documents the GitLab give-away: pipeline endpoints return 403 while every other
endpoint returns 200, and projects/:id reports jobs_enabled false with
builds_access_level disabled.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
The skill did not trigger in a session that was almost entirely rebase and
merge-request work, opened with "rebase, fix and update <MR url>". The
description said "handling merge conflicts", which does not obviously cover
rebasing a long-lived branch or splitting one into several PRs.

SKILL.md is now at 497 of the 500-word cap; further additions belong in a
reference file.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
One scenario per new section: dropped-upstream-work detection, the reference
merge for long rebases, re-deriving a stale PR body, checking CI is enabled
before watching for a pipeline, and blob-identity verification of a branch
split.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Copilot AI lite review requested due to automatic review settings August 10, 2026 05:18
@github-actions github-actions Bot added documentation Improvements or additions to documentation skill evals labels Aug 10, 2026
@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@CybotTM

CybotTM commented Aug 10, 2026

Copy link
Copy Markdown
Member Author

Bot-Review nicht verfügbar — von Hand geprüft und darauf entschieden.

Copilot hat auf 81756f3e zweimal mit Copilot was unable to review this pull request because the user who requested the review has reached their quota limit geantwortet. Das ist ein Kontingent, kein Ausfall — erneutes Anfordern ändert nichts. Nach references/merge-gate-watcher.md ist das keine Review, und der Check copilot-pull-request-reviewer steht laut isRequired(pullRequestNumber:158) auf keiner Pflichtliste.

Ich bin Autor dieses PRs; die folgende Prüfung ersetzt keine unabhängige Review und wird hier als das ausgewiesen, was sie ist.

Geprüft:

  • Alle acht Pflicht-Checks grün (Skill Validation, Eval Validation, CodeQL actions+python, gitleaks, Composer Audit, Opengrep, DCO).
  • Reine Dokumentation plus Evals; kein ausführbarer Code, keine Workflow-Änderung.
  • Jede Empfehlung nennt den Beobachtungsfall, aus dem sie stammt, und der git diff --stat <REF-sha> HEAD-Schritt ist die überprüfbare Zusicherung, nicht nur ein Ratschlag.
  • Der git checkout <ref> -- <path>-Hinweis widerspricht der Regel gegen pauschales git checkout -- . nicht: er ist pfadgebunden und begründet.

Ein Fund, der bleibt: im Split-Verifikations-Schnipsel steht for b in <branch-1> <branch-2> … mit einem echten Auslassungszeichen. Als Platzhalter neben <branch-1> konsistent, beim Kopieren aber ein literales Token. Nicht blockierend.

@CybotTM
CybotTM merged commit 53605f6 into main Aug 10, 2026
23 of 25 checks passed
@CybotTM
CybotTM deleted the feat/retro-long-branch-rebase branch August 10, 2026 06:07
CybotTM added a commit that referenced this pull request Aug 10, 2026
…erge recipe

Review of #158 found the dropped-upstream-work check scanning the wrong range.
It listed what upstream changed AFTER the merge; the work a resolution can drop
is what upstream changed BEFORE it. Reproduced on a purpose-built repo (upstream
commit touching f.txt and g.txt, dropped by a -s ours merge, plus one unrelated
later upstream commit):

  shipped:   DIFFERS: h.txt          <- unrelated; both dropped files missed
  corrected: DIFFERS: f.txt, g.txt

Whenever upstream has not touched the dropped files again - the common case -
the shipped loop printed nothing and read as an all-clear, which is the failure
the section exists to prevent. The candidate set now comes from the merge's own
parents, reusing the BASE the next snippet already computes.

Also in the same section pair:

- The reference-merge recipe could not run: git commit after a --no-commit merge
  exits 128 on unmerged paths. Adds git add -A, and pins REF as a tag so the only
  reference to it does not live in a prunable /tmp worktree.
- The exemption from "Never git checkout <ref> -- <path>" was too broad. It holds
  only on a path still carrying conflict markers, BEFORE it is edited; a
  hand-written resolution is destroyed with no reflog entry, which was verified.
  The rule at the top of the file now points forward to the exemption.
- Drops the --autosquash suggestion for empty commits: autosquash only reorders
  fixup!/squash! commits and cannot fold them.
- The split-verification loop word-split paths containing spaces into bogus
  entries and printed fatal: noise on deletions. Uses -z with read -d ''.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
CybotTM added a commit that referenced this pull request Aug 10, 2026
The runner is grep -qiE, case-insensitive and line-based, so several of the
patterns added in #158 matched any plausible answer: (reference merge|REF|...)
matches "prefer" and "refs/", (403|projects/) matches any GitLab answer, and
(stale|no longer|delete the section|remove) matches "remove".

rebase_long_branch_with_reference_merge scored 2 of 2 on an answer containing
none of the guidance, so it measured nothing. Each of the five entries now
asserts its distinctive claim and carries three assertions, matching the file's
norm. Re-tested against the same naive answer: all five now score 0.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
CybotTM added a commit that referenced this pull request Aug 10, 2026
fix(advanced-git): correct the dropped-work check from #158, and make the recipes testable
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation evals skill

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants