| English | 한국어 | 日本語 |
|---|
gitt is an agent worktree management tool for Docker Compose projects, built on top
of git worktree.
Spin up an isolated worktree and bring up its own Docker Compose stack per branch — even if you're not familiar with Git, GitHub, or Docker.
Especially useful for non-developers who want to contribute with AI coding tools like Claude Code or Codex. gitt lets anyone run multiple AI coding agents in parallel without thinking about worktrees, branches, or compose configuration.
| Command | Description |
|---|---|
gitt on |
Start the daemon (~/.gitt/gitt.sock, ~/.gitt/gitt.db). Prints the boxed logo banner only when [ui] logo_enabled = true in ~/.gitt/config.toml (default: off). Toggle with gitt logo. |
gitt off |
Stop the daemon |
gitt init [dir] |
Initialize a bare-layout repo in dir (default: current directory). Creates <dir>/.bare (bare repo), writes a <dir>/.git pointer file, and adds an empty orphan worktree at <dir>/.worktrees/<branch>. Use -b/--initial-branch <name> to set the initial branch (default: init.defaultBranch config, then main). Requires git 2.42+. Refuses if .bare or .git already exists. Best-effort daemon registration on finish (warns if daemon is down). No-remote counterpart of gitt clone. |
gitt add <branch> |
Create a worktree at <repo>/.worktrees/<branch>. Checks out the branch if it exists, creates a new one otherwise. / and \ in branch names are converted to -. If the branch is already checked out somewhere (e.g. main in the repo root), the existing path is reported and registered with the daemon — no new worktree is created. Add --print-path to suppress human-readable output and print only the worktree path to stdout (useful for shell wrappers). Requires daemon |
gitt remove <branch> |
Remove the worktree folder for the given branch (git worktree remove). Requires daemon |
gitt rename <old> <new> |
Rename a branch and its worktree folder together. Updates <repo>/.worktrees/<old> → <repo>/.worktrees/<new>, renames the branch, and updates the daemon record in one step. Refuses if <old> or <new> appears in [branches].protected (the <new> check blocks gitt rename feat/foo main-style policy bypass). Requires daemon |
gitt list |
List worktrees for the repo containing the current working directory. Output columns: BRANCH PROTECTED STATUS PATH. PROTECTED is * for branches in [branches].protected, empty otherwise. Add --global / -g to list every worktree the daemon knows about across all repos (the output gains a leading REPO column). Errors if cwd is not inside any git repo, unless --global is set. Requires daemon |
gitt status |
Print the current worktree's repository, branch, path, and state (clean/dirty/rebase/merge/conflict, etc.) |
gitt vscode |
Write (or update) <repo-root>/<repo-name>.code-workspace with one folder entry per registered worktree, labeled by branch name. Preserves existing settings/extensions. On first creation only, seeds terminal.integrated.environmentChangesIndicator: "off" and terminal.integrated.environmentChangesRelaunch: false into settings to suppress the terminal-relaunch prompt that env-contributing extensions raise on every folder-list change; once written, gitt never touches settings again, so changing or deleting those keys sticks. Useful because every worktree lives under .worktrees/ and otherwise shows an identical title in VSCode. Can be run from anywhere inside the bare layout (main root or any worktree) — the output always lands at the main repo root. Then open it with code <repo-root>/<repo-name>.code-workspace (e.g. code gitt/gitt.code-workspace); opening .worktrees/ directly is exactly the situation this command exists to avoid. Requires daemon |
gitt sqlite |
Run a SQLite self-test against the daemon's database to confirm the DB connection is healthy. Requires daemon |
gitt config |
Open ~/.gitt/config.toml in your editor. Creates the file from built-in defaults on first run; otherwise opens the existing file. Editor is resolved in order: $VISUAL → $EDITOR → vi. Values like code --wait work — the command is split on whitespace. Does not require the daemon. |
gitt update |
Fetch the latest release and install it. Shuts down the daemon, force-deletes all registered worktree folders (uncommitted and untracked changes are unrecoverable), runs git worktree prune on each repo, then removes ~/.gitt/ and replaces the binary. Use -y/--yes to skip the prompt |
gitt version |
Print the installed gitt version |
gitt logo |
Print the gitt logo art and interactively toggle whether gitt on shows it on startup. Persists the choice to ~/.gitt/config.toml as [ui] logo_enabled. Requires an interactive terminal (stdin must be a TTY). |
gitt uninstall |
Stop the daemon → remove ~/.gitt/ → remove the binary. Use -y/--yes to skip the confirmation prompt |
Daemon-dependent commands fail fast with a gitt on hint when the daemon is not
running. (No auto-start.)
gitt config opens ~/.gitt/config.toml in your editor. The file is created from
built-in defaults on first run. Schema:
[ui]
# Whether `gitt on` prints the boxed logo banner on startup.
# Toggle this with `gitt logo`.
logo_enabled = false
[worktree]
copy = [".env", ".env.local", ".env.development", ".envrc", ".npmrc", ".nvmrc"]
symlink = ["node_modules", ".venv"]
ignore = ["dist", "build", ".next", ".cache", "target"]
[branches]
protected = ["main", "master", "staging"]logo_enabled— controls whethergitt onprints the boxed logo banner. Easier to flip withgitt logothan editing the file directly.copy— files copied into each new worktree (env/secret files that should not be shared).symlink— paths symlinked into each new worktree (heavy directories you do not want duplicated).ignore— paths skipped when seeding a new worktree (build outputs, caches).protected— branch names listed here are refused bygitt rename(both as the source and the target). Match is case-sensitive and exact (maindoes not protectMain). Wildcards and regex are not supported; list each name explicitly. The daemon reads this list at startup; after editing the file rungitt off && gitt onfor the change to take effect.
Note: The
copy,symlink, andignorelists are not yet consumed bygitt addorgitt clone. The[branches].protectedlist is enforced bygitt renametoday;gitt removeenforcement is planned but not yet wired up.
Editor tip: Add export EDITOR="code --wait" to your shell rc to use VS Code.
The --wait flag is required so the editor blocks until you close the file.
A binary cannot cd its parent shell. Without a wrapper, gitt add prints a
"Open a new terminal, then run: cd ..." hint and you must copy-paste it
yourself. The wrapper below intercepts gitt add, captures the worktree path
via --print-path, and changes directory for you automatically.
Paste into ~/.zshrc or ~/.bashrc, then source the file (or open a new
terminal):
# gitt — auto-cd into the new worktree on `gitt add`.
gitt() {
if [ "$1" = "add" ]; then
shift
target="$(command gitt add --print-path "$@")" || return $?
[ -n "$target" ] && cd "$target"
else
command gitt "$@"
fi
}When --print-path is set, all human-readable progress goes to stderr and
stdout contains exactly one line — the absolute path of the worktree — which
the wrapper captures. Without the wrapper, gitt add behaves exactly as
before.
One-line install (macOS / Linux, amd64 / arm64):
curl -fsSL https://raw.githubusercontent.com/foreverfl/gitt/main/install.sh | sh-
Default install location:
$HOME/.local/bin/gitt— override withGITT_INSTALL_DIR -
Specific version:
GITT_VERSION=v0.0.1 curl ... | sh -
If
~/.local/binis not on yourPATH, add the line below to your shell rc (~/.zshrcfor zsh,~/.bashrcfor bash) and reload the shell:export PATH="$HOME/.local/bin:$PATH"
gitt uninstallStops the daemon → removes ~/.gitt/ (sock, pid, log, db) → removes the binary
(os.Executable()). Use -y / --yes to skip the prompt.