TL;DR: I built gion, a CLI to manage Git worktrees declaratively.
Write your desired state in gion.yaml, then plan/apply to create/update/cleanup in bulk with guardrails.
It also supports task-scoped workspaces (grouping multiple repos for a monorepo-like workflow) and fast navigation via giongo.
Repo / docs:
https://github.com/tasuku43/gion
Why I built this
After I started using AI coding agents more often, I ended up doing more parallel work. That naturally led me to git worktree.
But the more parallel tasks I had, the more I kept asking myself:
- Where should I create the next worktree?
- Navigating across many worktrees is annoying.
- Can I delete this safely? (Or will I accidentally lose local changes?)
There are already tools around worktrees, but I wanted two things in particular:
1) Guardrails during cleanup
I wanted to prevent “I didn’t mean to delete it, but it was deletable anyway.”
2) Task-scoped workspaces
I wanted a “box per task” that can contain one or more worktrees, possibly across multiple repositories, so I can run my coding agent from the workspace root — and then delete the whole box when done.
That’s what gion is.
Overview
The core workflow is Create / Move / Cleanup:
-
Create: edit
gion.yamlmanually, or usegion manifest add(interactive) →gion apply(Plan → confirm → Apply) -
Move: use
giongoto search and jump (no state changes) -
Cleanup: edit
gion.yamlmanually, or usegion manifest gc(automatic) /gion manifest rm(interactive) →gion apply(Plan → confirm → Apply)
Tip: gion manifest can be shortened to gion m or gion man.
How it works: gion.yaml and the manifest subcommands
The center of gion is gion.yaml.
-
gion.yamlis the source of truth (“desired state” / inventory). -
gion manifest ...is an entry point to update that YAML (you can also edit it directly). - After any update (via command or direct editing), you run
gion applyto reconcile the filesystem with the desired state. -
gion applycomputes a plan, shows the diff, and then applies it when you confirm. - By default,
gion manifest ...will rungion applyafter rewritinggion.yaml. Use--no-applyif you want to updategion.yamlonly and apply later.
Terminology: worktree vs workspace
- A Git worktree is a working directory that checks out a branch (or a specific commit).
- A workspace (in gion’s terms) is a task-scoped directory that can contain one or more worktrees — potentially from multiple repos.
A typical layout looks like this:
GION_ROOT/
├─ gion.yaml # desired state (inventory)
├─ bare/ # shared bare repo store
└─ workspaces/ # task-scoped workspaces
├─ PROJ-123/ # workspace_id (task)
│ ├─ backend/ # worktree (repo: backend)
│ ├─ frontend/
│ └─ docs/
└─ PROJ-456/
└─ backend/
Create: review a plan, then create in bulk
There are two ways to declare “create this workspace”:
- Use
gion manifest add, or - Edit
gion.yamldirectly
In both cases, you’re declaring a desired state first, and then reconciling with gion apply:
1) compute the plan
2) show the diff
3) apply when you confirm
Four creation modes
gion manifest add supports four entry paths:
repoissuereviewpreset
The entry point differs, but the destination is the same: everything ends up in gion.yaml as desired state.
issue / review: queue up many, then apply once
If you use issue / review, you’ll need the gh CLI (GitHub-only).
These correspond to --issue / --review.
The intended flow is:
- select multiple Issues / PRs
- add them to
gion.yaml - run
gion applyonce - review the plan, then apply
This is great when you want to spin up many review/issue worktrees quickly.
repo: create a single workspace quickly
If you just want the fastest “create one workspace”, repo is the simplest:
- choose a repo
- set a workspace id
- confirm the plan
- apply
preset: group multiple repos under one task workspace (monorepo-like workflow)
A workspace is a “task box”, so it’s common to want something like:
- backend + frontend + docs
- backend + infra
- or any other multi-repo set
With presets, you define the set once, and then reuse it to create workspaces repeatedly.
Direct YAML editing
Direct editing is useful when you want to:
- adjust branch names in bulk
- create/remove multiple workspaces at once
- refactor/reorganize existing definitions
After editing, run:
gion apply
You’ll get a plan showing creates / deletes / updates together, so you can calmly review what will happen before applying.
Move: search and jump to a workspace/worktree
Once worktrees start to accumulate, you waste time thinking:
“Where was I working on that?”
For navigation, use giongo (installed alongside gion via Homebrew/mise).
-
giongodoes not change any state. - It lists both workspaces and worktrees, and lets you filter and select.
- Select a workspace → jump to the workspace directory
- Select a worktree → jump to that repo’s working directory
Shell integration: make giongo change directories
If you want selection → cd, you need a small shell integration. The README includes options, but the simplest is:
eval "$(giongo init)"
(That prints a function you can paste into ~/.zshrc or ~/.bashrc for permanent setup.)
Cleanup: conservative gc, and guarded rm
As worktrees pile up, you eventually pause and ask:
“Is it safe to delete this?”
gion splits cleanup into two commands:
-
gion manifest gc: automatic, conservative cleanup -
gion manifest rm: manual selection with guardrails
gion manifest gc: conservative auto-cleanup
gion manifest gc proposes candidates that are highly likely safe to delete.
For example:
- workspaces whose checked-out branches are already merged into the default branch can be reclaimed
- anything ambiguous (uncommitted / unpushed / unreadable state, etc.) is excluded by default
- even “created but no commits” workspaces are excluded so you don’t delete something by accident
In short: gc aims to keep false-positives very low.
gion manifest rm: manual removal, with guardrails
gion manifest rm is for cases where a human decides what to delete.
It supports interactive selection and then a final confirmation. During selection, each workspace gets lightweight tags like:
[dirty][unpushed][diverged][unknown]
What those mean:
- dirty: working tree has uncommitted changes (including untracked files or conflicts)
- unpushed: your local branch is ahead of upstream (has commits not pushed)
- diverged: local and upstream have both advanced (ahead and behind)
- unknown: cannot be determined (no upstream, detached HEAD, git error, etc.)
When you delete something risky (e.g., dirty), the plan will show a risk summary (e.g., risk: dirty (unstaged=2)) and (for dirty cases) the changed files, so you can sanity-check quickly before you confirm.
Cleanup via direct YAML editing
You can also remove workspaces by editing gion.yaml directly.
Even then, gion apply will:
- clearly show what will be removed in the plan
- ask for a confirmation before destructive changes
So if you get nervous, you can just answer n and stop.
Closing
Installation (Homebrew / mise) and full usage examples are in the GitHub README. If you’ve ever felt the pain of worktree sprawl — especially in multi-repo tasks — I’d love for you to try gion and share feedback.










Top comments (0)