$ manygit

error: no terminal here — that's a phone in your hand.

it's a command-line tool.

manygit lives in a terminal — a real keyboard, a wide screen, a computer that isn't also a phone. there's honestly nothing for you to do on this screen.

$ manygit --anyway

are you sure?

the demo won't run down here — it needs the keys, and your screen is made of glass. you'd be reading about a keyboard app with no keyboard. but it's your data plan.

$ manygit --tell-me-anyway

fine. the whole pitch:

manygit is a lazygit-style TUI for a folder full of git repos. point it at a directory and every repo underneath lands on one screen — its branch, and whether it's ahead, behind, or dirty. then fetch, pull, push, or switch branches on the one under the cursor, without cd-ing around.

that's it. i'm not printing the install command down here — you can't paste it into a terminal you're not holding. so go open manygit on a real computer (the kind with a keyboard), like i already told you.

— see you on a bigger screen.

manygit v1.1.3 github
single binary
macOS · Linux · Windows

Which of your repos are dirty right now?

If you keep a folder full of them — services, packages, plugins — answering that means cd-ing through every one. manygit is a single CLI tool for managing multiple git repositories: every repo underneath lands on one screen — ahead, behind, dirty, clean — then fetch, pull, push, or switch branches on the one under your cursor, without leaving the list.

$brew tap rabeeh-ta/manygit && brew trust rabeeh-ta/manygit && brew install manygit
Linux, Windows, and other ways to install
A working copy of the interface, running here. The git is fake, and :'s AI reply and !'s shell output are scripted — the keys are the real keys. click to start it, then type · esc leaves swipe it · tap the keys below
panes
try

Install

One command. A single binary, no runtime, no config to write.

macOS — Homebrew

$brew tap rabeeh-ta/manygit && brew trust rabeeh-ta/manygit && brew install manygit

The trust step is required from Homebrew 6 onwards. A cask in a third-party tap can run arbitrary Ruby, so Homebrew refuses to load one until you opt in. Use brew trust --cask rabeeh-ta/manygit/manygit to trust only manygit rather than everything this tap may ever hold.

Homebrew owns the binary it installs, so manygit never replaces it. When a newer release lands it says so — at most once a day, after you quit — and leaves brew update && brew upgrade --cask manygit to you — the update is what pulls the tap, without which brew still reads the old cask.

macOS and Linux — installer script

$curl -fsSL https://raw.githubusercontent.com/rabeeh-ta/manygit/main/install.sh | bash

The installer picks the right build for your OS and architecture, and adds ~/.local/bin to your PATH if it isn't there already. This binary is yours rather than a package manager's, so manygit checks for a newer release on every launch and offers to update itself — the last time you'll run this.

Windows — installer script

$irm https://raw.githubusercontent.com/rabeeh-ta/manygit/main/install.ps1 | iex

PowerShell. Drops manygit.exe into %LocalAppData%\manygit\bin and adds it to your PATH, with the same self-update behavior as the script above. Already on Git Bash, MSYS2, Cygwin or WSL? install.sh detects Windows there too and installs the same binary.

With Go

$go install github.com/rabeeh-ta/manygit@latest

Managed by the Go toolchain, so it behaves like the Homebrew build: manygit reports new releases but never replaces itself.

From source

$git clone https://github.com/rabeeh-ta/manygit && cd manygit && go build -o ~/.local/bin/manygit .

Needs Go 1.24 or newer.

Then run it

$manygit # scan the current directory
$manygit --root ~/work # scan somewhere else

manygit walks the folder three levels deep, collects every git repo it finds, and groups them by parent directory.

Keys

Every action applies to the repo under the > cursor.

KEY ACTION
1 2 3 Focus Repos, Scripts, or Branches
4 Pull requests — a tab beside Branches
5 6 7 The bottom slot: commit graph, changed files, script output
tab Cycle the panes. shift+tab cycles back
[ ] Cycle the focused pane's tabs — 34, 567. The numbers still jump straight to any of them
j k Move within the focused pane
← → Hop between Repos and that repo's Branches
enter Select: open a repo's branches, check one out, run a script, or check out a PR
b Check out the highlighted branch — what enter does in Branches
s / p Sync (fetch, then fast-forward pull) / push
d / D Discard changes, after a confirm — d tracked files only, D also deletes untracked ones
f / r Fetch this repo / refetch all of them
/ Filter the focused list by what it shows. Repos match on their name and their current branch — /main finds every repo sitting on main, and the tag too while t is on. Branches match on name, so feat finds one among hundreds
F Show only repos that are changed, ahead, or behind
t Show each repo's latest tag inline
g / n Full-screen commit graph / full-screen news feed
esc Back out one layer of state — the diff, then Changes, then zoom, then the / and F filters. One press, one layer
o / z Open the repo in your editor / zoom the focused pane
: Plain-English git. Type a request — rebase current onto master, sync everything in apps — and your AI harness turns it into git commands against the whole tree. Repo, folder and branch names complete with tab, and @script.sh sends that file along as context — @scripts/update-all.sh only the frontend apps from this. Nothing runs until you confirm
! Shell in the highlighted repo. Opens a prompt naming where you are — $manygit:apps/api-gateway. Type a bash command — git status -sb, npm test — and it runs there (falling back to cmd.exe on Windows if bash isn't on PATH), streaming into the Output pane. The prompt stays open, so it is a shell you sit in: run, read, run again. The bottom bar shows which repo you are in while you type. esc leaves the shell and lands on Repos; ctrl+c is what stops a running command. Non-interactive, so vim and top will not work
? Help: the keybindings and the status legend, plus settings — themes, AI harness, news window, scan depth, glyphs, editor. tab or [ ] switch faces; ? or esc closes
q Quit

Status

The right-hand column of the Repos pane — every repo's git status at once, one glance each.

ok Up to date with upstream
↑N N commits ahead — something to push
↓N N commits behind — something to pull
↑N ↓M Diverged from upstream
*N N files changed in the working tree
no-remote A local-only repo, never pushed anywhere. s and p skip it
! The branch has no upstream, or git errored

These stay live without being asked — a PR checkout, a script, or a : plan updates the rows it touches as it touches them.

If the arrows misalign in your terminal, switch to ASCII +/- in the settings face — press ? then tab, in the demo above too.

Pull requests

If the gh CLI is signed in, a PRs tab appears next to Branches.

Press 4. One list is the pull requests you opened, m toggles to the ones waiting on your review, and it opens on whichever has something in it. Each row shows what merges where — base ← head — and the branch that clone is on.

enter checks the PR's branch out in the matching local clone and leaves you where you are, so you can walk a PR that spans several repos. Needs gh signed in.

Plain English

Press : and say what you want. It comes back as git commands you approve.

The prompt is named after your AI tool — claude: or codex: — and it knows the tree it is looking at: every repo, its branch, whether it is dirty, whether main is actually called master, and what the latest tag is. So rebase current onto master rebases each repo onto its own main branch, and sync everything in apps resolves the folder.

:@scripts/update-all.sh only the frontend apps from this

@ pulls a file in as context — point it at a script and ask for the part you want. Repo, folder, branch and script names complete with tab, filling in as far as they agree and waiting for the character that decides the rest. / recall what you asked earlier in the session.

Nothing runs until you say so. The exact commands are printed, and a y runs them; anything else drops the plan. A batch stops at the first failure, so a conflict leaves you one repo to sort out rather than five. It only ever runs git — asked for anything else, it says so in a sentence — and it is executed as an argument list, never through a shell, so force-pushes and remote deletions are refused before you are even asked.

Each request stands alone — there is no chat to follow up in, so it never asks you a question. Given something ambiguous it picks the most likely reading and shows you the commands; the plan is the question, and y or N is the answer.

No AI tool installed? : says so and does nothing. Nothing else changes.

News

The top bar reads the last few days of commits back to you in English.

If you have claude or codex on your PATH, manygit hands them the recent main-branch commits across every repo and rotates the summaries through the top bar. Press n for all of them at once. Summaries are cached for four hours and rewritten in place, so opening manygit doesn't re-summarize and the cache never grows.

No AI tool installed? The top bar shows a repo count instead. Nothing else changes.

Config

Optional. The settings face (? then tab) writes this file for you.

~/.config/manygit/config.yml
max_depth How many folders below the root to search for repos. Default 3. Also a row in the settings face — picking a depth re-walks the tree straight away, and a depth with no repos under it is refused rather than leaving you an empty list
open_cmd What o runs in the repo — code, cursor, code -r. A trailing . is fine
theme default, serika_dark, dracula, nord, catppuccin, 8008
status_glyphs unicode arrows, or ascii if they misalign

manygit never writes to the folder you launch it from. On its own it never force-pushes, merges, or rebases — s is fetch plus a fast-forward-only pull, p is a plain push — and the one destructive action it offers on its own is discarding a repo's changes with d / D, which always asks first.

! is the deliberate exception: it runs the bash command you type, in the highlighted repo (falling back to cmd.exe on Windows if bash isn't on PATH), with no confirm and no blocklist — a shell escape that second-guessed you would be useless. What it does instead is leave a record: the command is echoed into the Output pane with the repo it ran in, before any output arrives, and ctrl+c stops it mid-run.

: widens that on purpose, since merging and rebasing are the point of it. Every command is shown before it runs and needs a y; git is executed with an argument list rather than through a shell, so pipes and && cannot be expressed; and force-pushes, remote deletions and the git flags that take a shell command are refused before the confirm appears. A batch stops at the first failure.