DocsWorking with projects

Project Git client

The project view puts a full git client on your repository's main checkout — a commit graph with branches, tags, and stashes, plus pull, push, staging, context-menu branch surgery, and in-app conflict resolution.

This is the project-level counterpart to the session's Git tab: that one manages a single session's worktree branch, while this one manages the repository itself. Throughout this page is Cmd on macOS and Ctrl on Windows and Linux.

Open the project view

Click a project row in the left sidebar. This opens the project view and expands the project's sessions — it never collapses them. To collapse or expand a project without opening it, click the small chevron on the row instead; the two are separate targets, so the chevron never opens the view.

The header shows the project's name and repository path, a New session button, and an × to close the view. Below it sit three tabs:

⌘1Switch to the Dashboard tab
⌘2Switch to the Git tab
⌘3Switch to the Terminal tab

These share their default combos with the session tab shortcuts — a session and a project are never in view at the same time, so they don't conflict, and each is rebindable on its own. Plexus remembers which tab you left open per project.

The Dashboard tab

The Dashboard tab is the global dashboard's session table scoped to this one project: every unarchived session with its live activity dot, branch, and PR badge, per-project summary counts in the header, the same sort modes, and a New session button. Click a row to jump to that session. See Dashboard.

The Git tab

The Git tab is laid out in three resizable panes: the refs panel on the left (branches, remotes, worktrees, stashes, tags), the commit graph in the center, and a detail pane on the right showing whichever commit — or your uncommitted work — is selected. A toolbar with the branch switcher and sync actions runs across the top. Diffs never squeeze into the detail pane: clicking a file there opens its diff full-width in place of the refs panel and graph — see The detail pane.

Everything operates on the project's primary checkout — the folder you registered as the project — never on a session's worktree. Plexus keeps the tab current on its own: after its own operations, whenever you return to the window, and — while the tab is open — by checking every few seconds for git activity from your sessions or an outside terminal. New commits from your remotes arrive on their own too, through automatic fetching. The toolbar's refresh button forces a fetch and reload any time.

The commit graph

The center pane draws the repository's full history as a lane graph, GitKraken-style: colored lanes trace each branch line — running unbroken through the merges that join them — and each commit renders as a dot with the author's avatar inside, ringed in the lane's color. Merge commits stay small hollow dots. The commit's subject fills the row, with a compact relative age (2h, 3d) on the right edge. The graph is virtualized and extends itself as you scroll — deep histories load in pages automatically, with no Load more button to press.

Branch and tag labels sit in a fixed column on the graph's left edge, each tied to its commit's dot by a thin connector line in the branch's color. A branch gets one label wherever it lives, with presence icons telling you where: a computer icon when the branch exists locally, a cloud icon when it exists on a remote, and both together when local and remote point at the same commit — hover the label for the full remote-qualified names. A branch that exists only on a remote shows the bare branch name with just the cloud icon, so a glance still tells you whether a tip is only on your machine, only on the remote, or both. The checked-out branch's label is highlighted with a check mark, and tags keep their tag icon. Right-click a label and you get that branch's or tag's own context menu — the same actions as its row in the refs panel; right-clicking anywhere else on the row still gives you the commit menu. A row with several refs shows the first label and folds the rest into a +N badge — hover it, click it, or focus it and press Enter for a small panel listing the folded refs, each with the same right-click menu. Click a folded branch to check it out; clicking a folded tag jumps the graph to its commit instead, because checking a tag out detaches HEAD and that stays a deliberate menu action. Double-click a branch label to check the branch out — a remote label with no local branch yet creates a local tracking branch first; a remote label whose local branch already exists switches to that local branch and fast-forwards it to the remote (a pull), leaving it untouched if the two have diverged. Either way it matches checking the branch out from the refs panel.

Branch labels can also be dragged onto one another: drop one branch's label on another's and a menu offers the actions that fit that pair. Tags can't be dragged, and a drop with nothing to offer simply does nothing.

  • Fast-forward the dragged branch to the target — offered when the dragged branch is local; it refuses cleanly if the two have diverged.
  • Push the dragged branch to the target's remote branch — offered when the dragged branch is local and the target exists on a remote; it pushes your commits onto that remote branch even though the names differ. The push is never forced — it refuses if the remote branch has commits the dragged branch doesn't.
  • Merge the dragged branch into the target, or rebase the dragged branch onto the target — offered for any two different branches, and always in the direction you dragged (dropping develop on accept offers Merge develop into accept). Because git can only merge or rebase the checked-out branch, Plexus first checks out the receiving branch (for a merge) or the moving branch (for a rebase) when it isn't already current — so after Merge develop into accept you end up on accept. Both use the same confirm dialogs as the context menus: merge offers --no-ff, and conflicts flip the tab into conflict resolution as usual.
  • Reset the current branch to the target's tip (Soft / Mixed / Hard) — offered only when you drag the checked-out branch itself; a hard reset keeps its typed confirmation.
  • Start a pull request from the dragged branch's remote counterpart to the target's — offered when both branches exist on the same remote. A small dialog asks for a title (required) and an optional description, then Plexus creates the pull request on your provider — GitHub today — using the same authentication as the session-level Pull requests flow, and the success toast links to the new PR. Unlike the session flow, there's no AI-drafted description here.

Operations that change the working tree ride the usual busy-checkout guard.

The Uncommitted changes row is pinned at the top with a live count of changed files — click it to open the staging pane. An empty repository shows No commits yet; the row for uncommitted work still works, so you can stage and make the first commit from here.

Author avatars

Avatars come from Gravatar, matched by a one-way SHA-256 hash of each commit author's email — the address itself is never sent, results are cached on disk, and authors without a Gravatar get locally-drawn initials on a stable color.

Avatar lookups are the only network requests this tab makes beyond your git remotes. Turn them off with the global Show commit author avatars from Gravatar setting (Settings → Git & PRs) and Plexus renders initials only, with no request at all — see Settings and the Privacy Policy.

The detail pane

Selecting a commit fills the right pane with a header — the author's avatar, the sha, the commit's parents, and a changed-file count — above the list of changed files, switchable between a flat List and a folder Tree. Selecting a commit never opens a diff by itself.

Click a file and its diff opens full-width, replacing the refs panel and commit graph; the detail pane stays put on the right, so you can step through the commit's files without losing your place. The diff follows the Unified / Split toggle above it — one app-wide preference shared with the Review tab. Close the diff with its or press Escape to return to the graph.

Selecting Uncommitted changes works the same way: the detail pane holds the staging lists and commit composer, and a clicked file's diff — or a conflicted file's resolve pane — takes the full-width spot while you keep staging and committing from the right.

The refs panel

The left panel lists every ref in collapsible sections, each with a count: Local branches, one section per remote (e.g. origin — those sections are also where remotes are added, edited and removed), Worktrees, Stashes, and Tags. Names containing / nest into folders, so feature/login and feature/search group under feature. The Filter refs… box at the top narrows every section at once.

Clicking a branch or tag jumps the graph to its commit; right-clicking opens its context menu — the same menu the matching label carries in the graph; double-clicking a branch checks it out (a remote branch with no local copy gets a local tracking branch first; one that already has a local branch switches to it and fast-forwards it to the remote). Branch rows also drag onto one another for the same drop menu as the graph — handy when the branch you want to merge into, rebase onto, or push is scrolled out of view in the graph. Local branch rows also carry the sync state against their upstream: / ahead/behind counts, plus a cloud icon when the branch is fully on its remote or a computer icon when its latest commits exist only locally. The Worktrees section lists the repository's linked worktrees and their branches — with Plexus, that's typically one per session. Each row names the session that owns it, or reads project checkout for the repository itself. A row owned by an archived session says so — archiving never removed the worktree, so that folder is what restoring the session would resume into. A worktree whose folder git can no longer find is struck through and badged missing; one that has been locked carries a locked badge with the reason. Right-clicking any row opens its context menu, which is where you clean both of those up — see When a branch is locked to a worktree.

Hovering a stash row reveals Apply, Pop, and Drop actions. Drop asks for a second click (the button flips to Drop? for a moment) instead of a dialog. Stash rows also have a right-click menu with those same two actions plus Create branch from stash… and a Drop… that confirms in a dialog naming the stash — see Context menus.

Remotes

Each remote the repository is configured with — origin, an upstream you added, a mirror on a network share — gets its own section in the refs panel, holding the branches Plexus last fetched from it. The section header is the remote itself: hover it to see the URL it points at, and the separate push URL underneath when it has one.

Right-click that header to manage it:

  • Edit remote… — rename it, point it at a different URL, or give it a separate push URL so fetches and pushes go to different places. Clear the push URL again by emptying the field.
  • Add remote… — add another one, by name and URL. An HTTPS or SSH URL, or a path to a local repository, all work.
  • Remove remote… — drop it from this repository.
  • Copy URL / Copy remote name — for pasting into a terminal or a message.

Adding a remote doesn't contact it. The dialog's Fetch after adding switch (on by default) runs an ordinary fetch straight afterwards, so its branches show up right away — but the two are separate steps, and a URL typo or a credential problem is reported as a failed fetch against a remote that was still added successfully, rather than as an add that half-worked.

If the repository has no remotes at all, the refs panel says so and offers Add remote… there; the same item sits in the Pull button's menu, since with nothing to pull from there is no section header to right-click.

Renaming is the safe rewrite: git moves the remote's branches to the new name (upstream/main becomes fork/main) and repoints every local branch that was tracking them, so nothing is lost and nothing needs re-setting afterwards.

If a remote's URL has a password or token embedded in it, Plexus shows the URL without it — and the Edit dialog leaves that field empty, with the stripped URL as a hint. Leave it empty and the stored URL, credential and all, is kept exactly as it is; type a new one and it replaces the whole thing, so include the credential if you still need it there. The same guard costs one thing: a push URL that stores a credential can't be cleared from this dialog, because its field starts empty either way. A remote that git is configured to fetch from — or push to — at several URLs at once can't be edited here at all: Plexus disables the field and says so, because changing one of those at a time isn't something git can do.

Removing a remote deletes the copies of its branches on your machine and clears the upstream of every local branch that was tracking one. The confirmation spells that out first — it lists the branch copies that go, counts the locals that lose their upstream, and says how many running sessions share the configuration you are about to change. Your own branches and their commits stay exactly where they are, and nothing changes on the server — the remote repository, and everyone else's copy of it, is untouched.

Remotes belong to the repository, not to a session: every session of this project works in a linked worktree of the same checkout, so adding, renaming or removing one changes it for all of them at once, immediately. Renaming or removing the remote called origin costs one more thing — Plexus resolves a project's pull requests through origin, so its record of which PR belongs to which session is cleared, along with the PR badges showing it. Nothing is lost on the provider: the links come back on the next PR refresh, worked out from wherever origin now points. See Pull requests.

The toolbar

  • Branch switcher — shows the checked-out branch (or a short commit id with a detached badge). Open it to filter and check out another local branch, or pick Create branch… to branch from the current head, optionally checking it out immediately.
  • Pull — a split button. The main click runs your default action; the arrow opens the full menu with the same four actions as the Default Pull action setting: Fetch all (download only) (all remotes, pruning deleted branches), Fast-forward if possible (ff), Fast-forward only (ff-only), and Rebase. The Default action picker in the same menu saves your choice for this project — it's the Default Pull action setting (Settings → Git & PRs), which defaults to Fast-forward if possible and can also be set globally in Settings. Pull disables with an explanatory tooltip when there's nothing it could do — no remotes, a detached HEAD, or a branch with no upstream.
  • Push — pushes the current branch to its upstream, with / ahead/behind counts alongside. If the branch has no upstream yet, a Publish branch? prompt offers to push it to origin and set the upstream in one go. If the remote has diverged — you amended, rebased, or reset a branch that was already pushed — git rejects the push and Plexus asks first: a Force push? prompt offers to overwrite the remote with --force-with-lease, pinned to the exact remote state that rejection saw — if anyone else pushes in the meantime, the force push fails instead of overwriting their work. Cancel to leave the remote untouched. If the remote holds work you haven't fetched at all, Plexus doesn't offer the force — fetch first, then decide.
  • Stash / Pop — stash all changes including untracked files, or pop the newest stash. Individual stashes are managed from the refs panel.
  • Refresh — fetch from your remotes, then reload the graph, refs, and status. Use it when you want to be certain you're looking at the latest, rather than waiting for the next automatic fetch. Because you asked for it, this fetch authenticates exactly like Fetch all does — it can use your credential helper or ask for an SSH key passphrase, where a background fetch never will. If the fetch couldn't run — another git operation is already using the repository, it has no remotes, or a leftover lock file is blocking it — Plexus says so rather than quietly showing you the same local state again.

Every one of these talks to your remotes with your own git credentials. If your machine has none for an https remote, a connected provider is tried as a fallback — and if that doesn't work either, the error names the host that refused and what to do next, rather than reporting a password prompt you never saw.

Next to Refresh, a small note tells you how fresh what you're looking at actually is — "Fetched 3m ago", or "Never fetched" for a repository nothing has fetched into yet. This matters more than it sounds: the / counts are worked out against the copy of the remote on your machine, so "↓0" only means "nothing to pull as of the last fetch". The note tells you when that was. It spins while a fetch is running and turns amber, with the reason in its tooltip, when something is wrong: "Fetch failed" after a few failures in a row — a broken remote URL, an expired token, or simply being offline — or "Fetch blocked" when a leftover .lock file in the repository is stopping fetches from running at all (close any other git process using the repository; if none is running, delete the leftover lock file the tooltip describes). Both warnings are about automatic fetching, so they go away if you turn it off — the note then just keeps telling you how long ago the repository was last fetched, by anything.

When you are behind, the ↓N count is clickable: one click runs your default Pull action for those commits.

Automatic fetching

Plexus fetches from your remotes in the background so the commit graph and the ahead/behind counts stay current without you asking. It only downloads — nothing is merged, checked out, reset, or deleted, and no branch is ever removed, so a fetch can never change your files or lose work.

Two speeds, because they answer different questions:

  • the project whose Git tab you have open is fetched about once a minute — that's where a stale count is on screen in front of you;
  • your other projects are fetched about every ten minutes, so their graphs are already right when you switch to them.

Fetching pauses while the Plexus window is hidden, slows down while the window is in the background, and stands aside whenever a git operation of your own is running — it will never make one of your actions wait or fail. It also leaves your SSH setup alone: if you've configured your own ssh command for git, background fetches use it exactly as your own commands do. A background fetch will never prompt you for anything — no password box, no key passphrase — so a remote that needs one is simply left for Refresh or Fetch all, where you're there to answer. A connected provider is the exception that needs no answer from you: an https remote on GitHub or Bitbucket authenticates with that connection in the background, exactly as it would on Refresh. If a fetch fails, Plexus says nothing: it backs off, keeps trying more slowly, and shows it on the freshness note rather than interrupting you.

Because a fetch only downloads, it never moves your own branches: after one, origin/main is current but your local main is exactly where you left it. That's the gap the New session dialog's pull toggle closes — Pull base branch first when the session cuts a new branch, Pull the branch first when it starts on an existing one — see Pull before you start.

Turn it off for one project from the Pull button's menu — Fetch automatically — or globally, along with both intervals, in Settings → Git & PRs. See Settings.

Search the history

The box above the commit graph finds commits by message, author name or email, or commit id — a short prefix is enough. Results replace the graph with a plain list, newest first, and searching covers the whole repository rather than only the part of the history you've scrolled to.

The lane graph can't be drawn for a filtered set of commits — the lines between commits only mean something when their neighbours are present — so search deliberately shows a list instead. Clear the box (or press Escape in it) to return to the graph exactly where you were. With the box already empty, Escape does whatever it would normally do — closing a full-width diff, for instance — rather than being swallowed by the search field.

Stage and commit

Select Uncommitted changes (the pinned top row) to open the staging pane. Files group into Staged, Unstaged, and Conflicted sections with per-file and per-section stage/unstage buttons; clicking a file opens its working-tree diff in the full-width view.

Inside a diff, every hunk carries its own Stage hunk / Unstage hunk button, so you can split one file across several commits. Untracked files are the exception — they have no hunks yet and stage as a whole.

Discard changes

There are three ways to throw work away, and all of them confirm first.

One or more files. Right-click a changed file and choose Discard changes…, or select files and use the header button. Selection works like a file manager: click to select, Ctrl/Cmd-click to toggle individual files, Shift-click to select a range; once something is selected the header's Stash button is joined by Discard (N). Right-clicking a file that's already part of your selection acts on the whole selection — the menu entry says so, reading Discard 3 files… — while right-clicking outside it selects just that file first. Discard reverts modified and deleted files to the last commit and deletes new or untracked files from disk (there's no committed version to restore); the confirmation lists every affected path.

Everything at once. With nothing selected, the header offers Discard all instead. It returns every tracked file to the last commit and, unless you turn the switch off in the dialog, deletes every new file from disk — including new files you've already staged, which have never been committed either. Empty folders left behind by those files go too.

A single hunk. In the full-width diff, each hunk on the unstaged side carries a Discard hunk button next to Stage hunk. It reverts just those lines and leaves the rest of the file — and anything you've already staged in it — untouched.

Discard can't be undone, and nothing is stashed on your behalf. If you might want the changes back, cancel and use Stash instead — it's right next to the discard button and fully reversible.

Files ignored by .gitignore are never touched — not by Discard, not by Discard all, not behind any switch. That includes node_modules/, build output and local .env files. Since those never appear in the file list, a confirmation dialog couldn't show you what it was about to delete, so Plexus doesn't offer it at all; run git clean -xfd in the Terminal tab if you really want that.

Discard is blocked while an agent session is running on the main checkout unless you confirm the override — the same guard as checkout and reset. Discard all additionally refuses while a merge, rebase, cherry-pick or revert is in progress: finish or abort it from the conflict banner first. To discard a staged hunk, use Unstage hunk and then discard it from the unstaged side, where you can see the combined result before confirming.

The composer below takes a summary and an optional description. The AI button drafts both from the staged diff (tune it with the AI commit message instructions setting under Settings → Git & PRs), and Commit lands the staged files.

Amend

The composer's Amend switch rewrites the head commit instead of creating a new one: toggling it on prefills the message from the current head (unless you've already typed), and an amend may be message-only — no staged files required.

Amending a commit that's already on the remote rewrites published history — the composer warns you when the head commit has been pushed, because the next push will be rejected as a non-fast-forward. Pushing then offers the Force push? confirm (--force-with-lease) covered under the toolbar.

Context menus

Right-click gives each surface its own menu. There are eight: branches, remotes, tags, stashes, and worktrees in the refs panel, commits in the graph, and changed files in the staging pane — and the branch and tag menus follow their labels into the graph, folded refs in the +N panel included, so a right-click on a ref offers the same actions wherever you find it. On a commit row, the ref labels take the right-click and the rest of the row opens the commit menu.

Entries spell out what they will act on — "Merge into main…", "Delete from origin…" — so the labels below stand in <placeholders> for the part that varies. Anything that acts on the checked-out branch is greyed out when there isn't one, on a detached HEAD, and destructive entries always confirm before running.

Local branches — "Checkout <branch>" · "Create branch here…" · "Pull" (only on the branch you're on, and only with an upstream) · "Fast-forward to <upstream>" · "Push" · "Merge into <current>…" · "Rebase <current> onto this…" · "Set upstream…" · "Rename…" · Delete → "Delete local…", "Delete remote only…", "Delete local and remote…" · "Copy branch name" / "Copy sha" · "Create tag here…".

  • "Fast-forward to <upstream>" catches a branch up to its remote without checking it out and without touching your working tree — so you can bring main up to date while you keep working on your feature branch. It appears when the branch has an upstream and is behind it, and it only fast-forwards: a branch that has diverged is left alone.
  • "Delete remote only…" deletes the branch on the remote and keeps yours — the usual tidy-up after a merged pull request. It's available on the branch you're currently on, too; only local deletion needs you to be somewhere else first.
  • Deleting or renaming a branch that belongs to a session warns you first, naming the session.

Remote branches — "Checkout as local branch" (creating the local tracking branch, or switching to an existing one and fast-forwarding it to the remote) · "Create branch here…" · "Fast-forward <current> to this" (offered when it's the current branch's upstream) · "Merge into <current>…" · "Rebase <current> onto this…" · "Delete from <remote>…" · "Copy branch name" (the full origin/… name — what you'd paste into a git command) / "Copy sha" · "Create tag here…".

Remotes — on a remote's section header, not on the branches under it: "Edit remote…" · "Add remote…" · "Remove remote…" · "Copy URL" (what the header shows — a credential stored in the URL is never copied along) / "Copy remote name". See Remotes.

Commit rows — "Checkout commit" (detaches HEAD) · "Create branch here…" · "Create tag here…" · "Cherry-pick commit" · "Revert commit" · "Reset <current> to this commit" (Soft / Mixed / Hard — a hard reset discards work, so it demands a typed confirmation) · "Copy sha" / "Copy short sha" / "Copy subject" / "Copy message" (subject and body, the way git writes it).

Tags — "Create branch here…" · "Checkout tag" (detaches HEAD) · "Push to <remote>", one entry per remote · "Copy tag name" / "Copy sha" · "Delete tag locally…" · "Delete from <remote>…", again one per remote. The two deletions are deliberately separate: the local one only affects this checkout, while deleting from a remote removes the tag for everyone who fetches it.

Stashes — "Create branch from stash…" · "Apply" · "Pop" · "Copy message" · "Drop…".

  • "Create branch from stash…" asks for a name, then creates that branch where the stash was made, checks it out, applies the stash into it, and drops the entry — the clean way out of a stash that no longer fits the branch you're on.
  • Apply and Pop are the same actions as the row's hover buttons. "Drop…" is not: the menu entry opens a confirmation dialog naming the stash, while the hover button keeps its quicker two-step click.

Changed files — "Stage file" or "Unstage file", whichever side the file is on · "Copy path" / "Copy file name" · "Discard changes…". On a conflicted file the staging entries give way to "Take ours (whole file)" / "Take theirs (whole file)", and discard is greyed out — resolve it first, or discard the whole file from the header.

  • The two halves of the menu answer to different things, which the labels spell out: staging always acts on the one file you right-clicked, while discard acts on your whole selection — so with three files selected the entry reads "Discard 3 files…" next to a plain "Stage file".

Worktrees — "Copy path" · "Remove worktree…" · "Prune stale worktree entries…".

  • "Remove worktree…" deletes the worktree's folder from disk and clears git's record of it, which releases the branch it was holding. The dialog offers to delete that branch too (off by default). That branch delete is the safe kind: if the branch still carries commits that aren't merged anywhere, git keeps it and Plexus tells you — the worktree is gone by then, so the follow-up dialog offers to delete just the branch, spelling out that its commits go with it. The repository's main checkout can't be removed here, and neither can a worktree with a running session in it — stop that session first, even if that session belongs to another project on the same repository. A session that is in the middle of starting or stopping is refused the same way; try again once it settles. Removing one that belongs to a stopped session asks you to confirm, naming the session. An archived session's worktree removes without that extra confirmation — reclaiming those leftovers is what this section is for — but the dialog says whose it is and warns that restoring that session will no longer be able to resume it. Either way the session stops pointing at the folder you just removed, so it offers a fresh Start rather than a Resume that could only fail.
    Two things can stand in the way of a removal, and each gets its own confirmation: a folder that belongs to a stopped session, and a folder with uncommitted or untracked work in it. Confirming one never waives the other — if both apply, you'll be asked twice, once in each set of words.
  • "Prune stale worktree entries…" is repo-wide and touches nothing on disk. It only clears git's records for worktree folders that are already gone, and it tells you how many it cleared. The confirmation lists every record it will clear. Locked entries are left out of that list: a lock is how git marks a worktree that lives on removable or network storage and is only temporarily missing, so clearing one is a separate switch in the dialog — and the toast says how many locked entries it kept. Like Remove, it also stops any session that still pointed at a pruned folder from offering a Resume into it.

When a branch is locked to a worktree

git refuses to delete or check out a branch that is checked out in any worktree — including one whose folder has been deleted behind git's back. That second case is the confusing one: git names a path that no longer exists, so there's nothing to go and look at.

If deleting or checking out a branch fails with "already checked out at …", look for that path in the Worktrees section. A row badged missing means only git's record survives — use "Prune stale worktree entries…" to clear it (if that row is also badged locked, turn on the dialog's switch for locked entries). A row that's still really there needs "Remove worktree…" instead (or, if a session owns it, remove that session).

Plexus clears its own leftovers automatically: on startup it drops the records for any worktree it created that has since disappeared. It deliberately leaves worktrees you made yourself alone, even when their folder is missing — a worktree on an unplugged drive looks exactly the same, and cleaning it up is your call, not the app's.

Detached HEAD

"Checkout commit" and "Checkout tag" leave you on a detached HEAD — you're looking at that exact snapshot, with no branch to record new commits on (a commit isn't a branch, and neither is a tag, so there's nothing for further commits to advance). The branch switcher shows the short commit id with a detached badge, and everything that acts on the current branch — Pull, Push, merge, rebase, reset, cherry-pick, revert — greys out until you check a branch out again.

Detaching costs you nothing: your branches stay exactly where they are, and checking one out puts you straight back. But a commit you make while detached belongs to no branch and is easy to lose sight of — use Create branch here… on the commit or tag instead if you mean to build on it.

Conflict resolution

A merge, rebase, cherry-pick, revert, pull, or stash pop that hits conflicts doesn't fail — the tab switches into conflict mode and lets you resolve everything in place.

An amber banner appears under the toolbar naming the operation and counting the conflicted files remaining. While it's up, the toolbar and branch switcher are disabled and the view stays on your uncommitted changes, where conflicted files are listed in their own section.

Each conflicted file offers three ways out:

  • Ours / Theirs on the file row — take one side whole, no questions asked. (Binary or very large files resolve this way only.)
  • Hunk picker — click the file and its resolve pane opens in the full-width view, each conflict shown as side-by-side ours and theirs cards, labeled with where each side came from. Pick Take ours, Take theirs, or Take both per conflict; once every conflict has a choice, Apply resolution writes the file, and the default-on Mark resolved after applying switch stages it in the same step.
  • Edit file — switch the picker to a full editor to resolve the markers by hand, then Save & mark resolved.

When no conflicted files remain, the banner's action button finishes the operation — Commit merge, Continue rebase, Continue cherry-pick, Continue revert, or Done for a stash pop (which then drops the now-applied stash). A rebase that spans several commits may stop again on the next conflict; the banner simply stays up with the new file list. Abort (with a confirmation) backs the whole operation out and restores your working tree — a popped stash survives an abort.

A conflicting stash Apply is the one case with nothing to continue or abort: the stash is kept either way, so there's no banner — just resolve the conflicted files and stage them, and you're done.

The busy-checkout guard

Sessions started on the root tree run their agent directly in the same checkout this tab operates on. If such a session's agent is running, any operation that would change the working tree — checkout, pull, merge, rebase, reset, revert, cherry-pick, stash apply/pop, and continuing or aborting a conflict — is stopped first with an "An agent session is running on this checkout" dialog naming the session.

That's a guard, not a wall: Cancel leaves everything untouched, while Continue anyway runs the operation regardless — do that only when you're sure the agent won't trip over files changing underneath it. Operations that never touch the working tree — fetch, push, staging, committing, and tag work — are never blocked.

The Terminal tab

The Terminal tab opens plain shell terminals rooted in the project's root directory — the same primary checkout the Git tab operates on, never a session worktree. The shells are kept warm in the background, so a dev server or watcher you start here keeps running as you move around the app; add, close, and rename tabs the same way as the session's bottom terminal. See Project Terminal.

  • Project Terminal — root-level shells on the project's main checkout.
  • Session Git — the per-session git tab for a worktree branch.
  • Pull requests — how Plexus tracks a session's PR, and what changing origin resets.
  • Dashboard — the global session table; the project view scopes it down.
  • SettingsDefault Pull action, Show commit author avatars from Gravatar, and the AI commit prompt.
  • Keyboard shortcuts — the project tab bindings.