Skip to content

Repository files navigation

stackr (sr)

A local stacked-branch workflow manager for Git. Stackr organizes your branches into hierarchical stacks — parent-child relationships that let you work on dependent changes simultaneously, rebase entire chains with one command, and submit clean PRs that build on each other.

◉ feat-auth-ui ←         ← you are here
│
│ ◯ feat-auth-tests
├─┘
◯ feat-auth-middleware
│
◯ feat-auth-models
│
◯ main (trunk)

Why Stacked Branches?

Large features rarely fit in a single PR. Stacked branches let you:

  • Ship incrementally — each branch is a reviewable, mergeable unit
  • Work in parallel — start the next piece before the previous one merges
  • Keep PRs small — reviewers see focused diffs, not 2000-line monsters
  • Rebase safelysr sync updates your entire stack when trunk moves

Stackr tracks the dependency graph so you don't have to remember which branch sits on which.

Installation

From Source

Requires Go 1.25.5+ and Git.

# Clone and install globally
git clone https://github.com/amustafa/stackr.git
cd stackr
make install    # installs `sr` to your $GOPATH/bin

# Or build locally
make build      # outputs to build/sr

Zsh Plugin (antidote)

Stackr ships a zsh plugin at the repo root (stackr.plugin.zsh), so you can install its shell integration through a plugin manager. With antidote, add the repo to your ~/.zsh_plugins.txt:

amustafa/stackr

Then rebuild your plugin bundle (or restart your shell):

antidote update

The plugin sets up both the worktree auto-cd wrapper (sr shell-hook) and zsh completions (sr completion zsh) — but only if the sr binary is on your $PATH. If stackr isn't installed yet, loading the plugin is a harmless no-op, so the ordering of "install the binary" vs. "load the plugin" doesn't matter. Install the binary with make link/make install (see Development Setup), and the integration activates on your next shell.

The plugin is oh-my-zsh compatible too — clone the repo into $ZSH_CUSTOM/plugins/stackr and add stackr to your plugins=(...) list.

Shell Completions

If you'd rather wire things up manually (or aren't on zsh), generate completions directly:

# Bash
sr completion bash > /etc/bash_completion.d/sr

# Zsh
sr completion zsh > "${fpath[1]}/_sr"

# Fish
sr completion fish > ~/.config/fish/completions/sr.fish

And the worktree auto-cd wrapper (add to your .zshrc/.bashrc):

eval "$(sr shell-hook)"

Quick Start

# Initialize stackr in your repo
cd my-project
sr init

# Create your first stacked branch
sr create feat-models -m "Add user model"

# Stack another branch on top
sr create feat-api -m "Add user API endpoints"

# See your stack
sr log
# ◉ feat-api ←
#
# ◯ feat-models
#
# ◯ main (trunk)

# Trunk moved? Sync everything
sr sync

# Push and open PRs for the whole stack
sr submit --stack

Core Concepts

The Stack Graph

Stackr maintains a directed acyclic graph of your branches. Every tracked branch has exactly one parent (except trunk), and can have multiple children. This graph is stored alongside your git data and powers all stack operations.

        ┌── feat-c
feat-a ─┤
        └── feat-b ── feat-d

Trunk

Your main integration branch (main, master, etc.). Set during sr init. All stacks root here. View or switch to it with sr trunk.

Branch Metadata

Each tracked branch carries:

Field Purpose
Parent Which branch this one builds on
Children Branches that depend on this one
Revision The git SHA at the branch tip
Description A short objective for the branch
Context Structured key-value entries (for humans and AI agents)
Frozen If true, skipped during automatic restacking

Context Entries

Context entries are structured metadata you attach to branches — design decisions, references, ticket links. They're especially useful for AI-assisted workflows where agents need to understand why a branch exists.

sr context set approach "Using JWT for stateless auth" \
  --source file:internal/auth/jwt.go \
  --ticket AUTH-456

Command Reference

Initialization

Command Description
sr init Initialize stackr in a git repository
sr config Show or modify stackr configuration
sr config set <key> <value> Set a config value (e.g. trunk, remote)

Creating & Tracking Branches

Command Alias Description
sr create [name] c Create a new branch on top of the current one
sr track [branch] tr Start tracking an existing branch
sr untrack [branch] utr Stop tracking a branch
sr delete [branch] dl Delete a branch and reparent its children

sr create flags:

-m, --message     Commit message (creates an initial commit)
-a, --all         Stage all tracked changes
-u, --untracked   Stage tracked file changes
-p, --patch       Interactive patch selection
-i, --insert      Insert between current branch and its children
    --desc        Set branch description/objective
    --worktree    Create in a worktree instead of checking out

Navigation

Command Alias Description
sr up [N] u Move N branches upstack (away from trunk)
sr down [N] d Move N branches downstack (toward trunk)
sr top t Jump to the top of the current stack
sr bottom b Jump to the bottom of the current stack (first branch above trunk)
sr checkout [branch] Switch to a tracked branch
sr trunk Show or switch to trunk

Visualization & Information

Command Alias Description
sr log l Visualize the stack tree
sr info [branch] Show branch details (parent, children, commits, context)
sr parent [branch] Show parent branch
sr children [branch] Show child branches

sr log flags:

-a, --all       Show all stacks, not just the current one
-l, --long      Show commits for each branch
-r, --reverse   Reverse order (trunk at bottom)
-s, --stack     Show only the current stack

sr info flags:

-d, --diff      Show full diff against parent
-s, --stat      Show diff stat against parent

Branch Metadata

Command Alias Description
sr describe [text] desc Set or show the branch description/objective
sr context set <key> <text> Add/update a context entry
sr context rm <key> Remove a context entry
sr context list List all context entries

Context flags:

--source type:reference    Source reference (repeatable)
--ticket ID                Related ticket IDs (comma-separated or repeatable)

Committing

Command Description
sr commit Commit with stackr context tracking

sr commit flags:

-m, --message     Commit message (required)
-a, --all         Stage all tracked changes
-u, --untracked   Stage tracked file changes
-p, --patch       Interactive patch selection
    --desc        Update branch description
    --context     Commit context JSON blob (repeatable)

Context entries are structured JSON attached to individual commits:

sr commit -a -m "add validation" --context '{"key":"step-3","text":"Implementing zod validation","sources":[{"type":"file","reference":"codev/plans/1-validation.md"}]}'

Stack Operations

Command Alias Description
sr restack r Rebase the stack so branches are correctly ordered
sr sync Fetch trunk, restack, and clean merged branches
sr absorb ab Distribute staged changes to the right stack commits
sr split sp Split the current branch into multiple branches
sr fold Merge the current branch into its parent
sr squash Combine commits within a branch
sr move Move a branch onto a new parent (prompts if --onto is omitted)
sr reorder Reorder branches in a stack
sr pop Remove current branch and move to parent
sr freeze Mark a branch as frozen (skip during restack)
sr unfreeze Unfreeze a branch (resume restacking)

sr sync flags:

--restack       Restack after syncing (default: true)
-f, --force     Force sync
-a, --all       Sync all stacks

Collaboration

Command Alias Description
sr submit s Push branches and create/update PRs
sr get [branch] Fetch a branch from remote and track it
sr push-meta Push stackr metadata to the remote
sr pull-meta Pull and merge stackr metadata from the remote

sr submit flags:

-d, --draft           Mark PRs as draft
-s, --stack           Push all branches in the stack
-u, --update-only     Only submit branches that already have a PR or remote branch
-f, --force           Overwrite the remote when it has content you don't, without
                      prompting (the push is still lease-pinned)
    --no-force        Never force-push; fail instead
    --dry-run         Show what would be pushed, changing nothing
    --pr-meta         PR content as JSON, or a path to a file of JSON (repeatable)
    --title           PR title for a single PR (shorthand for --pr-meta)
    --body            PR body (used with --title)
    --body-file       Read PR body from file (used with --title)
    --ai              Launch Claude to generate and submit PR
    --aiprepare       Output PR context as JSON (for agents)

Writing PRs for a whole stack: --pr-meta. A submit pushes the current branch and its downstack ancestors, creating a PR for each one that lacks it. --title/--body can only describe one of those, so anything below the branch you are standing on either gets prompted for interactively or is pushed without a PR — a gap in the stack, where the PR above opens against a ref nobody reviews.

--pr-meta addresses content per branch. Each entry is {"branch", "title", "body" | "bodyFile", "draft"}, and a value is either inline JSON or a path to a file of JSON, holding one object or an array:

# One file for the whole stack — the usual form for a generated submit.
sr submit --stack --pr-meta prs.json

# Inline, one branch at a time; repeatable.
sr submit \
  --pr-meta '{"branch":"feat/api","title":"Add the endpoint","bodyFile":"/tmp/api.md"}' \
  --pr-meta '{"branch":"feat/ui","title":"Wire up the form","bodyFile":"/tmp/ui.md","draft":true}'
[
  { "branch": "feat/api", "title": "Add the endpoint", "bodyFile": "/tmp/api.md" },
  { "branch": "feat/ui",  "title": "Wire up the form", "bodyFile": "/tmp/ui.md", "draft": true }
]

"branch" may be omitted only when the submit creates exactly one PR — the one case where there is nothing to be ambiguous about. With more than one, the same entry could belong to either, and labelling a branch with another branch's summary is worse than an error, because it survives review looking deliberate.

"draft" overrides --draft for that branch, so one entry can opt out of an otherwise-draft submit.

The whole payload is validated before any PR is created: a file that is wrong about its third branch costs you a message, not two PRs and a half-built stack to unpick. Branch names are checked earlier still, before anything is pushed.

Force pushing is automatic — and safe. Restacking rewrites SHAs, so pushing a stacked branch nearly always needs a force push. Rather than making you decide whether -f is safe today, sr submit works it out per branch:

  1. If the remote still holds the commit stackr itself last pushed there, everything on it is yours and the force push is lossless. No prompt.
  2. Otherwise stackr compares content: a restack, squash, absorb, split or reorder contributes nothing new to the remote and still pushes silently.
  3. Only if the remote genuinely holds changes you don't have does it stop and ask — with the option to merge them in (squashed or cherry-picked), take theirs, or overwrite.

This all happens in a preflight that runs across every branch being submitted before anything is pushed, so you settle the whole stack in one go rather than discovering a conflict halfway through publishing it. Every force push pins its lease to the exact commit that was inspected, so if the remote moves while you're resolving, the push is rejected rather than overwriting it.

If preflight changed branches locally and you want them back, it prints a rollback id:

sr rollback              # undo the most recent submit's local changes
sr rollback --list       # see what's available
sr rollback 20260731-143022

(sr rollback restores branch tips. sr undo restores the branch graph — who depends on whom — and can't put back a reset or a cherry-pick.)

Three submit modes:

  1. Programmatic — an agent gathers context with sr submit --aiprepare, then calls sr submit --pr-meta prs.json once for the whole stack
  2. Bare interactivesr submit with no flags presents a wizard (Push only / Create PR)
  3. Agent interactivesr submit --ai spawns a Claude session that generates and submits the PR autonomously

The --aiprepare JSON describes the whole job — one entry per branch the submit acts on, each with its parent, description, recorded context entries, commits and any existing PR, plus a needsPR flag on the gaps. It is the input side of --pr-meta: the agent reads one payload describing every branch and writes one back. What it does not carry is the diff. The patch is the one unbounded thing in there, and most PR descriptions never need it, so instead the JSON carries a diffCommand field: the git diff invocation that prints this branch's changes against its parent. The agent runs it only if it decides it has to see the code.

Address Review

Command Description
sr address-review Walk the stack and address PR review comments interactively
sr address-review --aiprepare Output all unresolved comments as JSON (for agents)
sr address-review --ai Launch Claude to address all comments autonomously

Three address-review modes (same pattern as submit):

  1. Programmaticsr address-review --aiprepare outputs JSON, agent makes changes and resolves threads
  2. Bare interactivesr address-review walks bottom-up, presents each comment, lets you edit/reply/skip
  3. Agent interactivesr address-review --ai spawns Claude with /goal to address everything autonomously

State Management

Command Description
sr undo Undo the last stack mutation (the branch graph)
sr rollback [id] Restore branch tips recorded before a submit changed them
sr continue Continue after resolving a rebase conflict
sr abort Abort an in-progress operation
sr revert Revert a previous operation

Implementing Issues (sr implement)

Turn a GitHub issue or Jira ticket into a working branch in one step. sr implement <ref> fetches the issue host-side, creates a new tracked branch named <ref>-<title-slug>, records the issue linkage, and drives implementation.

Command Description
sr implement 123 GitHub issue → new branch; implement here or spawn Claude
sr implement PROJ-456 --worktree Jira ticket in a worktree
sr implement 123 --sandbox implement in a disposable sandbox (implies --worktree)
sr implement 123 --ai scaffold the branch and emit {branch, worktreePath, issueRef, prompt} as JSON

Source detection is automatic: a number (123, #123) or GitHub issue URL is a GitHub issue; a KEY-N (PROJ-456) or browse URL is a Jira ticket. Force it with --source github|jira.

How it implements depends on context: inside a Claude session (or with --ai) it scaffolds and hands the brief back as JSON — no nested agent; a bare terminal spawns an interactive Claude on the brief; --sandbox runs it in a container (attaching in a terminal, detached + JSON when driven by a skill).

Other flags: --branch <name> overrides the derived name, --parent <branch> changes what it stacks on (default: current branch), --comments folds the issue discussion into the brief. GitHub needs gh; Jira needs the jira CLI.

Sandboxed AI Sessions (sr sandbox)

Run Claude with --dangerously-skip-permissions without exposing your host: a disposable Docker container works on the branch's worktree, while your ~/.claude config, skills, and session history are shared so the work is indistinguishable from a normal local session — and resumable.

Command Alias Description
sr sandbox [branch] [-- "<prompt>"] sb Launch (or reuse) a sandbox for a branch and attach
sr sandbox attach [branch] Reattach; no arg opens a searchable picker
sr sandbox ls List this repo's sandboxes with status
sr sandbox watch [--notify] Live dashboard, or headless desktop notifications
sr sandbox stop <branch> Stop the container (relaunch resumes)
sr sandbox rm <branch> [--delete] Remove the container (--delete also removes the worktree)
sr sandbox config [--ai] Edit sandbox config in a TUI, or let Claude help

Highlights:

  • Session continuity — the sandbox's Claude session appears under the same ~/.claude/projects entry as the repo, so host claude --resume sees it.
  • Egress firewall by default — only an allowlist (Anthropic, GitHub, registries) is reachable; the agent requests new domains, which you add to the config and relaunch. --network full opts out.
  • No credentials in the sandbox — it records a proposed PR as a pr branch context entry; run sr submit on the host to open the PR from it.
  • Attentionsr sandbox ls/watch show when a session is waiting on you.

Requires Docker. The base image is built once and reused; per-container differences are just bind mounts and the launch command.

Utilities

Command Description
sr rename Rename a branch
sr modify Amend the current branch and restack descendants
sr worktree Manage git worktrees
sr claude install Install the stackr skill (with sandbox + implement lanes) for Claude Code
sr shell-hook Print shell integration script
sr completion Generate shell completion scripts

Methodology

Stackr is built around a development rhythm: plan the decomposition, build bottom-up, track decisions as you go, and submit in clean increments. This section describes how to use stackr effectively — whether you're working solo, with a team, or with AI agents.

Think in Layers, Not Features

Before writing code, decompose your feature into layers that build on each other. Each layer becomes a branch. The bottom of the stack should be the most foundational change — the thing everything else depends on.

# Bad: one giant branch
feat-auth (47 files, 2000 lines)

# Good: layered stack
feat-auth-models       ← data structures, types
feat-auth-middleware   ← request validation, token parsing
feat-auth-api          ← endpoints that use the middleware
feat-auth-tests        ← integration tests

Each branch should be independently reviewable. A reviewer looking at feat-auth-middleware should only need to understand feat-auth-models below it — not the entire feature.

Build Bottom-Up, Review Bottom-Up

Start at the bottom of your stack and work upward. When you create a new branch, give it a clear objective:

sr create feat-auth-models --desc "User and session types for JWT auth"

Commit with sr commit instead of git commit to keep the graph in sync and attach reasoning:

sr commit -a -m "add session model" --context '{"key":"design","text":"Sessions are stateless JWTs, not DB-backed"}'

When you're ready for review, submit the whole stack:

sr submit --stack

Reviewers should merge from the bottom up. As each PR merges, sr sync cleans it from the stack and rebases everything above.

Track Decisions, Not Just Code

Code says what changed. Context says why. Stackr has two levels:

Branch context — high-level decisions that apply to the whole branch:

sr context set approach "Stateless JWTs over DB sessions — latency constraint"
sr context set tradeoff "No revocation without a blocklist; acceptable for v1"

Commit context — per-step reasoning attached to individual commits:

sr commit -a -m "add token rotation" --context '{"key":"step","text":"Refresh tokens rotate on use per OWASP guidelines","sources":[{"type":"url","reference":"https://cheatsheetseries.owasp.org/..."}]}'

Both feed into PR description generation (sr submit --ai) and are visible via sr info. Both are lost on squash — persist anything that should outlive the branch to a file before squashing.

Handle Review Comments Across the Stack

When reviewers leave comments on your stack, sr address-review walks from the bottom up, presents each unresolved thread, and lets you edit code, reply, and resolve — then commits, restacks, and moves to the next branch.

# Interactive walkthrough
sr address-review

# Let Claude handle everything
sr address-review --ai

Keep the Stack Healthy

Situation Command
Trunk moved (someone merged) sr sync
Reviewer requested changes mid-stack sr checkout <branch>, fix, sr restack
Branch got too big sr split
Branch is trivial, fold into parent sr fold
Need to reorder the stack sr reorder
Made a mistake sr undo

Working with AI Agents

Stackr is designed for both human and AI-driven development. Every workflow command follows a three-mode pattern:

  1. Interactive — the bare command runs a terminal walkthrough for humans
  2. Programmatic--aiprepare outputs JSON context, --title/--body/--context accept structured input. An agent already in a session composes these.
  3. Autonomous--ai spawns a Claude session that owns the workflow end-to-end

The agent workflow:

  1. Agent reads the branch state: sr info, sr log
  2. Agent sets context as it works: sr context set, sr commit --context
  3. Agent submits when ready: sr submit --aiprepare → craft a PR per branch → sr submit --pr-meta prs.json
  4. Agent addresses review comments: sr address-review --aiprepare → make fixes → reply and resolve

Context entries are the key integration point. They let the agent explain its reasoning in a structured way that persists across sessions and feeds into PR generation.

Worktrees for Parallel Work

For long-running branches or when you want to keep your main working tree clean:

sr create feat-experiment --desc "Try approach B" --worktree
# Creates .worktrees/feat-experiment/ — main working tree stays on current branch

Add a .stackr/hooks/post-worktree script to automate setup (copying .env, running direnv allow, etc.):

#!/bin/bash
# .stackr/hooks/post-worktree
cp .env "$1/.env"
cd "$1" && direnv allow

Workflows

Daily Development

# Start your day — sync with trunk
sr sync

# Start a new feature stack
sr create feat-data-model -m "Add data model"
# ... make changes, commit ...

# Stack the next piece on top
sr create feat-api -m "Add API layer"
# ... make changes, commit ...

# Stack the UI on top of that
sr create feat-ui -m "Add UI components"

Updating Mid-Stack

# Reviewer requested changes on feat-data-model
sr checkout feat-data-model
# ... make fixes, commit ...

# Restack everything above
sr restack

Submitting for Review

# Push the entire stack and open PRs
sr submit --stack

# Or push just the current branch
sr submit

# Preview without pushing
sr submit --dry-run

Handling Trunk Updates

# Trunk moved (someone merged a PR)
sr sync
# Fetches trunk, rebases your stack, cleans up merged branches

Resolving Conflicts

# If a restack hits a conflict, stackr pauses
# Fix the conflict in your editor, then:
git add <resolved-files>
sr continue

# Or bail out:
sr abort

Repairing a Lost Base Commit

Every tracked branch records the commit it was branched from — its base. The range (base, branch] is what stackr replays when restacking, so the base is what keeps a rebase from picking up commits that belong to the parent.

Stackr keeps bases alive behind refs/stackr/bases and repairs them automatically where it safely can, including recovering one from the parent's reflog. If a base is lost beyond recovery — usually after heavy raw-git surgery plus an expired reflog — stackr stops rather than guess, because guessing duplicates or drops commits:

cannot determine which commits belong to feat-3: recorded base 0000000 is
missing or is not an ancestor of the branch.

Point it at the commit the branch was created from:

# See where the branch actually diverged
git log --oneline <parent>..<branch>

# Re-point the base and restack in one step
sr restack --branch feat-3 --base <sha>

Reorganizing a Stack

# Move a branch to a different parent
sr move --onto feat-auth

# Omit --onto to pick from a tree of the stacks. Branches you cannot move
# onto — your own dependents, your current parent — are shown greyed with
# the reason, rather than hidden.
sr move

# A move is a repoint plus a restack: the branch and everything stacked on
# it are replayed onto the new parent. Skip the replay with:
sr move --onto feat-auth --no-restack

# Insert a branch between two existing ones
sr create feat-middleware -i

# Merge a branch into its parent (fold up)
sr fold

# Split a branch that got too big
sr split

Claude Code Integration

Stackr ships a skill that teaches Claude how to use sr commands. Install it with:

sr claude install

sr init also offers this automatically: after initializing, it checks whether the stackr prompt is already reachable — either in the repo's CLAUDE.md or your global one ($CLAUDE_CONFIG_DIR/CLAUDE.md, default ~/.claude/CLAUDE.md) — and, if not, prompts to run the install for you. Already covered locally, it stays silent; covered only globally, it says so and skips. In non-interactive mode it prints a one-line hint instead of prompting.

This creates a single unified skill at .claude/skills/stackr/ — a SKILL.md covering the core workflow (branch creation, navigation, context tracking, conflict recovery, PR submission) plus progressive-disclosure lane files (sandbox.md, implement.md) that Claude reads on demand. Claude then uses sr via Bash instead of raw git. Upgrading from an older version folds the separate sr-sandbox / sr-implement skills into this one automatically.

It also writes an always-on prompt to .claude/prompts/stackr.md and imports it from CLAUDE.md via a small marker-delimited @-reference (@.claude/prompts/stackr.md). A skill only loads when its description matches the request, so this always-on prompt guarantees the essentials — prefer sr over raw git, stack sequential work, travel the stack with sr up/sr down — are in context even when the skill didn't trigger. The prompt lives in its own file (one source of truth) while CLAUDE.md keeps only a tiny import. It's idempotent, removed by sr claude uninstall, and leaves the rest of CLAUDE.md untouched. Pass --no-prompt-block to skip it, or --local to install into the current directory's .claude instead of the repo root (works even outside a git repo).

For programmatic workflows (agents already in a session), use the two-step submit:

# 1. Gather context for every branch the submit will act on
sr submit --aiprepare

# 2. Write a body file per branch, then one payload naming them all
cat > /tmp/prs.json <<'JSON'
[
  { "branch": "feat/api", "title": "Add auth middleware", "bodyFile": "/tmp/pr-api.md" },
  { "branch": "feat/ui",  "title": "Gate the dashboard",  "bodyFile": "/tmp/pr-ui.md" }
]
JSON

# 3. Create them all, bottom-up, in one command
sr submit --pr-meta /tmp/prs.json

For AI-driven submit, sr submit --ai spawns a Claude session that generates and submits the PR autonomously.

For addressing review comments across the stack:

# Gather all unresolved comments as JSON
sr address-review --aiprepare

# Walk through comments interactively
sr address-review

# Let Claude handle everything
sr address-review --ai

Storage

Stackr stores metadata in two tiers:

Shared metadata — refs/stackr/data

The branch graph, config, and PR info are stored as git objects behind a custom ref. This means:

  • Metadata can travel with git push/git fetch via refspecs
  • Git's garbage collection manages cleanup
  • Works correctly across worktrees (shared .git directory)
Blob Contents
config.json Trunk branch name, remote name
branches.json Complete branch graph with metadata
pr_info.json PR numbers, URLs, and state per branch

Local ephemeral data — .git/.stackr/

Per-machine state that shouldn't travel with push/pull:

Path Contents
undo/snapshots/ Graph snapshots for rollback
undo/events.json Undo event log
rebase-state.json In-progress rebase state

Architecture

cmd/             CLI commands (Cobra)
internal/
  context/       Session initialization, repo discovery
  engine/        Core algorithms (create, restack, sync, submit, ...)
  git/           Git command wrapper
  graph/         Branch graph model and tree rendering
  store/         Storage (git-ref shared + filesystem local)
  ui/            Terminal UI (charmbracelet/bubbletea)
  errors/        Sentinel error types
pkg/
  version/       Build metadata (set via ldflags)

Key Design Decisions

  • Engine layer separates business logic from CLI concerns — each operation (create, sync, restack) lives in its own file under internal/engine/
  • Graph is the single source of truth — all operations read the graph, mutate it, and write it back. Undo works by snapshotting the graph before mutations.
  • Git wrapper is explicitinternal/git/ exposes methods like RebaseBranch, CommitsBetween, DiffStat rather than raw command execution, making the engine testable.
  • Two-tier storage — shared metadata (graph, config, PRs) lives in git objects behind refs/stackr/data; local ephemeral data (undo, rebase state) stays on the filesystem under .git/.stackr/.

Global Flags

    --cwd string       Run as if started in this directory
    --debug            Print git commands as they run
    --interactive      Enable interactive prompts (default: true)
-q, --quiet            Suppress non-essential output
    --no-verify        Skip git hooks
-v, --version          Show version

Development Setup

make setup      # Create .envrc from template
make build      # Build to build/sr
make link       # Symlink to $STACKR_LINK_DIR (from .envrc)
make install    # Install to $GOPATH/bin/sr
make test       # Run all tests
make clean      # Remove build artifacts

License

See LICENSE for details.

About

Local stacked-branch workflow manager for Git

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages