docs: recipes for rebasing, splitting and describing long-lived branches - #158
Conversation
…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>
|
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
|
Bot-Review nicht verfügbar — von Hand geprüft und darauf entschieden. Copilot hat auf 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:
Ein Fund, der bleibt: im Split-Verifikations-Schnipsel steht |
…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>
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>
fix(advanced-git): correct the dropped-work check from #158, and make the recipes testable



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
/retrosession on 2026-08-10:3e729d81-7fec-4248-8f83-22e84ac39467Findings: B16 (hard-won technique) x3, B18 (review-issue learning), A6 (user correction) x2, B15 (trigger-coverage gap)
--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.mdverifies behavioural claims but not that the body still matches the branch.merge-gate-watcher.mdcovers watchers whose event is late, not watchers whose event cannot occur.git diff <target>...HEADand delete sections for changes that no longer exist; confirm CI is enabled before arming a pipeline watch; verify a split by blob identity.evals/evals.json—detect_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_identityChange
references/advanced-git.mdreferences/pull-request-workflow.mdreferences/merge-gate-watcher.mdSKILL.mdevals/evals.jsonThe reference-merge recipe uses
git checkout <REF> -- <path>against a dirty tree, whichadvanced-git.mdotherwise 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 warningsskill-repo/scripts/validate-evals.sh— 63 passed, 0 failedtests/test_validate_git_command.py— 0 failuresgit merge-file --diff3recipe reproduces on a branch with aMerge branch <base>commit