Repository navigation
feat(git): git tools on the terminal toolbar — fetch, fast-forward pull, status, switch - #177
Merged
Merged
Conversation
…ll, status, switch When a session's folder is a git repo, its terminal toolbar shows a chip, "⎇ main ● ↑2 ↓5" (branch, dirty dot, ahead/behind). Clicking it opens a menu: a summary header, Fetch, Pull (fast-forward only), Status…, Switch branch ▸, Copy branch name and, when code.cmd is on PATH, Open in VS Code. Hidden for SSH sessions. Deliberately read-mostly: no commit, push or merge. A Claude session is usually editing the same tree, and a one-click history write from outside its conversation is a race and an unrecoverable misclick. Pull is --ff-only --no-rebase; on a diverged branch or a conflicting local edit git refuses and a panel under the toolbar shows git's output plus a short hint. Nothing is typed into the terminal: every operation is its own background git process. - The poll is now one `status --porcelain=v2 --branch` instead of branch --show-current + status --porcelain (two spawns), and also yields upstream, ahead/behind and the change list. GetGitInfoAsync keeps its old contract on top. New SessionViewModel fields follow GitBranch: plain properties announced only through GitInfoVersion. - Every git spawn sets GIT_TERMINAL_PROMPT=0 (a credential prompt can never be answered); read-only calls also set GIT_OPTIONAL_LOCKS=0 so a background poll no longer takes index.lock and breaks a command the user runs at the same moment. Both are merged into WSLENV so the git inside WSL sees them. - A timed-out git run kills the whole process tree (git-remote-https / ssh children used to survive). - Switch runs `switch --no-guess -- <name>` (verified with a branch named -x). - One operation per repo at a time, keyed by RepoRoot; afterwards every pane on that repo re-reads git state, since a fetch only moves remote refs. Tests: GitToolsTests — porcelain v2 parser on captured output, wording, argv round-tripped through CommandLineToArgvW, and end to end against a throwaway bare remote (fast-forward; refusing a diverged branch with pull.rebase=true; refusing to overwrite a local edit; the -x branch; a remote-only branch --no-guess must not invent). Removing -- or --no-guess fails 6 tests each. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NsYm9iLc2aRnRDfV2uZRQX
Both launch-failure paths (WebView2 start, PTY start) removed the pane from the grid but left the entries BuildTerminalWrapper had registered in _runControls and _gitPanes. The run-control leak predates this branch; the git one would have joined it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NsYm9iLc2aRnRDfV2uZRQX
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When a session's folder is a git repo, its terminal toolbar shows a chip —
⎇ main ● ↑2 ↓5(branch, dirty dot, ahead/behind) — just left of ▶. Clicking it opens a menu: a summary header (main → origin/main · ↑2 ↓5 · 3 changed), Fetch, Pull (fast-forward only), Status…, Switch branch ▸, Copy branch name and, whencode.cmdis on PATH, Open in VS Code. Hidden for SSH sessions.Why
Checking whether a repo is behind, pulling, or switching branch meant typing into the terminal — and in a Claude session that text lands in Claude's prompt.
Implementation notes
--ff-only --no-rebase— on a diverged branch or a conflicting local edit git refuses, and a panel under the toolbar shows git's own output plus a short hint (GitStatusText.FailureHint).GitService.branch --show-current+status --porcelain(two spawns); it is now onestatus --porcelain=v2 --branch, which also yields upstream, ahead/behind and the change list. Since ~90% of a git call is process start-up, that is cheaper and richer.GetGitInfoAsynckeeps its old contract on top. NewSessionViewModelfields followGitBranch: plain properties, announced only throughGitInfoVersion.GIT_TERMINAL_PROMPT=0(an HTTPS credential prompt could never be answered and would sit until the timeout); read-only calls also setGIT_OPTIONAL_LOCKS=0, so the background poll no longer takesindex.lockand breaks a git command the user or Claude runs at the same moment. Both are merged intoWSLENVso the git inside WSL sees them.git-remote-https/sshchildren used to outlive it).switch --no-guess -- <name>:--because a ref can legally be named-x;--no-guessso a remote-only name doesn't silently create a tracking branch.RepoRoot, so worktrees share it); afterwards every pane on that repo re-reads git state, since a fetch moves only remote refs, whichGitRepoWatchernever sees._runControls/_gitPanesentries (the run-control leak predates this branch).GitStatusTextrow.Test plan
GitToolsTests: porcelain v2 parser on captured output (incl. CRLF, detached, unmerged, upstream gone); wording; argv round-tripped throughCommandLineToArgvW(hostile and option-shaped branch names); end to end against a throwaway bare remote — fast-forward, refusing a diverged branch even withpull.rebase=true, refusing to overwrite a local edit, the-xbranch, the remote-only branch--no-guessmust not invent.--or--no-guessfails 6 tests each. (Removing--no-rebasefails none — git 2.54 already lets--ff-onlywin; kept as a guard for other versions.)_; long branch name in a narrow 2×2 pane.🤖 Generated with Claude Code
https://claude.ai/code/session_01NsYm9iLc2aRnRDfV2uZRQX