Skip to content

Compare branches: a branch picker in the switcher, with stack-base suggestions - #1

Merged
kylekz merged 2 commits into
kylekz:mainfrom
Method-es:feat/branch-picker
Oct 29, 2026
Merged

kylekz merged 2 commits into
kylekz:mainfrom
Method-es:feat/branch-picker

Conversation

@Method-es

@Method-es Method-es commented Oct 28, 2026 •

Copy link
Copy Markdown

Summary

A repository's switcher rows end with Compare branches… (also in the source picker ⇄ ▾). It turns the switcher into a two-step picker: a local branch, then the base to compare it with. Picking the pair opens or resumes its branch review.

Each branch is offered against its stack base: the nearest unmerged branch below it (main → feat-a → feat-b: feat-b vs feat-a), else the default branch. The bases step lists the stack base, then the default branch, then every other local branch. Choosing the default branch stores no base, so it resumes the switcher's existing Branch row's review instead of starting a second one.

Why

The CLI can already review any branch against any base (dv review new --branch feat-b --base feat-a), and PLAN §2.2 has branch <b> [vs <base>] as a target. The app could only offer the checked-out branch against the default branch, so reviewing a stack of branches meant leaving the app.

How

  • dv_core::git::branches: local branches (for-each-ref) plus every branch's stack base from one git log --branches --simplify-by-decoration ^<default>. That keeps only the commits a branch points at outside the default branch and rewrites parents to the nearest such commit, so a branch's first rewritten parent is its stack base. It takes about 50 ms on a 411-branch repo.
  • Reviews reads them with each row refresh (RepoRow::branches), so the picker is a plain view over loaded data.
  • switcher::branches: the picker is a mode of the switcher (Mode::{Repos, Branches, Bases}), reusing its panel, filter, keys and automation targets. Esc steps back (bases → branches → repos) and closes from the branches step when it was opened from the source picker.
  • The palette skips the picker's rows.
  • Specs: DESIGN §4.1 (switcher, source picker), PLAN §2.2 ("Branches and stack bases") and §11.
  • Automation: state.switcher.mode and each row's detail, state.source_picker.compare; documented in tests/e2e/README.md.

Testing

  • New: 4 dv_core tests (stacks, no default branch, branches sharing a tip, ordering), 5 switcher tests (listings, plus keyboard-driven gpui tests that open a stacked review with only that branch's files), e2e switcher_branches with screenshots of both steps in dark and the branches in light.
  • review_chrome.jsonl line 14 now expects the new detail: null: it compares a whole switcher row exactly.
  • On macOS (Apple silicon): cargo clippy clean in all three shapes, cargo test --workspace passes, all e2e scenarios pass. Two runs of script/check failed on different dv_backend client::tests::lifecycle tests (10 s event timeouts) while the machine was under heavy load. The crate isn't touched here, and those tests pass alone on both main and this branch, and in a later full workspace run. A few e2e scenarios needed a rerun after "no frame within 10s" while the window was covered.
  • Tried by hand on a demo stack (main → feat-a → feat-b → feat-c, plus hotfix).

Not run: script/check --linux / --linux-gui and the Windows gates (no Windows or WSL machine here).

…ts stack base

A repository's "Compare branches…" row, also in the source picker, turns the switcher
into a picker over its local branches, then the bases the picked one can be compared
with, opening or resuming the branch review of the pair. Each branch is offered against
its stack base (the nearest unmerged branch below it, found for every branch with one
git log --simplify-by-decoration ^<default>), else the default branch; a default-branch
base stores no base, so it resumes the Branch row's review. Esc steps back. DESIGN §4.1,
PLAN §2.2 and §11; state.switcher mode and detail, source_picker.compare;
switcher_branches.
@kylekz

kylekz commented Oct 29, 2026

Copy link
Copy Markdown
Owner

honestly wasn't expecting anyone to find this let alone make PRs. you seem legit from looking you up and i'm not seeing anything sketchy, so thanks for these. CI is running, i'll fix the conflicts once it's done

@Method-es

Copy link
Copy Markdown
Author

honestly wasn't expecting anyone to find this let alone make PRs. you seem legit from looking you up and i'm not seeing anything sketchy, so thanks for these. CI is running, i'll fix the conflicts once it's done

Haha; I was looking to make a similar tool, and decided to see if someone else already had. I really like it and started using it but had to make a few tweaks for my workflow. Much appreciated. Not sure what your intentions/directions are, so please let me know if you aren't a fan of any approach I make.

main gained repo removal in the switcher (a hover x on the header and
Shift Delete). Both stay; removal is the repositories' list's only: the
branch picker's header has no x and Shift Delete there removes nothing,
since the header is the repository the picker compares in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kylekz

kylekz commented Oct 29, 2026

Copy link
Copy Markdown
Owner

only thing left to do was github syncing but i'm still 50/50 on doing it at all, since it works really well for now just local-first. haven't really thought of anything else, it's been pretty good as-is for the last couple weeks

@kylekz
kylekz merged commit 9edec64 into kylekz:main Oct 29, 2026
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.

2 participants