GitButler Stacks
Dependent branches → anchor-based stacking → reviewable chunks.
<when_to_use>
- •Sequential dependencies (e.g., refactor → API → frontend)
- •Large features broken into reviewable chunks
- •Granular code review (approve/merge early phases independently)
- •Post-hoc stack organization after exploratory coding
NOT for: independent parallel features (use virtual branches), projects using Graphite stacking
</when_to_use>
Stacked vs Virtual Branches
| Type | Use Case | Dependencies |
|---|---|---|
| Virtual | Independent, unrelated work | None — parallel |
| Stacked | Sequential dependencies | Each builds on parent |
Stacked branches = virtual branches split into dependent sequence. Default: Virtual branches are stacks of one.
Creating Stacks
# Base branch (no anchor) but branch new base-feature # Stacked branch (--anchor specifies parent) but branch new child-feature --anchor base-feature # Third level but branch new grandchild-feature --anchor child-feature
Result: base-feature ← child-feature ← grandchild-feature
Short form: -a instead of --anchor
but branch new child -a parent
Stack Patterns
Common patterns: feature dependency chains, refactoring sequences, deep stacks.
Example - Feature Dependency:
but branch new auth-core but branch new auth-oauth --anchor auth-core but branch new auth-social --anchor auth-oauth
See references/patterns.md for detailed patterns with commit examples.
Post-Hoc Stack Organization
Convert independent branches into a stack by recreating with correct anchors:
- •Create new branch with
--anchorpointing to intended parent - •Move commits with
but rub <sha> <new-branch> - •Delete original branch
See references/reorganization.md for detailed workflows.
Publishing Stacks
Using but publish (Preferred)
# Publish entire stack - pushes and creates PRs but publish # Publish specific branch only but publish -b dependent-feature
but publish handles:
- •Pushing branches to remote
- •Creating PRs with correct base branches
- •Updating existing PRs if already created
Using GitHub CLI (Alternative)
# Push branches git push -u origin base-feature git push -u origin dependent-feature # Create PRs with correct base branches gh pr create --base main --head base-feature \ --title "feat: base feature" \ --body "First in stack" gh pr create --base base-feature --head dependent-feature \ --title "feat: dependent feature" \ --body "Depends on base-feature PR"
GitHub Settings
- •Enable automatic branch deletion after merge
- •Use Merge strategy (recommended) — no force pushes needed
- •Merge bottom-to-top (sequential order)
Conflict Handling in Stacks
GitButler resolves conflicts per-commit during rebase:
- •When base branch updates, dependent commits rebase automatically
- •Conflicted commits marked but don't block other commits
- •Resolve conflicts per affected commit
- •Partial resolution can be saved and continued later
# Update base (may trigger rebases in stack) but base update # Check which commits have conflicts but status # Resolve in editor, GitButler auto-detects resolution
Unlike git rebase: Remaining commits continue rebasing even if some conflict.
Stack Reorganization
Key operations for restructuring stacks:
| Operation | Command |
|---|---|
| Squash commits | but rub <newer> <older> |
| Move commit | but rub <sha> <target-branch> |
| Split branch | Create anchored branch, move commits |
See references/reorganization.md for detailed examples.
Stack Navigation
Note: Virtual branches don't need checkout — all branches active simultaneously.
# View full stack structure
but log
# Work on any branch directly (no checkout needed)
but commit base-feature -m "update base"
but commit dependent-feature -m "update dependent"
# JSON for programmatic analysis
but --json log | jq '.[] | .branchDetails[] | {name, baseCommit}'
ALWAYS:
- •Create stacks with
--anchorfrom the start - •Merge stacks bottom-to-top (base first, dependents after)
- •Snapshot before reorganizing:
but snapshot --message "Before stack reorganization" - •Keep each level small (100-250 LOC) for reviewability
- •Delete empty branches after reorganization
NEVER:
- •Skip stack levels when merging
- •Stack independent, unrelated features (use virtual branches)
- •Create deep stacks (5+ levels) without good reason
- •Forget anchor when creating dependent branches
Troubleshooting
| Symptom | Cause | Solution |
|---|---|---|
Stack not showing in but log | Missing --anchor | Recreate with correct anchor |
| Commits in wrong stack level | Wrong branch targeted | but rub <sha> correct-branch |
| Can't merge middle of stack | Wrong order | Merge bottom-to-top only |
Recovery
To fix a branch with wrong/missing anchor: create new branch with correct anchor, move commits with but rub, delete original.
See references/reorganization.md for complete recovery procedures.
Best Practices
Planning
- •Start simple: 2-3 levels max initially
- •Single responsibility per level
- •Only stack when there's a real dependency
Maintenance
- •Run
but logregularly to verify structure - •Commit to correct branches immediately
- •Clean up empty branches
Communication
- •Clear commit messages explaining why stack level exists
- •Descriptive names indicating stack relationship
- •Share
but statuswhen coordinating
Reference Files
- •
references/patterns.md— Detailed stack patterns (feature dependency, refactoring, deep stacks) - •
references/reorganization.md— Post-hoc organization, squashing, moving commits, splitting
Related Skills
- •gitbutler-virtual-branches — Core GitButler workflows
- •gitbutler-complete-branch — Merging to main
- •gitbutler-multi-agent — Multi-agent coordination