Kindra is a CLI tool for managing stacked git branches. Its kin command automates the tedious parts of working with dependent branches, such as rebasing descendants after a commit or moving an entire stack of work to a new base.
-
Stacked Commits: Automatically rebase all descendant branches when you commit in the middle of a stack.
-
Stack-Aware Absorb: Distribute staged changes into the commits that introduced the touched lines (via the git-absorb engine), fold them, and restack descendants in one pass.
-
Atomic Stack Moves: Move a branch and all its descendants onto a new base branch in one pass using
--update-refs. -
Fork-Aware Reordering: Edit branch parent relationships in your
$EDITOR, including creating or preserving forks. -
Smart Sync: Rebase the current stack onto
main/masterin one pass using--update-refs, while skipping already-landed lower PRs. -
Auto-Restack: Automatically identify and repair "floating" branches that were based on an old version of the current branch (e.g., after an
amendorrebase). -
Local Overrides: Temporarily restore managed files for checkouts and stack operations, then reapply local config and agent instructions. Configure overrides.
-
Interactive Navigation: Quickly hop between branches in your stack with
up,down, andtopcommands. -
Visual Branch Splitting: Assign branches to specific commits in a linear history using your favorite
$EDITOR. -
Atomic Pushes: Push all branches in your stack simultaneously with
force-with-leasesafety. -
Run Commands Across Stack: Execute shell commands on each branch in your stack with
kin run. -
PR Workflow Helpers: Create/update stack PRs with automatic flatten/push preflight, flatten stack PR bases to upstream, open PRs in your browser, edit PR metadata, inspect review/check status, export threaded review comments as markdown, and merge stack PRs with readiness checks — retargeting child PR bases on GitHub so they aren't orphaned by the merge, then (unless
--no-cascade) restacking children onto the updated trunk and deleting the merged branch locally and on the remote (--method squash|rebase|merge,--no-cascade,--no-delete).
Kindra can be installed directly from GitHub:
cargo install --git https://github.com/Pajn/kindra.git kindra --bin kinIf you already use cargo-binstall, the git-based install works there too:
cargo binstall --git https://github.com/Pajn/kindra.git kindraYou can also install it from source:
# Clone the repository
git clone https://github.com/Pajn/kindra.git
cd kindra
# Build and install
cargo install --path .Kindra uses cargo-release to keep the Cargo version, version bump commit, and Git tag in sync. The GitHub release workflow runs when a v* tag is pushed.
cargo install cargo-release
# Review the planned version bump, commit, tag, and push.
cargo release 0.3.0
# Perform the release after reviewing the dry run.
cargo release 0.3.0 --executeRun kin tree from any branch in a stack to see that entire connected stack, including sibling forks, without unrelated stacks. Run it from the base branch (such as main) to see all stacks branching from that base. A branch with no commits of its own is marked (no commits); of the branches sitting on the base itself, only the checked-out one is shown. Add --commits to include commit details.
- Start a stack: Create several branches, each building on the previous one — with
kin co -b <name>(git checkout -bthat keeps local overrides in place), orkin commit -b <name>to fork a branch and commit onto it in one step (add--insertto splice it into the middle of an existing stack). - Make a change: Checkout a branch in the middle of the stack and run
kin commit. - Watch the magic: Kindra will automatically rebase all branches that depend on your change.
- Move the stack: Ready to target a different feature?
kin move --onto mainrelocates the current branch and its descendants, preserving branch relationships. Moving onto a descendant rotates that target and its single-child chain ahead of the current branch, stopping at a fork; side branches retain their parents. Conflicts supportkin continueandkin abort. Descendant rotations do not support merge commits. - Sync after merges: If lower PRs landed, run
kin syncto rebase the remaining stack onto latestmain. Branching stacks are synced parent first, preserving every fork in the connected tree, even when you start from a leaf. Conflicts pause the operation forkin continue;kin abortrestores the original branch tips. - Reorder the stack: Need to reshuffle or fork branches? Run
kin reorderand edit the parent map in your editor. - Repair broken stacks: Amended a commit and left dependent branches "floating"? Run
kin restackto fix them. - Manage PRs in stack:
kin prto create/update your PRs, automatically flattening mismatched PR bases and pushing firstkin pr --allto include PRs in the stack that are authored by other GitHub userskin pr --no-pushto skip that preflight and use the old create/update behaviorkin pr opento open a PR from the stackkin pr --current --title "Title" --body-file body.mdto publish only the current branch's PR with prepared metadatakin pr --metadata-file prs.tomlto publish a stack with distinct titles and descriptions per branchkin pr --metadata-all --title "Shared title" --body-file body.mdto explicitly reuse metadata across new PRskin pr --body-from-commitsto generate each new PR's description from its commits- Add repeatable
--label/--reviewerflags, and--draft/--no-draft, to control new PR submission kin pr editto edit title/body/labels/reviewers in a terminalkin pr flattento retarget all open stack PRs to the resolved upstream base branch on GitHubkin pr statusto inspect reviewers, unresolved comments, and failing/running checkskin pr reviewto render PR review threads as markdown, optionally write them to a file, or copy them via OSC 52kin pr mergeto merge a stack PR only when reviews/checks are ready, or clearly explain/prompt when GitHub would still allow an override
- Run across stack:
kin run -c "cargo test"to run tests on each branch in the stack. - Undo a mistake: Didn't like the result of a
sync,reorder,move,restack, orsplit? Runkin undoto restore the previous branch tips (andkin redoto reapply, orkin reflogto review recent operations).
For a full list of commands and detailed examples, see the CLI Reference.
kin push --no-interactive feature/auth
kin pr --no-interactive --current --title "Add authentication" --body-file auth.md --draft
kin pr --no-interactive --metadata-file prs.toml --draftSee Agents and CI for global flags and exit
codes, and pr for creation defaults, the metadata
manifest format, and the stack description contract.
kin reorder opens a file with one row per branch:
branch feature-c parent main
branch feature-a
branch feature-b
branch <name> parent <parent>sets the branch parent explicitly.branch <name>means "make the branch on the previous line the parent".- The first row must have an explicit parent, usually your upstream branch.
- Forks are created by repeating the same explicit parent on multiple rows.
Example fork:
branch feature-c parent main
branch feature-a parent feature-c
branch feature-b parent feature-c
Kindra reads two optional TOML files:
- Repository config:
kindra.tomlin the repository's common Git directory (.git/kindra.tomlin a standard clone;git rev-parse --git-common-dirprints the directory). It applies to every worktree of the repository, including linked worktrees. - Global config:
kindra/config.tomlin the platform config directory —$XDG_CONFIG_HOMEor~/.configon Linux,~/Library/Application Supporton macOS,%APPDATA%on Windows. It applies to every repository, supports the[restack]and[rebase]sections, and is overridden by repository config.
A syntax error in either file stops the commands that read it, naming the file. Unknown top-level keys in repository config print a warning. See the CLI reference for every key.
Repository config can also run commands after kin pr publishes the stack, receiving the stack as JSON on stdin: [hooks] after_pr = ["…"]. See Hooks.
Commands that need the trunk — the upstream/base branch stacks are built on (for example sync, split, push, commit, and move) — resolve it in this order:
-
upstream_branchin repository config (an error if no such branch exists):upstream_branch = "branch-name"
-
git config init.defaultBranch -
Built-in defaults:
main,master,trunk -
Remote fallbacks:
origin/<branch>
Kindra now includes an opinionated kin wt workflow for managed git worktrees:
kin wt mainensures a stable trunk worktree exists.kin wt review [branch]creates or reuses a fixed review worktree and repoints it safely.kin wt temp [branch]creates or reuses a branch-scoped disposable worktree, andkin wt temp -b <new-branch> [start-point]creates a new branch in one.kin wt add [branch]creates (or reuses) a durable worktree for a branch in a sibling directory, or in<repo>/worktrees/{branch}when the repository has no parent directory, andkin wt add -b <new-branch> [start-point]creates a new branch in one. Added worktrees are plain by default, unless their paths match a configured temp or cleanup-only location.kin wt listshows every git worktree and its current state (role, or-for plain worktrees).kin wt path <target>prints just the worktree path for shell/editor integrations.kin wt cd <target>changes directory into a worktree (needs shell integration — see below).kin shell-init <bash|zsh|fish>(top-level) prints the shell snippet that enableskin wt cd.kin wt remove <target>removes a worktree (by role or branch) with confirmation by default.kin wt cleanupremoves merged temp and cleanup-only worktrees.
By default Kindra stores the role worktrees (main/review/temp) under:
.git/kindra-worktrees/
That keeps disposable working trees out of the repo root while still making them easy to find and clean up. Durable kin wt add worktrees instead default to a sibling directory (../<repo>-worktrees/{branch}), or to <repo>/worktrees/{branch} when the repository has no parent directory, so they're visible to editors and git status.
# Ensure a persistent trunk worktree exists
kin wt main
# Reuse a stable review workspace for the current branch
kin wt review
# Switch the review workspace to another branch
kin wt review feature/auth
# Create or reuse a temp worktree for a branch
kin wt temp feature/auth
# Create a new temp worktree branch from the current branch
kin wt temp -b feature/spike
# Create a new temp worktree branch from origin/main
kin wt temp -b hotfix/main origin/main
# Create a durable sibling worktree for a branch you want to keep checked out
kin wt add feature/auth
# Use the resolved path in shell tooling
cd "$(kin wt path review)"
# Or, with shell integration enabled, cd straight into a worktree
kin wt cd feature/auth
# Remove a single managed temp worktree
kin wt remove feature/auth
# Clean up merged temp and cleanup-only worktrees
kin wt cleanupkin wt cd <target> moves your shell into a worktree. Because a CLI process can't change its parent shell's directory, this needs a one-time wrapper (from the top-level kin shell-init) in your shell config:
# bash / zsh
eval "$(kin shell-init zsh)"# fish
kin shell-init fish | sourceThe wrapper intercepts kin wt cd and forwards everything else straight to kin. Without it, kin wt cd just prints the path (and tells you how to enable the integration).
kin shell-init also registers Kindra's shell completions by default, so that one line sets up both. Pass --no-completions if you install completions separately.
Managed worktrees are configured in the [worktrees] section of repository config:
[worktrees]
trunk = "main"
# Default location for `kin wt add` ({branch} required; sibling dir by default,
# falling back to <repo>/worktrees when the repo has no parent directory).
add_path_template = "../myrepo-worktrees/{branch}"
[worktrees.hooks]
on_create = []
on_checkout = []
on_remove = []
[worktrees.main]
path = ".git/kindra-worktrees/main"
[worktrees.review]
path = ".git/kindra-worktrees/review"
[worktrees.temp]
path_template = ".git/kindra-worktrees/temp/{branch}"
delete_merged = trueNotes:
mainis pinned to the trunk:worktrees.trunkif set, otherwise the resolved trunk from Upstream Branch Selection.reviewreuses a fixed path and refuses to discard local changes unless you confirm or pass--force.addworktrees default toadd_path_template; by default that is a sibling directory, or<repo>/worktrees/{branch}when the repo has no parent directory. Pass--pathto override. Unlike the role paths it isn't required to live under the managed root.[[worktrees.cleanup]]entries recognize existing worktrees under eachpathfor cleanup without creating there. See the CLI reference for configuration and role precedence.kin wt pathis the script-friendly command: it prints only the resolved path on success.- Use
branch:<name>withkin wt pathorkin wt removeto target a branch literally namedmainorreview. - Hooks run in the worktree directory and stop the action if they fail.
kin wt addruns only the global[worktrees.hooks]; main/review/temp worktrees run global plus role-specific hooks; cleanup-only worktrees run global removal hooks.
kin restack bounds floating-branch discovery by default so very deep repositories do not pay for an unbounded first-parent scan.
Resolution order:
- CLI override:
kin restack --history-limit <n> - Repository config
- Global config
- Built-in default:
100
Use 0 to disable the bound and scan the full first-parent history.
Example repository config:
[restack]
history_limit = 250Kindra sets uncommitted changes aside itself for the commands that rebase or check out branches, records them with a paused operation so kin continue and kin abort restore them, and never uses Git's own autostash. --autostash is the permission to set uncommitted tracked changes aside: move, sync, restack, reorder, and run default to --no-autostash, refusing up front when tracked files have changes, so those changes do not get hidden implicitly. Untracked files need no permission: move
67D1
, sync, restack, and reorder set them aside with everything else, while run leaves them in place. split only moves branch refs, so it leaves uncommitted changes as they are and ignores the flags. commit always sets aside the unstaged changes it has to move out of the way and ignores the flags. See the CLI reference.
Resolution order:
- CLI override:
--autostashor--no-autostash - Repository config:
[rebase] autostash - Global config:
[rebase] autostash - Git config:
rebase.autostash - Built-in default:
false
Example config:
[rebase]
autostash = trueRun the permanent Criterion benchmarks for stack navigation (checkout top, co up, co down) across two repository shapes:
- 5,000 commits on
main+ 10,000 noise branches - 50,000 commits on
main+ 1,000 noise branches
cargo bench --bench checkout_topTraditional git workflows often involve large, monolithic Pull Requests or manual, error-prone rebasing when trying to keep multiple small, dependent PRs in sync. Kindra treats your branches as a stack, allowing you to focus on small, reviewable increments of code while it handles the plumbing.
Use kin abort --clear-state to forget Kindra's saved operation and manage the
current Git state yourself. It clears both rebase and kin run state, including
malformed state files, without restoring branch tips, switching branches,
changing the index or working tree, or applying or dropping saved stashes.
An active Git rebase stays active: finish or abort it with Git. Other kin
commands are no longer blocked by the saved Kindra operation, but Git's normal
requirements for a clean working tree or completed rebase still apply. Saved
changes remain available through git stash list.