# git-stk
> Git-native stacked branch workflow helper with GitHub and GitLab review integration.
---
`git-stk` keeps stacks as ordinary Git branches. Stack parent metadata is stored locally in `.git/config` as
`branch.<name>.stkParent`, and GitHub PR bases or GitLab MR target branches can be used to reconstruct that metadata.
## Status
This project is experimental. The current implementation focuses on local stacked branch workflows plus
provider-backed review lookup, sync, submit, and cleanup. It does not replace Git's branch model or
attempt automatic conflict resolution.
## Install
```sh
Installers are also attached to [GitHub Releases](https://github.com/lararosekelley/git-stk/releases), or install
from [crates.io](https://crates.io/crates/git-stk) with `cargo install git-stk --locked`.
Then install the man page and wire up shell completions (idempotent; prompts before touching your shell rc):
```sh
git stk setup
```
Upgrade an installer-managed copy with:
```sh
git stk upgrade
```
## Shell Completions
`git stk setup` configures these automatically. Completions are dynamic: the shell asks the binary for
candidates at completion time, so subcommands, flags, and even branch names complete (`git stk up <TAB>`
offers only the current branch's stack children). The installed binary prints its own registration script,
so completions stay in sync across upgrades:
```sh
# bash: add to ~/.bashrc
source <(git stk completions bash)
# zsh: write to a directory on your fpath
git stk completions zsh > "${fpath[1]}/_git-stk"
```
Elvish, fish, and PowerShell are also supported. The bash and zsh output includes a wrapper so git's own
completion can complete `git stk <TAB>` in addition to `git-stk <TAB>`.
## Install For Development
```sh
just install
just check
cargo install --path .
```
After installation, Git can use the binary as a sub-command:
```sh
git stk list
```
## Commands
Local stack metadata:
```sh
git stk new <branch>
git stk parent [branch]
git stk children [branch]
git stk list [--markdown]
git stk adopt <branch> --parent <parent>
git stk detach [branch]
```
`list` prints the stack leaf-first, like a pile sitting on its base, with the trunk labeled:
```text
feature/b *
feature/a
main (trunk)
```
`list --markdown` prints a shareable summary instead - a status line and the PRs in merge order with
links and states, ready to paste into Slack or a tracking issue:
```markdown
2 PRs, base `main`, 1 open / 1 merged
1. [Bottom change (#9)](https://github.com/owner/repo/pull/9) - merged
2. [Top change (#10)](https://github.com/owner/repo/pull/10) - open
```
Branches without reviews degrade to plain names, so it works before submitting too.
Navigation and re-stacking:
```sh
git stk up [branch] # towards the top of the stack (children)
git stk down # towards the trunk (parent)
git stk restack [--update-refs | --no-update-refs] [--push | --no-push]
git stk continue
git stk abort
```
Provider-backed workflows:
```sh
git stk provider
git stk config
git stk status [branch]
git stk review [branch]
git stk sync [branch] [--dry-run]
git stk repair [--dry-run]
git stk submit [branch] [--dry-run] [--push | --no-push]
git stk submit --stack [--dry-run] [--push | --no-push]
git stk cleanup [branch] [--dry-run] [--delete-branch]
```
`submit --push` (or `git config stk.pushOnSubmit true`) pushes the submitted branches with
`-u --force-with-lease` before creating or updating reviews, so new branches exist remotely and rebased
ones are updated safely.
`submit --stack` also maintains a stack overview at the end of every PR/MR description: the full stack as
linked bullets (leaf-first, with a pointer on the PR being viewed) sitting on the trunk, plus a footer
crediting the tool. The section lives between HTML comment markers and self-repairs on the next submit if
the markup is hand-edited away.
Upgrading:
```sh
git stk upgrade # upgrade to the latest release
git stk upgrade --force # reinstall the latest release even if up to date
git stk upgrade --head [-y] # build and install the latest unreleased commit
```
`upgrade` uses the install receipt written by the shell installer; copies installed with `cargo install` should
upgrade through cargo instead. `--head` requires a Rust tool-chain, prompts before installing a pre-release build,
and `git stk upgrade --force` returns you to the latest release afterwards.
## Configuration
All settings live under `[stk]` in git config, so the tool's footprint stays separated from git's own.
Everything is optional; defaults shown below:
```ini
[stk]
; Review provider: github or gitlab. Default: auto-detect from the remote URL.
provider = github
; Remote used for provider detection and pushes. Default: origin.
remote = origin
; Pass --update-refs to git rebase during restack. Default: false.
updateRefs = true
; Force-push (with lease) every rebased branch after restack. Default: false.
pushOnRestack = true
; Push branches (-u --force-with-lease) before submitting reviews. Default: false.
pushOnSubmit = true
```
The tool also manages per-branch metadata: `branch.<name>.stkParent` (the stack parent) and
`branch.<name>.stkBase` (the recorded fork point). These are written by `new`, `adopt`, `sync`, `restack`,
and `cleanup`; you normally never touch them by hand.
Branches are the real state; the metadata is just annotation. If it is ever lost or stale, `git stk repair`
rebuilds it from review bases (when `gh`/`glab` is available) and branch ancestry, and verifies recorded
fork points. Anything it cannot resolve safely is reported for a manual `git stk adopt`.
Inspect everything stk reads or wrote with:
```sh
git stk config
```
## Providers
Provider detection uses `stk.provider` first, then `stk.remote`, then `origin`. GitHub support shells out
to `gh`. GitLab support shells out to `glab`. Authenticate those CLIs before using provider commands.
## Re-stacking
`restack` follows the `stk.updateRefs` config (default false). Use `--update-refs` or `--no-update-refs` to
override that for one run. If a rebase conflicts, `git-stk` records state in `.git/stack-state`; resolve
conflicts and run `git stk continue`, or run `git stk abort`.
`git-stk` records each branch's fork point in `.gitconfig` as `branch.<name>.stkBase` and rebases with
`--onto`, so only a branch's own commits are replayed. This makes restacking safe after a parent is
squash-merged, rebase-merged, or amended. A missing or stale fork point falls back to a plain rebase.
After a restack, every rebased branch's remote counterpart is stale. Pass `--push` (or set
`git config stk.pushOnRestack true`) to force-push (with lease) all rebased branches automatically,
including after a conflicted restack finishes via `git stk continue`. Without it, `restack` prints the
exact push command instead. `--no-push` overrides the config for one run; `stk.remote` picks the remote
(default `origin`).
## Generated Assets
Shell completions and a `man` page can be generated with:
```sh
just generate-assets
```
Generated files are written under `target/generated`.
## Project Tasks
```sh
just build
just test
just lint
just check
```
## License
Copyright (c) 2026 [Lara Kelley](https://larakelley.com). MIT License. See [LICENSE](./LICENSE).