Skip to content

Kirboyyy/groot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

groot 🌲

A CLI for managing git worktrees in bare repos. One branch, one directory, no stashing.

groot new feat/my-feature    # fetch, diff-check, create worktree, open editor
groot open feat/my-feature   # re-open an existing worktree in the editor
groot rm feat/my-feature     # run hooks, remove worktree, prune
groot list                   # table of active worktrees
groot purge                  # remove all non-protected worktrees
groot init <url>             # clone bare repo and write starter config

How it works

groot assumes you're working with a bare clone — a repo with no working tree of its own, where every branch gets its own directory via git worktree. This gives you instant branch switching with no stashing, no checkout thrash, and no editor reload.

~/worktrees/
  myrepo/
    main/          ← worktree for main
    feat-login/    ← worktree for feat/login
    fix-crash/     ← worktree for fix/crash-on-nil

Installation

git clone --bare https://github.com/kirboyyy/groot ~/repos/groot.git
cd ~/repos/groot.git
make install
# macOS  → installs to ~/go/bin/groot
# Linux  → installs to ~/.local/bin/groot

Or build manually:

go build -o groot ./cmd/groot

Both paths are on $PATH by default for their respective platforms.


Configuration

Config lives at ~/.config/groot/config.json. Run groot init to generate a starter file.

{
  "worktreesBase": "~/worktrees",
  "editor": "kitty",
  "editorArgs": [],
  "autoFetch": true,
  "protectedBranches": ["main", "master"]
}

Fields

Key Default Description
worktreesBase ~/worktrees Root directory for all worktrees
editor kitty Command to launch when opening a worktree
editorArgs [] Extra args passed to the editor before the path
autoFetch true Fetch from origin before creating a worktree
protectedBranches ["main","master"] Branches purge will never touch

Editor examples

{ "editor": "code",      "editorArgs": [] }
{ "editor": "idea",      "editorArgs": [] }
{ "editor": "zed",       "editorArgs": [] }
{ "editor": "nvim",      "editorArgs": [] }
{ "editor": "kitty",     "editorArgs": ["--directory"] }

groot runs: <editor> [editorArgs...] <worktree-path>, detached from the process.

Hooks

Hooks are executable scripts placed in .groot/hooks/ inside the bare repo. Each hook receives the worktree path as $GROOT_WORKTREE_PATH and branch as $GROOT_BRANCH.

myrepo.git/
  .groot/
    hooks/
      after-new
      before-remove
      after-remove
      before-purge
      after-purge

Example before-remove:

#!/bin/sh
# Close project in IDEA before removing the worktree
idea "$GROOT_WORKTREE_PATH" --wait --close-project
Hook When
after-new After worktree is created and editor is launched
before-remove Before a worktree is removed (single rm)
after-remove After worktree removal and prune
before-purge Before purge starts removing worktrees
after-purge After all worktrees have been removed and pruned

Hooks are optional — missing scripts are silently skipped. A non-zero exit code aborts the operation.


Commands

groot new <branch>

Creates a worktree for <branch> and opens it in your configured editor.

Branch resolution order:

  1. Local branch exists → check it out
  2. origin/<branch> exists → create local tracking branch
  3. Neither → create a new branch

If autoFetch is enabled: fetches from origin first, then prompts if the branch is behind.

$ groot new feat/login
  feat/login  3 commits behind origin — continue? [y/N]
🌲 ~/worktrees/myrepo/feat-login

groot open [branch-or-path]

Opens an existing worktree in the editor. With no argument, shows an interactive list to pick from.

groot rm [branch-or-path...]

Removes one or more worktrees. With no argument, shows a checkbox list to select which to remove. Accepts multiple arguments directly.

  1. Resolves the path
  2. Runs before-remove hook
  3. git worktree remove
  4. git worktree prune
  5. Runs after-remove hook

groot list

Prints a table of all active worktrees, skipping the bare repo entry.

BRANCH              PATH                              HEAD
feat/login          ~/worktrees/myrepo/feat-login     a3f2c1d
fix/crash-on-nil    ~/worktrees/myrepo/fix-crash       b91e4aa
main                ~/worktrees/myrepo/main            ff02381

groot purge

Removes all worktrees except protected branches. Prompts for confirmation.

$ groot purge
  feat/login          ~/worktrees/myrepo/feat-login
  fix/crash-on-nil    ~/worktrees/myrepo/fix-crash

remove 2 worktrees? [y/N]

groot init <url>

Clones <url> as a bare repo and writes a starter ~/.config/groot/config.json (non-destructively — won't overwrite existing config).

groot init https://github.com/you/myrepo

Shell completions

# bash
groot completion bash > /etc/bash_completion.d/groot

# zsh
groot completion zsh > "${fpath[1]}/_groot"

# fish
groot completion fish > ~/.config/fish/completions/groot.fish

License

MIT

About

Git worktree manager for bare repos — one branch, one directory, no stashing. Instant context switching with lifecycle hooks and editor integration

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors