A terminal UI for reviewing your working changes like a pull request: everything that differs from the base branch — committed or not — in one view.
The comparison point is git merge-base <base> HEAD, diffed against the
working tree, so committed work, uncommitted edits, and untracked files
all show up together. The base branch is auto-detected (origin/HEAD,
then main, then master), and can be switched from inside the app.
The same UI also opens real pull requests: browse the repo's open GitHub PRs or GitLab MRs, read the discussion, reply to review threads, comment on lines, resolve, delete — without leaving the terminal. See Pull requests.
macOS / Linux
curl -fsSL https://tothalex.github.io/drift/install.sh | shPrebuilt binaries (x86_64/aarch64) land in ~/.local/bin (override with
DRIFT_INSTALL_DIR).
Windows (experimental)
Grab drift-windows-x86_64.zip from the
latest release and
unzip it. Then, from PowerShell in the folder containing drift.exe, move
it somewhere permanent and add that folder to your user PATH:
New-Item -ItemType Directory -Force "$env:LOCALAPPDATA\Programs\drift" | Out-Null
Move-Item drift.exe "$env:LOCALAPPDATA\Programs\drift\"
[Environment]::SetEnvironmentVariable("Path",
[Environment]::GetEnvironmentVariable("Path", "User") + ";$env:LOCALAPPDATA\Programs\drift", "User")Open a new terminal and drift is available. (Alternatively: Start menu →
"Edit environment variables for your account" → edit Path → add the
folder there.) Windows Terminal is recommended. Windows support is new —
if something misbehaves, please
open an issue.
Or build from source on any platform: see Build.
drift # review the current repo
drift --base dev # compare against a different base
drift ~/some/repo # review another repository
drift --pr 123 # open pull request #123 right awayThe primary view is your own working changes — everything since the base branch, kept live as you edit:
- Changes are shown inside their enclosing code block (function, class, if, …) resolved with tree-sitter, not as bare hunks; the scope can be widened and narrowed. Rust, Python, JavaScript, TypeScript/TSX, and Go; other files fall back to plain hunks.
- Syntax highlighting, with changed lines marked by gutter accents and word-level emphasis on the exact edit.
- Comment-only lines render as prose with
TODO/FIXMEtags accented; unchanged comment blocks can be folded to a one-line summary. - Two-pane focus:
haims the cursor keys at the file tree,lat the code view (the lit-up header shows which; clicking a pane focuses it too).H/Lstep between files, skipping ones checked off. - Each pane keeps its own
/search with match highlighting;n/Ncycle the focused pane's matches — and in an unsearched code view they hop between the changes themselves, so large files navigate by edit, not by scrolling. - File tree with review progress: check files off as you go, navigation skips what's done.
- Vim-style keys (counts,
g/G, visual mode, yank) and full mouse support (wheel per pane, click, drag-to-copy, pane resize). - Live reload: the working tree is watched, so edits made outside the
app — your editor, an AI agent, a
git commit— appear as they land, without losing your cursor or scroll position. Gitignored paths (build artifacts) never trigger a refresh. - Press
eto open the file in your editor at the cursor's line (neovim by default, configurable — see below); edits show up in the diff the moment you save. - Review scopes: press
b(or click the branch name in the status bar) to switch the base branch, then narrow the review to one commit or to untracked files only — or keep everything at once. - All views are precomputed on background threads — navigation stays instant regardless of changeset size.
Press ? inside the app for all keybindings.
drift doubles as a PR review tool. Press p (or run drift --pr 123)
to list the repository's open pull requests (GitHub) or merge requests
(GitLab) and open one — the same file tree, block-scoped diffs, review
progress, and search as the primary view, with the whole review
conversation in place:
- Inline review threads sit under the exact diff lines they were written
on, with their resolved/unresolved state;
tfolds a thread down to its head line. Threads that no longer match the current diff stay reachable instead of disappearing. - A virtual
# conversationentry pinned at the top of the tree holds the PR description, the PR-level discussion, and those outdated threads. - Comment anywhere:
aon a diff line starts a new inline thread,aon a thread's[a] replyrow answers that thread, andAwrites a PR-level comment from wherever you are. - Comments are composed in a small in-app box —
enterposts,shift+enter(oralt+enterin terminals without the kitty keyboard protocol) adds a line,esccancels; the box's footer shows the keys that work in your terminal. While a comment posts, a spinner marks the exact row it will land on. - On comment rows
rtoggles the thread resolved/unresolved andd(pressed twice, with the author named in the confirmation) deletes your comment — the[r]/[d]hints under each thread advertise them; elsewhere both keys keep their global meanings. rrefetches the open pull request without losing your place;p(or clicking the#Nstatus segment) returns to the list, where the first row leads back to your local changes.- When the PR's commits exist locally (after any
git fetch), diffs get full syntax highlighting and block scoping; otherwise drift falls back to the plain hunk view — no fetch is ever run for you.
drift talks to the forge through the official CLIs — gh for GitHub,
glab for GitLab — so install the one for your forge and run its
auth login once. That's also what makes GitHub Enterprise and
self-managed GitLab work: authenticate the CLI against your host
(gh auth login --hostname git.corp.example) and drift picks the forge
from the repo's origin remote. If your hostname names neither
"github" nor "gitlab", set it explicitly in the config:
[forge]
kind = "gitlab" # or "github"
# gh = "/path/to/gh" # binary overrides, if not on PATH
# glab = "/path/to/glab"Every keybinding and color is configurable via
~/.config/drift/config.toml (respects $XDG_CONFIG_HOME). Generate the
documented default file with:
drift --init-configKeys take single characters, named keys (enter, space, tab, arrows,
pageup/pagedown, home/end), optionally prefixed ctrl-; listing
an action replaces all of its default keys. Colors take ANSI names,
256-color indexes, or hex values — including the full syntax palette,
and a [theme.<lang>] section (rust, python, javascript, typescript,
tsx, go) overrides any syntax color for that language only. A top-level
base = "…" sets the default comparison branch.
Colors layer in three steps: a base colorscheme, then [theme] /
[theme.<lang>] overrides on top. The built-in colorscheme is
onedark; a custom one is a file next to the config:
# ~/.config/drift/config.toml
colorscheme = "mytheme"
# ~/.config/drift/themes/mytheme.toml — same keys as [theme]; missing
# keys keep the built-in defaults
keyword = "#fb4934"
string = "#b8bb26"
[rust]
bracket = "#fe8019"The editor is a top-level editor = "…" command; {file} and {line}
are substituted, and the file path is appended when {file} is absent:
editor = "nvim +{line}" # the default
# editor = "code -g {file}:{line}"
# editor = "subl {file}:{line}"cargo build --release # binary at target/release/drift
cargo testGit repositories are read natively (via gitoxide) — the git binary is
not required.


