Skip to content

docs(workflow): root feature branches off dash, never main - #48

Merged
mhenrixon merged 1 commit into
dashfrom
chore/branch-off-dash
Jul 29, 2026
Merged

mhenrixon merged 1 commit into
dashfrom
chore/branch-off-dash

Conversation

@mhenrixon

Copy link
Copy Markdown
Collaborator

Summary

Feature branches now always root off dash, never off main.

The old rule rooted them off main to keep them upstream-PR-able. That bought
little and cost a lot:

  • The .claude/ toolkit is committed on dash, so every feature branch started
    without it. CLAUDE.md carried a whole subsection teaching you to
    git restore --source=dash --worktree -- .claude CLAUDE.md and then remember
    never to commit the result.
  • A main-rooted branch starts without the fork's merged features, so work gets
    written against a codebase the fork does not actually run.
  • /finish-prs and /github-review-pr both had to carry a caveat that merging
    dash into a feature branch "pollutes its upstream diff".

Rooting off dash removes all three.

Upstreaming still works

This is the one thing the old rule was actually protecting, so it is replaced
rather than dropped. .claude/rules/upstream-sync.md now extracts the feature's
own diff instead of relying on the branch point:

git checkout -b pr/<feature> main
git diff dash...feat/<feature> | git apply -3      # the feature's changes only
git status                                         # review before committing
git commit -a -m "<upstream-facing message>"

The three-dot dash...feat/<feature> diffs from merge-base(dash, feat/<feature>)
to the branch tip. The merge-base is a commit on dash, so fork identity, the
toolkit, and other merged features all fall out of the diff.

This was verified empirically, not assumed — including the case that could
plausibly break it (a branch that merged dash forward, with dash having moved
on afterwards):

Commit Where In extracted diff?
feat work 1 branch, before the forward-merge ✅ yes
dash work 1 dash, merged into the branch ❌ no (correct)
feat work 2 branch, after the forward-merge ✅ yes
dash work 2 dash, after the branch's last merge ❌ no (correct)

git diff --stat tmp-dash...tmp-feat returned exactly FEATURE_A.txt +
FEATURE_B.txt. The scratch branches were deleted afterwards.

Files changed

File Change
CLAUDE.md Never/Always rules; /lfg row; toolkit section now says "inherited automatically"
.claude/rules/git-workflow.md branch-model table, PR workflow, added NEVER root off main rule
.claude/rules/upstream-sync.md branch roles, sync loop merges dash not main, rewrote "Upstreaming a feature"
.claude/commands/lfg.md Phase 0 branch setup, Phase 7 upstreaming note, checklist
.claude/commands/finish-prs.md dropped the obsolete upstream-diff-pollution caveat (x2)
.claude/commands/github-review-pr.md same caveat in the conflict-resolution step
.claude/commands/github-review-comments.md, architect.md, security.md one line each

Remaining git merge main references are all the legitimate dash <- main
sync path and were deliberately left alone. Upstream now reaches a feature
branch only through dash: upstream/main -> main -> dash -> feat/*.

Deviations & judgment calls

  • Rewrote the upstreaming recipe rather than deleting it. The user asked to
    change where branches root, not to abandon upstreaming. merge --squash onto
    main would now drag all of dash into the PR, so it had to be replaced with
    the three-dot extraction. If upstreaming is in fact dead for this fork, that
    whole section can go — say so and I will drop it.
  • Kept the git restore --source=dash snippet in CLAUDE.md, rescoped to
    pr/<feature> and old main-rooted branches. It is still the only way to get
    the toolkit onto a main-rooted branch, which the upstreaming flow creates.
  • Left /perf's "baseline vs main" untouched — that is a benchmark
    reference point, not a branch-rooting rule.
  • Docs-only change, so no rubocop/unit-test run is reported. Nothing under
    lib/ or test/ was touched.

Feature branches previously rooted off `main` to stay upstream-PR-able.
That bought little and cost a lot: the `.claude/` toolkit lives on `dash`,
so every feature branch started without it and needed a manual
`git restore --source=dash` to make slash commands load; branches also
started without the fork's merged features, so work was written against a
codebase the fork does not actually run.

Feature branches now always root off `dash`. Upstreaming stays possible —
it just extracts the feature's own diff (`git diff dash...feat/<feature>`,
whose merge-base is a `dash` commit) instead of relying on the branch
point, which also drops the "merging dash pollutes the upstream diff"
caveat that /finish-prs and /github-review-pr had to carry.

Upstream still reaches features only through dash:
upstream/main -> main -> dash -> feat/*.
@mhenrixon
mhenrixon merged commit 99c96c3 into dash Jul 29, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant