| ⇧R ⇧F ⇧U ⇧P | Refresh, Fetch, Pull (update), Push |
| ⇧O | Switch repository |
| ⇧B ⇧D | Fold the branch list, or commit details, away |
| ⇧E | Expand the panel to the window, or put it back |
| ⇧K | Filter branches |
| ⇧M ⇧W ⇧S | Manage remotes, worktrees, stashes |
| ⇧C ⇧X | Clear a multi-commit selection; diff the two selected |
| ⇧G ⇧V ⇧A | Put the cursor in the graph; pick commits; show what the selection changed |
| ⇧T | Check out a branch |
Shift alone is only a modifier, so Shift-click still extends a selection in the graph, and a capital letter typed in the branch filter is still a capital letter. Nothing here shadows one of your VS Code bindings: Ctrl, Cmd and Alt combinations are left alone.
Drive the graph without the mouse
⇧G puts a cursor on a commit — the one you already had selected, or the newest — and from there the graph behaves like any other list.
| ↑ ↓ | Move the cursor. It selects nothing, so you can read your way down a branch without the panel doing any work |
| Home End | Newest commit, oldest commit |
| PgUp PgDn | A screenful at a time |
| Enter | The left click: select this commit and show what it changed |
| ⇧Enter | The right click: this commit's menu. Menu and ⇧F10 do it too |
Picking several. ⇧V turns Space into a picker and says so in a banner. Move with the arrows, Space to tick a commit in or out, and nothing is sent anywhere while you choose — that is the point of the mode. Enter then shows the combined changes and leaves; Esc leaves and keeps your picks without asking for anything.
⇧A asks for the selection's changes at any time, however the selection was made — the way back to the Changes view once you have scrolled off it.
The cursor is deliberately not the selection. A cursor that selected as it moved would spawn a worktree per keystroke; this one costs nothing until you press something.
Give the graph the room
The panel is short and splits its width three ways. Either side pane folds away with the thin handle beside it — the handle stays where it is when the pane is gone, so the way back is where the way out was — and the graph takes the space. GitHawk remembers which panes you had.
Height is the other half of the problem, and it belongs to the workbench rather than to us: the ⇕ button in the toolbar — or ⇧E — grows the panel to the window and puts it back. VS Code has its own chevron for this in the panel's title bar; a graph is the one thing in there that always wants the height, so it gets a control where you are already looking.
Review a whole branch, or any set of commits

- Click a branch → "Review my work against …" — everything your branch adds relative to that one, measured from the merge base, including work you have not committed yet.
- Cmd/Ctrl-click several commits, or Shift-click for a run. Their combined changeset appears automatically — selecting is the request, there is no button. They do not have to be next to each other.
- "Compare … with …" — any two branches, tags, or commits, directly. Neither
side has to involve where you currently are, so you can sit on
mainand compare two other branches.
The tree always states how the comparison was made, because a merge-base diff, a direct diff, and a reconstruction answer different questions.
Act on branches and commits

Click a branch, or right-click a commit, and you get a native VS Code menu — grouped by topic, with your keyboard shortcuts and theme, not a menu drawn inside a webview.
The branch labels drawn on the graph are the same click target as the branch list, so a branch is actionable wherever you happen to be looking at it. Both offer "Copy branch name" — a webview cannot be text-selected, and a branch name is what gets retyped into a checkout, a PR description, or a CI filter.
On a commit: create a branch or tag here, check it out, cherry-pick, revert, reset, copy the hash. On a branch: push, pull, check out, merge, rebase, rename, delete, or delete it on the remote.
Push and pull are per branch, and always there. The Sync group at the top
of a branch's menu offers both every time, with the state in the description —
3 behind, nothing to push, already up to date — rather than appearing only
when there is something to do. A branch that has never been pushed offers
"Publish" instead, which sets its upstream so the next push needs no arguments.
There is no --force anywhere, so git refusing a non-fast-forward is left to
refuse.
main is behind while you are on a feature branch? That does not need a
checkout. Pulling a branch you are not standing on writes the ref directly — your
working tree, index, and HEAD are untouched — and the menu says so. The branch list
shows ↓ behind, ↑ ahead, or gone at a glance, and
GitHawk: Update All Branches From Upstream does every eligible one at once.
Anything destructive asks first, and says what will be lost.
Put work aside
Stash entries appear in the graph as rows of their own, hanging off the commit the work was left on, and in the sidebar beside the branches and worktrees. All four sidebar sections — local, remote, worktrees, stashes — are always there, each folding away and remembering it, and each saying what it is for when there is nothing in it. Remote, Worktrees and Stashes carry a Manage button.
GitHawk: Manage Stashes lists the stash with what each entry says it is,
the branch it was made on, and when. An entry git named itself — WIP on main: 1234abc … — is marked (unnamed), because that wording describes the commit
the work was sitting on rather than the work.
Apply an entry from the list in one click, or open it for the rest: show what is in it in the Changes tree, apply, pop, or drop. Stashing asks for a message and whether to include untracked files, which is never the default — it is the one variant that sweeps up a scratch file you had not thought about.
Popping and dropping ask first. Both remove the entry, and a dropped entry survives only as a dangling commit.
A stash entry is a commit, so showing what is in it is the same comparison machinery as everything else — it lands in the Changes tree and opens in the diff editor.
Manage remotes
Manage on the sidebar's Remote section, or GitHawk: Manage Remotes.
Either lists every remote with its URL, and a remote with a
separate push URL — the fork workflow, reading from upstream and writing to your own
copy — shows both, because being shown one of two is how you push somewhere you did
not mean to.
Add, rename, re-point, or remove one; fetch a single remote with pruning from the list without opening anything; or prune deleted branches without fetching. Removing a remote and pruning both ask first: they delete tracking refs, and nothing in the reflog brings those back.
Work across several repositories

Open a folder of projects and GitHawk finds the repositories inside it. The name at
the left of the toolbar switches between them; so does
GitHawk: Switch Repository. Switching moves everything with it — graph,
menus, comparisons, and the Changes tree.
Submodules, linked worktrees, and repositories nested inside a monorepo are all
found. How deep it looks is gitHawk.repositoryScanDepth.
Keep up with the repository
Commit in a terminal, check out from the Source Control view, let an agent rebase in a worktree — the graph reloads on its own. GitHawk watches git's metadata, not your working tree, and waits for an operation to finish rather than redrawing on every step of a rebase. Your place in the history is kept: the row you are looking at stays where it is instead of sliding down as commits arrive above it.
Manage worktrees

A worktree is a second directory with a different branch checked out, sharing one repository. They stay niche because git's errors are opaque — it refuses a checkout because of a directory you deleted last month, and tells you only that the branch "is already used by worktree at …".
GitHawk names the rule instead:
- A branch checked out in another worktree is badged in the branch list, so you can see before clicking that a checkout would be refused. Its menu offers to open that worktree instead.
- A Worktrees section appears in the sidebar once you have more than one,
flagging
lockedandmissing. - Any free branch offers Create a worktree for …, suggesting a sibling of the repository named after the branch.
- A worktree whose directory is gone is reported as
missingwith a Prune entry — until that record is cleared, git keeps refusing its branch everywhere.
Each row has buttons to open a new VS Code window, open a terminal, or start an AI CLI there — Claude Code, Codex, Gemini CLI, and opencode by default, configurable. That is the one place AI appears in GitHawk: launching your tool in the right directory. It reads nothing and sends nothing.
In the editor
Three keys that work where the code is, rather than in the panel. All three are chords under ⌘K (Ctrl+K on Windows and Linux), and none of them was already bound by VS Code.
| ⌘K B | Blame on, and off again |
| ⌘K H | Who wrote this line — the same card the mouse gets, at the caret. Works whether or not the annotations are on |
| ⌘K G | Show this line's commit in the graph |
They are also in the editor's right-click menu, under GitHawk, which is where the keys announce themselves — a shortcut nobody can find is a shortcut nobody has. The hover card names ⌘K G beside its "show in the graph" link for the same reason.
⌘K G follows the file rather than the panel: a workspace usually holds more than one repository, and if the file you are reading is in a different one, GitHawk switches to it and then shows the commit.
Settings
| Setting | Default | What it does |
|---|---|---|
gitHawk.commitLimit |
500 |
How many commits to read. Higher shows more and loads slower. |
gitHawk.blame.style |
off |
Blame in the editor: column for IntelliJ's annotate, endOfLine for one label per block. |
gitHawk.autoRefresh |
true |
Reload the graph when the repository changes outside GitHawk. Watches git's metadata, never your working tree. |
gitHawk.repositoryScanDepth |
2 |
Directory levels below each opened folder to search for repositories. 0 searches the folders only; 2 covers a folder of projects, or a folder of buckets each holding projects. |
gitHawk.aiTools |
Claude Code, Codex, Gemini CLI, opencode | Commands offered by "Start an AI CLI here". |
Commands
| Command | |
|---|---|
GitHawk: Open Git Graph |
Cmd+9 / Ctrl+9 |
GitHawk: Toggle Blame Annotations |
Cmd+K B / Ctrl+K B |
GitHawk: Refresh Git Graph |
Also rescans for new repositories |
GitHawk: Switch Repository |
|
GitHawk: Check Out A Branch |
The branch list as a picker |
GitHawk: Who Wrote This Line |
Cmd+K H / Ctrl+K H |
GitHawk: Show This Line's Commit In The Graph |
Cmd+K G / Ctrl+K G |
GitHawk: Manage Worktrees |
|
GitHawk: Manage Remotes |
Add, rename, re-point, remove, fetch, prune |
GitHawk: Manage Stashes |
List, show, apply, pop, drop; stash the working tree |
GitHawk: Show Uncommitted Changes |
Everything uncommitted, against HEAD |
GitHawk: Start An AI CLI Here |
|
GitHawk: Update All Branches From Upstream |
Fast-forwards every branch that can be |
GitHawk: Show Log |
GitHawk's own output, when something goes wrong |
Known limitations
Honest list, in the order they are likely to annoy you:
- No row virtualisation. A large
commitLimitrenders every row; 500 is fine, 5000 is not. - A conflicting merge or rebase leaves you mid-operation. GitHawk reports git's message but offers no abort or resolution.
- One repository at a time — there is no combined view across several.
- Repositories are found by scanning on load, not watched. One cloned while the window is open needs a refresh.
Contributing
Bug reports and pull requests are welcome — issues. See CONTRIBUTING.md for the architecture, how to run it locally, and how the three tiers of tests work.
Licence
MIT — see LICENSE. Actually MIT, in the sense that you may fork it, ship it, and sell it.



