Skip to content

Graph

The graph is tt-git’s main view. It shows the history of every branch, remote branch and tag as one GitLens-style graph, newest commit first, with one row per commit. Branches keep their column from top to bottom, so you can follow a line by eye. From here you open a commit’s details, filter the history down to one author or one file, and start a branch, merge, rebase or cherry-pick at the selected commit. Press 1 to focus it from anywhere.

The graph pane with its title, lanes, badges, subjects, author and date columns called out

Each row is one commit:

● [side] side experiment Test User 2h b66
◉─╮ main <v1.0> Merge 'feature' Test User 3h 59f
│ ● [feature] feature work Test User 1d 788
● │ main work Test User 1d f75
●─╯ base Test User 2d b29

From left to right:

  • Lanes: where the commit sits in the history, and how it connects to its parents.
  • Badges for the branches and tags that point at it.
  • The subject, the first line of the commit message.
  • The author, how long ago it was committed (now, 5m, 3h, 2d, 3w, 4mo, 2y) and the short hash.

On a narrow pane the author moves ahead of the other columns, so the subject stays readable.

Merge commits are dimmed: their subject, author, date and hash are drawn in gray, so the commits that did the work stand out. Their badges and the ◉ in the lanes keep their colors.

The title tells you what you’re looking at: Graph [all] 12/4031 means every branch is shown and the 12th of 4,031 loaded commits is selected. A filter adds to it, for example Graph [all · author Ada · file src/] 3/120. While a load is running the title ends in loading….

A close-up of graph lanes showing a commit, a merge, a lane ending and a lane opening

Every line of history has its own column and color, and keeps that column for as long as it runs. Branches go straight down instead of shifting sideways as other branches start and end.

GlyphMeans
●A commit
◉A merge commit (more than one parent)
│A line of history passing through this row
─╯A line ending here: it joins this commit
─╮A merge opening a new line for its other parent
…More lanes than fit (see max_lanes below)

A commit with nothing above it in its column is a branch tip. Each new tip and each merge’s extra parent gets the next of eight colors.

Only the first 16 lanes are drawn; wider histories collapse into …. You can change that with max_lanes in the configuration file.

A close-up of the badges for the checked-out branch, a local branch, a remote branch and a tag

Badges sit between the lanes and the subject:

BadgeMeans
main on greenThe branch you have checked out
HEAD on redA detached HEAD
[feature] (green)A local branch
[origin/main] (magenta)A remote branch
<v1.0> (yellow)A tag

Symbolic refs like origin/HEAD are left out, since they only repeat another badge. When a row is too narrow for everything, badges are dropped before the subject is.

Press a to switch between two views:

  • all shows every branch, remote branch and tag.
  • current shows only HEAD and its upstream, so you can see what you’d push or pull without the rest of the repository in the way.

The title shows which one you’re in: Graph [all] or Graph [current]. To leave the upstream out of the current view, set current_includes_upstream = false in the configuration file.

The Unmerged and Merged tabs of the branches pane use the graph to show a single branch. While they do, the title shows that branch’s name, and a goes back to the full graph.

You don’t have to leave the graph to get there. With the graph focused, ] and [ (or } and {) step the branches pane to its next or previous tab, as they do in the branches pane itself. Focus stays on the graph, so you can flip to Unmerged or Merged and watch the graph follow.

The Filter graph popup listing authors with their commit counts

Press f to open Filter graph. It has two tabs, Author and File; tab switches between them. You can set one or both, and a commit has to match both.

  1. Press f.
  2. Type part of a name or path. The list narrows as you type.
  3. Pick an entry with ↑ ↓.
  4. Press enter. The graph reloads with only the matching commits.

With the mouse, click an entry to filter by it straight away, or click Author or File to switch tabs. The wheel moves the selection, and a click outside the popup closes it without changing the filter.

  • Authors are listed with the most commits first. Each person appears once, even if they’ve committed under several email addresses, as long as your .mailmap says they’re the same person.
  • Files lists every tracked file, with each folder listed just before the first file in it. Pick a folder, such as src/components/, to see every commit that touched anything under it.
  • Matching ignores case. Entries that contain what you typed come first, then entries that only match it as a sequence of letters, so apcmp still finds app/components/.
  • Deleted files aren’t in the list, since only files that still exist are. If nothing matches on the File tab, enter uses what you typed as the path, so you can still see the history of a file that’s gone. The popup says so: no matches · enter shows commits that changed ….

When a filter is set, the first entry on its tab is Any author or Any file, which clears just that part. To clear the whole filter, close details and press esc in the graph.

The graph filtered to a folder, with the filter shown in its title

A file filter keeps the lanes joined up: each commit links to the nearest earlier commit that also touched the path, so you still get a readable graph. An author filter can’t do that, so each run of one person’s commits is its own short line. Renames aren’t followed. If no commits match, the graph says no commits match the filter (f to change it, esc to clear it).

The New branch dialog opened from the graph

These keys act on the selected commit:

KeyDoes
enterOpens the commit fullscreen: its changed files on the left, the selected file’s diff on the right. See Details.
spaceShows or hides the commit’s details.
oChecks out the commit. See Checking out a commit.
nMakes a new branch at the commit and switches to it. tab in the dialog makes it in a new worktree under .worktrees/ instead.
TMakes a tag at the commit. tab in the dialog makes it annotated, and asks for a message next. See Tags.
MMerges the commit into the current branch, after asking.
rRebases the current branch onto the commit, after asking.
CCherry-picks the commit onto the current branch, after asking.
cCopies the full commit hash to the clipboard.
AAsks an AI agent about the commit, or starts a ready-made request such as Explain branch. See Agent actions.

For M and r, if a branch points at the commit, tt-git uses the branch name (Merge feature into the current branch?); otherwise it uses the hash. If a merge, rebase or cherry-pick stops on a conflict, see Merge, rebase and cherry-pick.

Copying uses your terminal’s clipboard support (OSC 52), so it also works over SSH.

o checks out the selected commit:

  • If a local branch points at it, tt-git switches to that branch (git switch <name>), so you don’t end up on a detached HEAD where main already is. With several, the first alphabetically wins.
  • Otherwise it checks out the commit itself with HEAD detached (git switch --detach <commit>). The graph shows HEAD on it.
  • If HEAD is already there, tt-git says so and does nothing.

With uncommitted changes, tt-git asks first: Uncommitted changes says how many files have changes and offers to stash them. y stashes everything, untracked files included, then checks out; the changes wait on the Stash tab to pop back later. n or esc leaves everything as it was. If the checkout still fails after stashing, tt-git pops the stash straight back so your changes aren’t left behind.

To check out a branch by name, use the Branches pane.

Press + to make the graph fill the screen, and + again to go back. With the graph fullscreen, space opens details below it at full width.

The graph zoomed to fill the screen with details open below it

The graph loads 1,000 commits at a time while git log is still running, so the first rows appear straight away. It loads up to 20,000 commits (max_commits), and when you scroll within 200 commits of the end, it loads the next batch. On a refresh the old rows stay on screen until the new ones arrive, so the graph never flashes empty. A fetch that brings nothing new doesn’t reload it at all.

See How tt-git uses git for the details, and Memory and speed for what this costs on a large repository.

KeyDoes
j k ↓ ↑Next / previous commit
ctrl+d ctrl+uPage down / up
g GFirst / last loaded commit
enterThe commit fullscreen: changed files beside the diff
spaceShow / hide details
escHide details; with details hidden, clear the filter
aAll branches ↔ current branch
tDates as age ↔ local date and time (also in blame)
fFilter by author or file
oCheck out the commit (its local branch if it has one)
nNew branch at the commit (tab in the dialog: in a worktree)
TNew tag at the commit (tab in the dialog: annotated)
MMerge into the current branch
rRebase the current branch onto it
CCherry-pick
cCopy the commit hash
AAsk an AI agent about the commit
] [ (} {)Next / previous tab in the branches pane
+Zoom the graph fullscreen and back

The mouse works too: click a row to select it, double-click it to open the commit fullscreen as enter does, and use the wheel to scroll. In Filter graph, click an author or file to filter by it. Every key can be changed; see Key bindings.