Skip to content

feat(lib)!: support mixed Graphite/gh-stack repos - #101

Open
lettertwo wants to merge 4 commits into
stack-merged-markerfrom
stack-model-mixed
Open

lettertwo wants to merge 4 commits into
stack-merged-markerfrom
stack-model-mixed

Conversation

@lettertwo

@lettertwo lettertwo commented Sep 16, 2026 •

Copy link
Copy Markdown
Owner

Summary

This PR lets one repository hold live Graphite and gh-stack branches at the same time. workon.stackModel = auto used to resolve any repo with both tools' artifacts to Graphite, which silently hid every branch gh-stack tracked. Detection now tie-breaks on which provider has ref-backed tracked branches, and a new StackModel::Mixed { primary } reads both providers' metadata with per-branch fallback. gh-stack is the primary provider: GitHub's native stack support removed the reason to treat Graphite's gt init as the more deliberate signal.

Detection

With only one tool's artifacts present, nothing changes. With both present, StackModel::detect reads each provider's liveness (graphite::has_live_branches / gh_stack::has_live_branches, which check parents keys against resolve::branch_exists and never probe the gt binary):

Graphite live gh-stack live Resolves to
yes yes Mixed { primary: GhStack }
yes no Graphite
no yes GhStack
no no GhStack (doctor explains)

The last row changes 0.13.x behavior, which resolved a doubly-stale repo to Graphite; hence the !.

An explicit workon.stackModel = graphite or gh-stack stays strict and never falls back. Two new values, mixed:gh-stack and mixed:graphite, pin Mixed with the named primary and skip the liveness read, so a repo that wants Graphite answering first can say so without losing gh-stack's branches. Bare mixed is rejected. The rule and its rationale are in ADR-028, "Detection: live-metadata tie-break".

Library

  • StackModel::providers() yields the providers to consult in fallback order. current_stack and assemble_changesets return the first provider with a row for the head branch. A read error from either provider propagates rather than falling through, since a corrupt store is a failure and not an empty result.
  • enumerate_stacks under Mixed returns the primary's stacks followed by the secondary's, dropping any secondary stack that shares a branch with a primary one. display::build_tree dedupes by visited, so without this a shared branch would land non-deterministically.
  • provider_has_live_branches is public so the CLI can ask the same liveness question detect does.

CLI

  • new registers a fork with whichever provider already tracks its base branch, checked in providers() order. No base, or a base neither provider knows, falls to the primary. gh-stack's symlink plumbing still runs whenever gh-stack is one of the providers, regardless of which one owns the fork.
  • doctor's BothStackToolsDetected now reports what auto resolved to and each provider's liveness. A new StackModelPinHidesLiveBranches check fires when an explicit pin hides the other provider's live branches, and a mixed:<provider> pin whose primary has no artifacts gets the same treatment as stackModel = graphite without gt init.
  • list prints a dimmed stderr hint under the same pin-hides-branches predicate. Mixed itself stays quiet, since both providers are already visible.

Testing

Detection tests cover all four cells of the table plus ghost (unresolvable) branches on each side. Config tests cover the two mixed: values and the rejected forms. CLI tests cover fork registration following the parent's provider under Mixed (and falling to gh-stack when no provider knows the base), the doctor liveness report and pin checks, and the list hint. The recipe in docs/recipes/stacked-diffs.md describes the user-facing behavior.

@lettertwo
lettertwo changed the base branch from main to stack-merged-marker September 16, 2026 14:36
@lettertwo
lettertwo added this pull request to stack #103 September 16, 2026 14:36
@lettertwo lettertwo changed the title feat: support mixed stack models feat(lib): resolve mixed Graphite/gh-stack repos with live-metadata tie-break Sep 16, 2026
@lettertwo lettertwo changed the title feat(lib): resolve mixed Graphite/gh-stack repos with live-metadata tie-break feat(lib): support mixed Graphite/gh-stack repos Sep 16, 2026
@lettertwo lettertwo changed the title feat(lib): support mixed Graphite/gh-stack repos feat(lib)!: support mixed Graphite/gh-stack repos Sep 16, 2026
@lettertwo
lettertwo force-pushed the stack-model-mixed branch 2 times, most recently from a9ec8e8 to bea298f Compare September 16, 2026 15:47
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