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 two tabs:

⌘1Switch to the Dashboard tab
⌘2Switch to the Git 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 pair 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 refreshes the tab automatically after its own operations and whenever you return to the window, so git activity from an outside terminal shows up too; the toolbar's refresh button forces a 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. A row with several refs shows the first label and folds the rest into a +N overflow. 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 other branch into the current one, or rebase the current branch onto the other — offered when either side of the pair is the checked-out branch (git can only merge or rebase the checkout). 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 git.avatars.gravatar setting 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. 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), 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; 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). 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.

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.

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: Fetch all (all remotes, pruning deleted branches), Pull (fast-forward if possible), Pull (fast-forward only), and Pull (rebase). The Default action picker in the same menu saves your choice for this project — it's the git.pull.defaultMode setting (fetchAll / ff / ffOnly / rebase, default ff), so you can also set it 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. Pushes are never forced — if you amended or reset a branch that was already pushed, git will reject the push and you'll need to resolve that outside Plexus, by design.
  • Stash / Pop — stash all changes including untracked files, or pop the newest stash. Individual stashes are managed from the refs panel.
  • Refresh — force-reload the graph, refs, and status.

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.

The composer below takes a summary and an optional description. The AI button drafts both from the staged diff (tune it with the git.commit.aiPrompt setting), 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.

Context menus

Right-click gives each surface its own menu. Destructive entries always confirm before running.

Local branches (refs panel): Checkout · Create branch here… · Pull / Push · Merge into the current branch… · Rebase the current branch onto this… · Set upstream… · Rename… · Delete (local, or local and remote in one go) · Copy branch name / sha · Create tag here…. 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) · Fast-forward the current branch to this (offered when it's the current branch's upstream) · Merge into the current branch… · Rebase the current branch onto this… · Delete from the remote….

Commit rows (graph): Create branch here… · Create tag here… · Cherry-pick commit · Revert commit · Reset the current branch to this commit (Soft / Mixed / Hard — a hard reset discards work, so it demands a typed confirmation) · Copy sha / short sha / subject.

Tags: Push to a remote · Delete · Copy name / sha.

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.

  • Session Git — the per-session git tab for a worktree branch.
  • Dashboard — the global session table; the project view scopes it down.
  • Settingsgit.pull.defaultMode, git.avatars.gravatar, and the AI commit prompt.
  • Keyboard shortcuts — the project tab bindings.