📦 deps(thirdparty): update snapshots

This commit is contained in:
ci[bot]
2026-05-29 08:33:53 +00:00
parent fdb52f1e96
commit 06e0d13d57
1615 changed files with 232858 additions and 0 deletions
@@ -0,0 +1,296 @@
---
name: gitbutler-complete-branch
description: This skill should be used when the user asks to "complete a branch", "merge to main", "finish my feature", "ship this branch", "integrate to main", "create a PR from GitButler", or when `--complete-branch` flag is mentioned. Guides completion of GitButler virtual branches with safety snapshots, integration workflows, and cleanup.
metadata:
version: "1.0.0"
author: outfitter
category: version-control
related-skills:
- gitbutler-virtual-branches
- gitbutler-stacks
---
# Complete GitButler Virtual Branch
Virtual branch ready → snapshot → merge to main → cleanup → return.
<when_to_use>
- Virtual branch work is complete and ready to ship
- Tests pass and code is reviewed (if required)
- Ready to merge changes into main branch
- Need to clean up completed branches
NOT for: ongoing work, branches needing more development, stacks (complete bottom-to-top)
</when_to_use>
## TL;DR
**Using CLI** (preferred): `but oplog snapshot` -> `but push <branch>` -> `but pr new <branch>` -> merge PR on GitHub -> `but branch delete <branch>`
**Direct merge**: `but oplog snapshot` -> `git checkout main` -> `git pull` -> `git merge --no-ff refs/gitbutler/<branch>` -> `git push` -> `but branch delete <branch>` -> `git checkout gitbutler/workspace`
**Manual PR workflow**: `git push origin refs/gitbutler/<branch>:refs/heads/<branch>` -> `gh pr create` -> merge PR -> cleanup
See detailed workflows below.
## Pre-Integration Checklist
Run through before any integration:
| Check | Command | Expected |
|-------|---------|----------|
| GitButler running | `but --version` | Version output |
| Work committed | `but status` | Committed changes, no unassigned files |
| Tests passing | `bun test` (or project equivalent) | All green |
| Base updated | `but pull` | Up to date with main |
| Snapshot created | `but oplog snapshot -m "Before integrating..."` | Snapshot ID returned |
## Integration Workflows
### A. Using CLI (Preferred)
```bash
# 1. Verify branch state
but status
but show feature-auth
# 2. Create snapshot
but oplog snapshot --message "Before publishing feature-auth"
# 3. Authenticate with forge (one-time)
but config forge auth
# 4. Push branch and create PR
but push feature-auth
but pr new feature-auth
# 5. Review and merge PR on GitHub
# 6. Update local and clean up
but pull
but branch delete feature-auth
```
**Benefits:**
- Full CLI workflow, no GUI needed
- Correct base branch set automatically for stacks
- Stays in GitButler workspace throughout
### B. Direct Merge to Main
```bash
# 1. Verify branch state
but status
but show feature-auth
# 2. Create snapshot
but oplog snapshot --message "Before integrating feature-auth"
# 3. Switch to main
git checkout main
# 4. Update main
git pull origin main
# 5. Merge with --no-ff (preserves history)
git merge --no-ff refs/gitbutler/feature-auth -m "feat: add user authentication"
# 6. Push
git push origin main
# 7. Clean up
but branch delete feature-auth
git checkout gitbutler/workspace
```
### C. Manual Pull Request Workflow
```bash
# 1. Push branch to remote
git push origin refs/gitbutler/feature-auth:refs/heads/feature-auth
# 2. Create PR
gh pr create --base main --head feature-auth \
--title "feat: add user authentication" \
--body "Description..."
# 3. Wait for review and approval
# 4. Merge PR (via GitHub UI or CLI)
gh pr merge feature-auth --squash
# 5. Update main and clean up
git checkout main
git pull origin main
but branch delete feature-auth
git checkout gitbutler/workspace
```
### D. Stacked Branches (Bottom-Up)
```bash
# Must merge in order: base → dependent → final
# 1. Merge base branch first
git checkout main && git pull
git merge --no-ff refs/gitbutler/feature-base -m "feat: base feature"
git push origin main
but branch delete feature-base
git checkout gitbutler/workspace
# 2. Update remaining branches
but pull
# 3. Merge next level
git checkout main && git pull
git merge --no-ff refs/gitbutler/feature-api -m "feat: API feature"
git push origin main
but branch delete feature-api
git checkout gitbutler/workspace
# 4. Repeat for remaining stack levels
```
> For comprehensive stacked branch management, load the **gitbutler-stacks** skill.
## Error Recovery
### Merge Conflicts
```bash
# View conflicted files
git status
# Resolve conflicts manually
# Stage resolved files
git add src/auth.ts
# Complete merge
git commit
# Verify and push
git push origin main
# Clean up
but branch delete feature-auth
git checkout gitbutler/workspace
```
### Push Rejected (Main Moved Ahead)
```bash
git pull origin main
# Resolve any conflicts if main diverged
git push origin main
```
### Undo Integration (Not Pushed Yet)
```bash
git reset --hard HEAD~1
git checkout gitbutler/workspace
```
### Undo Integration (Already Pushed)
```bash
git revert -m 1 HEAD
git push origin main
```
## Post-Integration Cleanup
```bash
# Delete integrated virtual branch
but branch delete feature-auth
# Clean up remote branch (if created for PR)
git push origin --delete feature-auth
# Verify workspace is clean
but status # Should show remaining active branches only
but status # Branch should be gone
```
<rules>
ALWAYS:
- Create snapshot before integration: `but oplog snapshot --message "..."`
- Use `--no-ff` flag to preserve branch history
- Return to workspace after git operations: `git checkout gitbutler/workspace`
- Run tests before integrating
- Complete stacked branches bottom-to-top
NEVER:
- Merge without snapshot backup
- Skip updating main first (`git pull`)
- Forget to return to `gitbutler/workspace`
- Merge middle of stack before base
- Force push to main without explicit confirmation
</rules>
## Troubleshooting
| Symptom | Cause | Solution |
|---------|-------|----------|
| Merge conflicts | Diverged from main | Resolve conflicts, stage, commit |
| Push rejected | Main moved ahead | `git pull`, resolve, push |
| Branch not found | Wrong ref path | Use `refs/gitbutler/<name>` |
| Can't return to workspace | Integration branch issue | `git checkout gitbutler/workspace` |
## Emergency Recovery
```bash
# If integration went wrong
but oplog
but undo # Restores pre-integration state
# If stuck after git operations
git checkout gitbutler/workspace
```
## Best Practices
**Keep branches small:**
- Small branches = easier merges
- Aim for single responsibility per branch
**Update base regularly:**
```bash
but pull
```
**Test before integrating:**
- Always run full test suite before merging
**Meaningful merge commits:**
```bash
# Good: Describes what and why
git merge --no-ff feature-auth -m "feat: add JWT-based user authentication"
# Bad: Generic message
git merge --no-ff feature-auth -m "Merge branch"
```
<references>
### Related Skills
- [gitbutler-virtual-branches](../virtual-branches/SKILL.md) — Core GitButler workflows
- [gitbutler-stacks](../stacks/SKILL.md) — Stacked branches
### Reference Files
- [gitbutler-virtual-branches/references/reference.md](../virtual-branches/references/reference.md) — CLI reference and troubleshooting
### External
- [GitButler GitHub Integration](https://docs.gitbutler.com/features/forge-integration/github-integration)
</references>
@@ -0,0 +1,357 @@
---
name: gitbutler-multi-agent
description: This skill should be used when coordinating multiple AI agents working concurrently, handling agent handoffs, transferring commits between agents, or when "multi-agent", "concurrent agents", "parallel agents", "agent collaboration", or "parallel execution" are mentioned with GitButler. Provides virtual branch patterns for parallel execution without coordination overhead.
metadata:
version: "1.0.0"
author: outfitter
category: version-control
related-skills:
- gitbutler-virtual-branches
- gitbutler-stacks
- multi-agent-vcs
---
# GitButler Multi-Agent Coordination
Multiple agents → virtual branches → parallel execution → zero coordination overhead.
<when_to_use>
- Multiple agents working on different features simultaneously
- Sequential agent handoffs (Agent A → Agent B)
- Commit ownership transfer between agents
- Parallel execution with early conflict detection
- Post-hoc reorganization of multi-agent work
NOT for: single-agent workflows (use standard GitButler), projects needing PR automation (Graphite better)
</when_to_use>
## Core Advantage
**Traditional Git Problem:**
- Agents must work in separate worktrees (directory coordination)
- Constant branch switching (context loss, file churn)
- Late conflict detection (only at merge time)
**GitButler Solution:**
- Multiple branches stay applied simultaneously
- Single shared workspace, zero checkout operations
- Immediate conflict detection (shared working tree)
- Each agent manipulates their own lane
## Workflow Patterns
### Pattern 1: Parallel Feature Development
```bash
# Agent 1
but branch new agent-1-auth
echo "auth code" > auth.ts
but rub auth.ts agent-1-auth
but commit agent-1-auth -m "feat: add authentication"
# Agent 2 (simultaneously, same workspace!)
but branch new agent-2-api
echo "api code" > api.ts
but rub api.ts agent-2-api
but commit agent-2-api -m "feat: add API endpoints"
# Result: Two independent features, zero conflicts
```
### Pattern 2: Sequential Handoff
```bash
# Agent A: Initial implementation
but branch new initial-impl
# ... code ...
but commit initial-impl -m "feat: initial implementation"
# Agent B: Takes ownership and refines
but rub <agent-a-commit> refinement-branch
# ... improve code ...
but commit refinement-branch -m "refactor: optimize implementation"
```
### Pattern 3: Cross-Agent Commit Transfer
```bash
# Instant ownership transfer
but rub <commit-sha> agent-b-branch # Agent A → Agent B
but rub <commit-sha> agent-a-branch # Agent B → Agent A
```
### Pattern 4: Agent Code Review Cycle
Reviewer agent commits fixes separately, then swap/merge:
```bash
# Author agent implements
but branch new author-impl
but commit author-impl -m "feat: implement feature"
# Reviewer agent creates sibling branch for fixes
but branch new reviewer-fixes
# ... reviewer makes fixes ...
but commit reviewer-fixes -m "fix: address review feedback"
# Adopt reviewer fixes into author branch
but rub <reviewer-commit> author-impl
# Clean audit trail, final branch has both
```
### Pattern 5: Agent Swarm (Many Agents, One Branch)
Multiple agents contribute to a single feature:
```bash
but branch new shared-feature
# Agent A assigns their work
but rub <a-file-id> shared-feature
# Agent B assigns their work
but rub <b-file-id> shared-feature
# Agent C assigns their work
but rub <c-file-id> shared-feature
# Single commit with all contributions
but commit shared-feature -m "feat: collaborative implementation"
```
Use with Workspace Rules (`but mark`) for auto-assignment to branches.
### Pattern 6: Exploratory Development
Compare multiple approaches in parallel:
```bash
# Parent branch with shared setup
but branch new perf-parent
but commit perf-parent -m "chore: benchmark setup"
# Strategy A
but branch new perf-strategy-a --anchor perf-parent
but commit perf-strategy-a -m "perf: try caching approach"
# Strategy B
but branch new perf-strategy-b --anchor perf-parent
but commit perf-strategy-b -m "perf: try batching approach"
# Run benchmarks on each, keep winner
but rub <winning-commit> perf-parent
```
### Pattern 7: Emergency Hotfix (Feature Work Continues)
Ship a fix without disturbing ongoing multi-agent work:
```bash
# Create isolated hotfix branch
but branch new hotfix-urgent
but rub <file-id> hotfix-urgent
but commit hotfix-urgent -m "fix: prod outage"
# Push and create PR
but push hotfix-urgent
but pr new hotfix-urgent
# Other agents continue unaffected in their lanes
```
## Branch Naming Convention
```
<agent-name>-<task-type>-<brief-description>
Examples:
- claude-feat-user-auth
- droid-fix-api-timeout
- codex-refactor-database-layer
```
Makes ownership immediately visible in `but status`.
## AI Integration Methods
### 1. Agents Tab (GUI)
- Branch-agent binding in GitButler GUI
- Each virtual branch = independent agent session
- Automatic commit management per session
- Parallel execution with branch isolation
- Access: `but gui` then navigate to Agents Tab
### 2. Lifecycle Hooks (CLI)
| Platform | Commands |
|----------|----------|
| **Claude Code** | `but claude pre-tool`, `but claude post-tool`, `but claude stop` |
| **Cursor** | `but cursor after-edit`, `but cursor stop` |
Example Claude Code hooks config (`.claude/hooks.json`):
```json
{
"hooks": {
"PostToolUse": [{"matcher": "Edit|Write", "hooks": [{"type": "command", "command": "but claude post-tool"}]}],
"Stop": [{"matcher": "", "hooks": [{"type": "command", "command": "but claude stop"}]}]
}
}
```
### 3. MCP Server
```bash
but mcp # Start MCP server for programmatic access
```
Exposes `gitbutler_update_branches` tool for async commit processing.
### 4. Workspace Rules (Auto-Assignment)
```bash
but mark agent-auth-branch
but mark agent-api-branch
```
New changes auto-route to the marked branch.
**Key Instruction for All Agents:**
> "Never use the git commit command after a task is finished"
For detailed hook configs and MCP schemas, see `references/ai-integration.md`.
## The `but rub` Power Tool
Single command handles four critical multi-agent operations:
| Operation | Example | Use Case |
|-----------|---------|----------|
| **Assign** | `but rub m6 claude-branch` | Organize files to branches post-hoc |
| **Move** | `but rub abc1234 other-branch` | Transfer work between agents |
| **Squash** | `but rub newer older` | Clean up history |
| **Amend** | `but rub file commit` | Fix existing commits |
## Coordination Protocols
**Status Broadcasting:**
```bash
# File-based coordination
but status > /tmp/agent-$(whoami)-status.txt
# Or use Linear/GitHub comments
# "[AGENT-A] Completed auth module, committed to claude-auth-feature"
```
**Concurrent Safety:**
1. Snapshot before risky operations
2. Broadcast status regularly to other agents
3. Respect 🔒 locks — files assigned to other branches
4. Use `but --json` for programmatic state inspection
## vs Other Workflows
| Aspect | Graphite | Git Worktrees | GitButler |
|--------|----------|---------------|-----------|
| Multi-agent concurrency | Serial | N directories | Parallel ✓ |
| Post-hoc organization | Difficult | Difficult | `but rub` ✓ |
| PR Submission | `gt submit` ✓ | Manual | `but push` + `but pr new` ✓ |
| Physical layout | 1 directory | N × repo | 1 directory ✓ |
| Context switching | `gt checkout` | `cd` | None ✓ |
| Conflict detection | Late (merge) | Late (merge) | Early ✓ |
| Disk usage | 1 × repo | N × repo | 1 × repo ✓ |
## Decision Framework: When to Use What
### Use GitButler when:
- Multiple agents work in same repo simultaneously
- Exploratory development (organize code after writing)
- Frequent reorganization of commits between branches
- Visual organization preferred (GUI + CLI)
- Early conflict detection matters
### Use Graphite when:
- Fully automated CLI workflows (scripted end-to-end)
- Terminal-first teams
- Established stacked PR practices
- Need `gt up`/`gt down` stack navigation
### Use Git Worktrees when:
- Complete branch isolation required
- Different dependencies per branch
- CI/CD needs separate checkouts
**Don't mix in same repo** - Choose one model per repository.
<rules>
ALWAYS:
- Use unique branch names per agent: `<agent>-<type>-<desc>`
- Assign files immediately after creating: `but rub <id> <branch>`
- Snapshot before coordinated operations
- Broadcast status to other agents when completing work
- Check for 🔒 locked files before modifying
NEVER:
- Use `git commit` — breaks GitButler state
- Let files sit in "Unassigned Changes" — assign immediately
- Modify files locked to other branches
- Mix git and but commands during active agent sessions
</rules>
## Troubleshooting
| Symptom | Cause | Solution |
|---------|-------|----------|
| Agent commit "orphaned" | Used `git commit` | Find with `git reflog`, recover |
| Files in wrong branch | Forgot assignment | `but rub <id> <correct-branch>` |
| Conflicting edits | Overlapping files | Reassign hunks to different branches |
| Lost agent work | Branch deleted | `but undo` or restore from oplog |
## Recovery
```bash
# Find orphaned commits
git reflog
# Recover agent work
but oplog
but undo
# Extract from snapshot
git show <snapshot>:index/path/to/file.txt
```
## Limitations
- **Overlapping file edits** — adjacent lines can only go to one branch
- **No stack navigation CLI** — no `gt up`/`gt down` equivalent (all branches always applied)
- **MCP server limited** — only `gitbutler_update_branches` tool currently exposed
<references>
### Reference Files
- **`references/ai-integration.md`** — Detailed hook configs, MCP schemas, troubleshooting
### Related Skills
- [gitbutler-virtual-branches](../virtual-branches/SKILL.md) — Core GitButler workflows
- [gitbutler-stacks](../stacks/SKILL.md) — Stacked branches
- **outfitter:multi-agent-vcs** — Tool-agnostic multi-agent policy (invoke with Skill tool)
### External
- [GitButler AI Docs](https://docs.gitbutler.com/features/ai-integration/) — Official AI integration
- [Agents Tab Blog](https://blog.gitbutler.com/agents-tab) — Claude Code integration details
</references>
@@ -0,0 +1,273 @@
# Multi-Agent AI Integration Reference
Detailed configuration and patterns for multi-agent workflows with GitButler.
---
## Hook Configuration by Platform
### Claude Code
File: `.claude/hooks.json`
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|MultiEdit|Write",
"hooks": [
{
"type": "command",
"command": "but claude pre-tool"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|MultiEdit|Write",
"hooks": [
{
"type": "command",
"command": "but claude post-tool"
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "but claude stop"
}
]
}
]
}
}
```
| Hook | Purpose |
|------|---------|
| `but claude pre-tool` | Snapshot before changes |
| `but claude post-tool` | Auto-assign changes to agent's branch |
| `but claude stop` | Finalize commits, cleanup |
### Cursor
```json
{
"hooks": {
"after-edit": "but cursor after-edit",
"stop": "but cursor stop"
}
}
```
---
## MCP Server
### Starting
```bash
but mcp
```
### Available Tool
**`gitbutler_update_branches`**
```typescript
{
prompt: string // Description of changes
}
```
Returns immediately; commits processed asynchronously.
### Current Limitations
- Single tool available
- No branch creation
- No stack operations
- No push/PR operations
---
## Multi-Agent Coordination Strategies
### Strategy 1: Branch-Per-Agent
Each agent owns dedicated branch(es):
```bash
# Agent A owns auth domain
but branch new agent-a-auth
but mark agent-a-auth
# Agent B owns api domain
but branch new agent-b-api
but mark agent-b-api
# New changes auto-route to marked branch
```
**Best for:** Independent parallel development
### Strategy 2: Shared Branch with Turn-Taking
Agents share branch, coordinate via file-based status:
```bash
# File-based coordination
but status > /tmp/agent-$(whoami)-status.txt
# Other agents check before modifying
```
**Best for:** Sequential refinement of same feature
### Strategy 3: Stack-Per-Agent
Agents own stack levels:
```bash
# Agent A: Foundation layer
but branch new foundation
but commit foundation -m "feat: foundation"
# Agent B: Build on foundation
but branch new feature --anchor foundation
but commit feature -m "feat: feature layer"
# Agent C: Tests on top
but branch new tests --anchor feature
but commit tests -m "test: comprehensive tests"
```
**Best for:** Layered architecture development
### Strategy 4: Review Pairs
Author and reviewer agents work in parallel:
```bash
# Author implements
but branch new author-impl
# Reviewer creates sibling for fixes
but branch new reviewer-fixes
# Swap commits as needed
but rub <commit> <other-branch>
```
**Best for:** Code review cycles
---
## Status Broadcasting
### File-Based
```bash
# Broadcast status
but status > /tmp/agent-status-$(hostname)-$(date +%s).txt
# Other agents poll status files
```
### Issue Tracker Comments
```markdown
[AGENT-A] Completed auth module
- Branch: agent-a-auth
- Commits: abc1234
- Ready for review
```
### JSON for Programmatic Inspection
```bash
# Machine-readable status
but status --json | jq '.stacks'
but show feature-branch --json | jq '.commits'
```
---
## Agent Instructions Template
Add to agent system prompt:
```
## GitButler Rules
1. NEVER use `git commit` - use `but commit`
2. NEVER use `git add` - GitButler manages staging
3. NEVER use `git checkout` - all branches always applied
4. ALWAYS check file IDs with `but status` before `but rub`
5. ALWAYS snapshot before risky operations: `but oplog snapshot`
6. Return to workspace after git ops: `git checkout gitbutler/workspace`
## Your Branch
- Name: {agent-branch-name}
- Pattern: {file-pattern}
Assign your changes: `but rub <file-id> {agent-branch-name}`
Commit your work: `but commit {agent-branch-name} -m "your message"`
```
---
## Troubleshooting Multi-Agent
### Agents modifying same files
**Symptom:** Overlapping hunks in unassigned changes
**Solution:**
1. Assign non-overlapping hunks to respective branches
2. For overlapping lines: coordinate which agent owns them
3. Use `but mark` rules for clearer ownership
### Lost agent work
**Recovery:**
```bash
# Check oplog
but oplog
# Undo if recent
but undo
# Or restore from snapshot
but oplog restore <snapshot-id>
```
### Agent committed with git
**Symptom:** Orphaned commit not in GitButler
**Recovery:**
```bash
git reflog # Find orphaned commit
# Create new branch from it
git branch recovered <commit-sha>
# Return to GitButler
git checkout gitbutler/workspace
```
---
## References
- [GitButler MCP Docs](https://docs.gitbutler.com/features/ai-integration/mcp-server)
- [Claude Code Hooks Docs](https://docs.gitbutler.com/features/ai-integration/claude-code-hooks)
- [Cursor Hooks Docs](https://docs.gitbutler.com/features/ai-integration/cursor-hooks)
@@ -0,0 +1,246 @@
---
name: gitbutler-stacks
description: This skill should be used when creating stacks, dependent branches, or when "stack", "stacked branches", "anchor", "--anchor", "but branch new -a", "create dependent branch", or "break feature into PRs" are mentioned with GitButler. Covers anchor-based stacking for dependent features and reviewable PR breakdown.
metadata:
version: "1.0.0"
author: outfitter
category: version-control
related-skills:
- gitbutler-virtual-branches
- gitbutler-complete-branch
- gitbutler-multi-agent
---
# 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
```bash
# 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`
```bash
but branch new child -a parent
```
## Stack Patterns
Common patterns: feature dependency chains, refactoring sequences, deep stacks.
**Example - Feature Dependency:**
```bash
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:
1. Create new branch with `--anchor` pointing to intended parent
2. Move commits with `but rub <sha> <new-branch>`
3. Delete original branch
See `references/reorganization.md` for detailed workflows.
## Publishing Stacks
### Using CLI (Preferred)
```bash
# Push and create PR for a branch
but push dependent-feature
but pr new dependent-feature
# Push all unpushed branches
but push
```
`but push` + `but pr new` handles:
- Pushing branches to remote
- Creating PRs with correct base branches
- Updating existing PRs if already created
### Using GitHub CLI (Alternative)
```bash
# 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:
1. When base branch updates, dependent commits rebase automatically
2. Conflicted commits marked but don't block other commits
3. Resolve conflicts per affected commit
4. Partial resolution can be saved and continued later
```bash
# Update base (may trigger rebases in stack)
but pull
# 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 squash <branch>` or `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.
```bash
# View full stack structure
but status
# Work on any branch directly (no checkout needed)
but commit base-feature -m "update base"
but commit dependent-feature -m "update dependent"
# Inspect a specific branch
but show dependent-feature
# JSON for programmatic analysis
but show dependent-feature --json | jq '.commits[] | .id'
```
<rules>
ALWAYS:
- Create stacks with `--anchor` from the start
- Merge stacks bottom-to-top (base first, dependents after)
- Snapshot before reorganizing: `but oplog 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
</rules>
## Troubleshooting
| Symptom | Cause | Solution |
|---------|-------|----------|
| Stack not showing in `but status` | 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 status` regularly 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 status` when coordinating
<references>
### 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](../virtual-branches/SKILL.md) — Core GitButler workflows
- [gitbutler-complete-branch](../complete-branch/SKILL.md) — Merging to main
- [gitbutler-multi-agent](../multi-agent/SKILL.md) — Multi-agent coordination
### External
- [GitButler Stacks Docs](https://docs.gitbutler.com/features/branch-management/stacked-branches)
- [Stacked Branches Blog](https://blog.gitbutler.com/stacked-branches-with-gitbutler)
</references>
@@ -0,0 +1,53 @@
# Stack Patterns
Detailed patterns for GitButler stacked branches.
## Feature Dependency Stack
Build features that depend on each other in sequence.
```bash
# Auth foundation
but branch new auth-core
but commit auth-core -m "feat: add authentication core"
# OAuth layer depends on auth core
but branch new auth-oauth --anchor auth-core
but commit auth-oauth -m "feat: add OAuth integration"
# Social login depends on OAuth
but branch new auth-social --anchor auth-oauth
but commit auth-social -m "feat: add social login"
```
## Refactoring Stack
Break large refactors into reviewable phases.
```bash
# Extract utilities
but branch new refactor-extract-utils
but commit refactor-extract-utils -m "refactor: extract common utilities"
# Update consumers
but branch new refactor-use-utils --anchor refactor-extract-utils
but commit refactor-use-utils -m "refactor: use extracted utilities"
# Clean up
but branch new refactor-cleanup --anchor refactor-use-utils
but commit refactor-cleanup -m "refactor: remove deprecated code"
```
## Deep Stack (5+ Levels)
For complex features requiring many dependent phases.
```bash
but branch new db-schema
but branch new data-access --anchor db-schema
but branch new business-logic --anchor data-access
but branch new api-endpoints --anchor business-logic
but branch new frontend-integration --anchor api-endpoints
```
**Caution:** Deep stacks increase merge complexity. Prefer 2-3 levels when possible.
@@ -0,0 +1,70 @@
# Stack Reorganization
Advanced techniques for reorganizing GitButler stacks.
## Post-Hoc Stack Organization
**Problem:** Created branches independently, now want to stack them.
**Solution:** Recreate with correct anchors:
```bash
# Current: three independent branches
# feature-a, feature-b, feature-c
# Stack feature-b on feature-a
but branch new feature-b-stacked --anchor feature-a
commit_sha=$(but show feature-b --json | jq -r '.commits[0].id')
but rub $commit_sha feature-b-stacked
but branch delete feature-b --force
# Stack feature-c on feature-b-stacked
but branch new feature-c-stacked --anchor feature-b-stacked
commit_sha=$(but show feature-c --json | jq -r '.commits[0].id')
but rub $commit_sha feature-c-stacked
but branch delete feature-c --force
```
## Squashing Within Stack
Combine commits within the same stack level.
```bash
# Squash all commits in a branch
but squash my-branch
# Or squash specific commits
but squash <newer-commit> <older-commit>
```
## Moving Commits Between Stack Levels
Relocate a commit to the correct branch in the stack.
```bash
# Use commit ID from `but status` or `but show`
but rub <commit-id> correct-branch
```
## Splitting a Branch
Extract part of a branch into a new stack level.
```bash
# Original has multiple features
but branch new second-feature --anchor original-branch
# Use commit ID from `but show original-branch`
but rub <commit-id> second-feature
```
## Recovery
Recreate a branch with correct anchor when the original was created wrong.
```bash
# Recreate branch with correct anchor
but branch new child-stacked --anchor parent
commit_sha=$(but show child --json | jq -r '.commits[0].id')
but rub $commit_sha child-stacked
but branch delete child --force
```
@@ -0,0 +1,250 @@
---
name: gitbutler-virtual-branches
description: This skill should be used when the user asks to "create a virtual branch", "assign file to branch", "work on multiple features simultaneously", "organize commits after coding", "use but commands", or mentions GitButler, virtual branches, parallel development without checkout, post-hoc commit organization, multi-agent concurrent development, or `--gitbutler`/`--but` flags.
metadata:
version: "1.0.0"
author: outfitter
category: version-control
related-skills:
- gitbutler-multi-agent
- gitbutler-stacks
- gitbutler-complete-branch
---
# GitButler Virtual Branches
Virtual branches → parallel development → post-hoc organization.
<when_to_use>
- Multiple unrelated features in same workspace simultaneously
- Multi-agent concurrent development (agents in same repo)
- Exploratory coding where organization comes after writing
- Post-hoc commit reorganization needed
- Visual organization preferred (GUI + CLI)
NOT for: projects using Graphite (incompatible models), simple linear workflows (use plain git)
</when_to_use>
## This, Not That
| Task | This | Not That |
| ---- | ---- | -------- |
| Initialize workspace | `but setup` | manual setup |
| Create branch | `but branch new name` | `git checkout -b name` |
| View changes | `but status` | `git status` |
| Assign file to branch | `but rub <file-id> <branch>` | manual staging |
| Commit to branch | `but commit <branch> -m "msg"` | `git commit -m "msg"` |
| Move commit | `but rub <sha> <branch>` | `git cherry-pick` |
| Squash commits | `but squash <branch>` | `git rebase -i` |
| Undo operation | `but undo` | `git reset` |
| Switch context | Create new branch | `git checkout` |
**Key difference from Git**: All branches visible at once. Organize files to branches after editing. No checkout.
## Core Concepts
| Concept | Description |
|---------|-------------|
| Virtual branches | Multiple branches applied simultaneously to working directory |
| Integration branch | `gitbutler/workspace` tracks virtual branch state — never touch directly |
| Target branch | Base branch (e.g., `origin/main`) all work diverges from |
| File assignment | Assign file hunks to branches with `but rub` |
| Oplog | Operations log for undo/restore — your safety net |
## Quick Start
```bash
# Initialize (one time)
but setup
# Create branch
but branch new feature-auth
# Make changes, check status for file IDs
but status
# ╭┄00 [Unassigned Changes]
# │ m6 A src/auth.ts
# Assign file to branch using ID
but rub m6 feature-auth
# Commit
but commit feature-auth -m "feat: add authentication"
```
## Core Loop
1. **Create**: `but branch new <name>`
2. **Edit**: Make changes in working directory
3. **Check**: `but status` to see file IDs
4. **Assign**: `but rub <file-id> <branch-name>`
5. **Commit**: `but commit <branch> -m "message"`
6. **Repeat**: Continue with other features in parallel
## The Power of `but rub`
Swiss Army knife — combines entities to perform operations:
| Source | Target | Operation |
|--------|--------|-----------|
| File ID | Branch | Assign file to branch |
| File ID | Commit | Amend commit with file |
| Commit SHA | Branch | Move commit between branches |
| Commit SHA | Commit SHA | Squash (newer into older) |
## Essential Commands
| Command | Purpose |
|---------|---------|
| `but setup` | Initialize GitButler in repository |
| `but status` | View changes and file IDs |
| `but branch new <name>` | Create virtual branch |
| `but branch new <name> --anchor <parent>` | Create stacked branch |
| `but rub <source> <target>` | Assign/move/squash/amend |
| `but commit <branch> -m "msg"` | Commit to branch |
| `but commit <branch> -o -m "msg"` | Commit only assigned files |
| `but absorb` | Auto-amend uncommitted changes to appropriate commits |
| `but squash <commits>` | Squash commits (by IDs, range, or branch) |
| `but show <id>` | Inspect a commit or branch in detail |
| `but resolve <commit>` | Enter conflict resolution mode |
| `but push` | Push branches to remote |
| `but pr new` | Create/update PRs on forge |
| `but config forge auth` | Authenticate with GitHub (OAuth) |
| `but mark <branch>` | Auto-assign new changes to branch |
| `but unmark` | Remove all mark rules from workspace |
| `but oplog` | Show operation history |
| `but undo` | Undo last operation |
| `but oplog snapshot --message "msg"` | Create manual snapshot |
| `but pull` | Update workspace with latest base |
| `but gui` | Open GitButler GUI for current repo |
**JSON output**: Use `--json` or `-j` flag on any command: `but status --json`
## Parallel Development
```bash
# Create two independent features
but branch new feature-a
but branch new feature-b
# Edit files for both (same workspace!)
echo "Feature A" > feature-a.ts
echo "Feature B" > feature-b.ts
# Assign to respective branches
but rub <id-a> feature-a
but rub <id-b> feature-b
# Commit independently
but commit feature-a -m "feat: implement feature A"
but commit feature-b -m "feat: implement feature B"
# Both branches exist, zero conflicts, same directory
```
## Conflict Handling
GitButler handles conflicts **per-commit** during rebase/update (unlike Git's all-or-nothing model):
1. Rebase continues even when some commits conflict
2. Conflicted commits marked in UI/status
3. Use `but resolve` to enter resolution mode per commit
4. Partial resolution can be saved for later
```bash
# Update base (may cause conflicts)
but pull
# Check which commits have conflicts
but status
# Enter resolution mode for a specific commit
but resolve <commit-id>
# Fix conflicts in your editor, then check remaining
but resolve status
# Finalize when done (or cancel to abort)
but resolve finish
```
For detailed conflict resolution workflows, see `references/reference.md#conflict-resolution`.
## Auto-Assignment with Marks
Set up workspace rules to auto-assign files to branches:
```bash
# Auto-assign new changes to auth-feature branch
but mark auth-feature
# Remove all rules
but unmark
```
Useful for multi-agent workflows where changes should route to a specific branch.
<rules>
ALWAYS:
- Use `but` for all work within virtual branches
- Use `git` only for integrating completed work into main
- Return to `gitbutler/workspace` after git operations: `git checkout gitbutler/workspace`
- Snapshot before risky operations: `but oplog snapshot --message "..."`
- Assign files immediately after creating: `but rub <id> <branch>`
- Check file IDs with `but status` before using `but rub`
NEVER:
- Use `git commit` on virtual branches — breaks GitButler state
- Use `git add` — GitButler manages index
- Use `git checkout` on virtual branches — no checkout needed
- Push `gitbutler/integration` to remote — it's local-only
- Mix Graphite and GitButler in same repo — incompatible models
- Pipe `but status` directly — causes panic; capture output first:
```bash
status_output=$(but status)
echo "$status_output" | head -5
```
</rules>
## Troubleshooting
| Symptom | Solution |
|---------|----------|
| Files not committing | Assign first: `but rub <file-id> <branch>` |
| Broken pipe panic | Capture output: `output=$(but status)` |
| Mixed git/but broke state | `but pull` or `but setup` |
| Lost work | `but undo` or `but oplog restore <snapshot-id>` |
For detailed troubleshooting (branch tracking, conflicts, filename issues), see `references/reference.md#troubleshooting-guide`.
## Recovery
Quick undo: `but undo` | Full restore: `but oplog restore <snapshot-id>` | View history: `but oplog`
For recovery from lost work or corrupted state, see `references/reference.md#recovery-scenarios`.
<references>
### Reference Files
- **`references/reference.md`** — Complete CLI reference, JSON schemas, troubleshooting
- **`references/examples.md`** — Real-world workflow patterns with commands
- **`references/ai-integration.md`** — Hooks, MCP server, agent lifecycle
### Related Skills
- [gitbutler-multi-agent](../multi-agent/SKILL.md) — Multi-agent coordination
- [gitbutler-stacks](../stacks/SKILL.md) — Stacked branches
- [gitbutler-complete-branch](../complete-branch/SKILL.md) — Merging to main
### External
- [GitButler Docs](https://docs.gitbutler.com/) — Official documentation
- [GitButler AI Integration](https://docs.gitbutler.com/features/ai-integration/) — Hooks and MCP
</references>
@@ -0,0 +1,238 @@
# AI Integration Reference
GitButler provides hooks, MCP server, and GUI features for AI agent integration.
---
## Lifecycle Hooks
GitButler CLI commands that can be called from AI agent lifecycle hooks.
### Claude Code Hooks
Add to `.claude/hooks.json`:
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|MultiEdit|Write",
"hooks": [
{
"type": "command",
"command": "but claude pre-tool"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|MultiEdit|Write",
"hooks": [
{
"type": "command",
"command": "but claude post-tool"
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "but claude stop"
}
]
}
]
}
}
```
**Hook commands:**
| Command | Trigger | Purpose |
|---------|---------|---------|
| `but claude pre-tool` | Before Edit/Write | Prepare workspace, snapshot |
| `but claude post-tool` | After Edit/Write | Auto-assign changes |
| `but claude stop` | Session ends | Finalize commits, cleanup |
### Cursor Hooks
```json
{
"hooks": {
"after-edit": "but cursor after-edit",
"stop": "but cursor stop"
}
}
```
**Hook commands:**
| Command | Purpose |
|---------|---------|
| `but cursor after-edit` | Auto-assign/commit after Cursor edits |
| `but cursor stop` | Finalize when task completes |
---
## MCP Server
Start GitButler's MCP server for programmatic agent access:
```bash
but mcp
```
### Available Tool
**`gitbutler_update_branches`**
Updates commits based on prompt and changes. Designed for async processing:
1. Agent calls after making code changes
2. GitButler records changes + prompt immediately (returns fast)
3. Processing happens asynchronously to create commits
**Input schema:**
```typescript
{
prompt: string // Description of changes made
}
```
**Current limitations:**
- No branch creation via MCP
- No stack management
- No push/submit operations
- No branch navigation
- No restack commands
**Future roadmap (from GitButler docs):**
- Auto-absorbing changes into existing commits
- Creating new branches based on prompt theme
- Creating stacked branches
- More sophisticated commit organization
---
## Agents Tab (GUI)
GitButler GUI provides an Agents Tab for Claude Code integration:
1. **Branch-Agent Binding**: Each virtual branch can be tied to an agent session
2. **Parallel Execution**: Multiple agents run simultaneously, isolated by branch
3. **Automatic Commit Management**: Agent work auto-committed to their branch
4. **Session Persistence**: Agent context preserved across restarts
### Setup
1. Open GitButler GUI for repo: `but gui`
2. Navigate to Agents Tab
3. Create agent sessions tied to virtual branches
4. Configure which branches each agent can modify
---
## Agent Workflow Patterns
### Pattern 1: Hook-Based Auto-Commit
Let GitButler handle commits automatically:
```bash
# Agent instruction
"Never use the git commit command after a task is finished"
```
PostToolUse hook creates commits automatically.
### Pattern 2: Explicit Agent Commits
Agent controls commit timing:
```bash
# Agent creates branch
but branch new agent-feature
# Agent makes changes...
# Agent assigns and commits explicitly
but rub <file-id> agent-feature
but commit agent-feature -m "feat: implementation"
```
### Pattern 3: Multi-Agent with Marks
Set up auto-assignment for agent branches:
```bash
# Agent A's branch receives new changes
but mark agent-a-auth
# Agent B's branch receives new changes
but mark agent-b-api
```
---
## Key Agent Instructions
When configuring agents to work with GitButler:
1. **Never use `git commit`** - Breaks GitButler state
2. **Never use `git add`** - GitButler manages index
3. **Never use `git checkout`** - All branches always applied
4. **Always return to workspace** after any git operations: `git checkout gitbutler/workspace`
5. **Use `but status` to find file IDs** before using `but rub`
---
## Troubleshooting
### Agent commit "orphaned"
**Cause:** Agent used `git commit` instead of `but commit`.
**Solution:**
```bash
git reflog # Find orphaned commit
but branch new recovered-work
# Manually apply changes or cherry-pick
```
### MCP server not responding
**Cause:** Feature may be behind experimental flag.
**Solution:**
1. Check GitButler version (0.16+)
2. Enable experimental features in GUI settings
3. Restart `but mcp`
### Hooks not triggering
**Verify:**
1. Hook file location correct (`.claude/hooks.json`)
2. JSON syntax valid
3. `but` command in PATH
4. GitButler initialized in repo
---
## References
- [GitButler MCP Server Docs](https://docs.gitbutler.com/features/ai-integration/mcp-server)
- [Claude Code Hooks Docs](https://docs.gitbutler.com/features/ai-integration/claude-code-hooks)
- [Cursor Hooks Docs](https://docs.gitbutler.com/features/ai-integration/cursor-hooks)
- [Agents Tab Blog Post](https://blog.gitbutler.com/agents-tab)
@@ -0,0 +1,402 @@
# GitButler Examples
Real-world patterns and workflows for virtual branches, multi-agent collaboration, and post-hoc organization.
---
## Basic Workflows
### First Virtual Branch
```bash
# Initialize (one time)
cd /path/to/repo
but setup
# Check state
but status
# ● 0c60c71 (common base) [origin/main]
# Create branch
but branch new feature-user-auth
# Make changes
echo "export function authenticate()" > src/auth.ts
echo "test('authenticates user')" > src/auth.test.ts
# Check status for file IDs
but status
# ╭┄00 [Unassigned Changes]
# │ m6 A src/auth.ts
# │ p9 A src/auth.test.ts
# Assign and commit
but rub m6 feature-user-auth
but rub p9 feature-user-auth
but commit feature-user-auth -m "feat: add user authentication"
```
### Context Switching (No Checkout!)
```bash
# Working on feature when bug reported
but branch new feature-dashboard
echo "Dashboard code" > dashboard.ts
but rub <id> feature-dashboard
# Bug reported - switch context immediately (no checkout!)
but branch new bugfix-login-timeout
echo "Fix timeout" > login.ts
but rub <id> bugfix-login-timeout
# Both exist in same workspace
but status # Shows both branches
# Commit bugfix first (urgent)
but commit bugfix-login-timeout -m "fix: resolve login timeout"
# Continue feature work
but commit feature-dashboard -m "feat: add dashboard"
```
---
## Reorganizing Work
### Moving Commits Between Branches
```bash
# Oops, committed to wrong branch!
but status
# Shows def5678 "feat: add new feature" on bugfix-branch
# Create correct branch
but branch new feature-new-capability
# Move the commit
but rub def5678 feature-new-capability
# Commit moved!
but status
```
### Squashing Commits
```bash
# Too many small commits on feature-branch
# Squash using explicit command
but squash feature-branch
```
### Post-Hoc File Assignment
```bash
# Made changes without branches
echo "Auth code" > auth.ts
echo "API code" > api.ts
echo "Docs" > README.md
but status
# Shows all files in Unassigned Changes
# Create branches and organize
but branch new feature-auth
but branch new feature-api
but branch new docs-update
# Assign to respective branches
but rub m6 feature-auth
but rub p9 feature-api
but rub i3 docs-update
# Commit each
but commit feature-auth -m "feat: add authentication"
but commit feature-api -m "feat: add API endpoints"
but commit docs-update -m "docs: update readme"
```
---
## Multi-Agent Patterns
### Parallel Feature Development
```bash
# Agent 1 (Claude)
but branch new claude-feature-auth
echo "Auth implementation" > src/auth.ts
but rub <id> claude-feature-auth
but commit claude-feature-auth -m "feat: add authentication"
# Agent 2 (Droid) - simultaneously, same workspace!
but branch new droid-feature-api
echo "API implementation" > src/api.ts
but rub <id> droid-feature-api
but commit droid-feature-api -m "feat: add API endpoints"
# Zero conflicts, zero coordination overhead
```
### Sequential Handoffs
```bash
# Agent A: Initial implementation
but branch new feature-user-management
echo "Initial user code" > user.ts
but rub <id> feature-user-management
but commit feature-user-management -m "feat: initial user management"
# Agent A hands off to Agent B
but branch new feature-user-management-tests --anchor feature-user-management
# Agent B: Adds tests
echo "Tests for user management" > user.test.ts
but rub <id> feature-user-management-tests
but commit feature-user-management-tests -m "test: add user management tests"
```
### Cross-Agent Commit Transfer
```bash
# Agent A finishes work
but branch new agent-a-feature
but commit agent-a-feature -m "feat: implementation complete"
# Agent B creates their branch
but branch new agent-b-continuation
# Transfer commit from A to B
but rub abc1234 agent-b-continuation
# Agent B continues
echo "More work" >> feature.ts
but commit agent-b-continuation -m "feat: continue implementation"
```
---
## Stack Management
### Creating a Linear Stack
```bash
# Base refactoring
but branch new refactor-database
echo "Refactor database layer" > db-refactor.ts
but rub <id> refactor-database
but commit refactor-database -m "refactor: restructure database"
# Build on refactoring
but branch new feature-new-model --anchor refactor-database
echo "New data model" > model.ts
but rub <id> feature-new-model
but commit feature-new-model -m "feat: add new data model"
# Add tests on top
but branch new test-new-model --anchor feature-new-model
echo "Model tests" > model.test.ts
but rub <id> test-new-model
but commit test-new-model -m "test: comprehensive model tests"
# Visualize stack
but status
```
### Submit Stack as PRs
```bash
# Using but CLI (preferred)
but push refactor-database
but pr new refactor-database
but push feature-new-model
but pr new feature-new-model
but push test-new-model
but pr new test-new-model
```
```bash
# Alternative: using git + gh directly
git push origin refactor-database
gh pr create --title "refactor: database layer" --base main
git push origin feature-new-model
gh pr create --title "feat: new data model" --base refactor-database
git push origin test-new-model
gh pr create --title "test: model tests" --base feature-new-model
```
---
## Emergency Recovery
### Recover Deleted Branch
```bash
# Oops, deleted wrong branch
but branch delete important-feature --force
# Check oplog
but oplog
# Undo deletion
but undo
# Verify recovery
but status # Branch recovered!
```
### Recover from Bad Reorganization
```bash
# Snapshot before risky operations
but oplog snapshot --message "Before reorganizing commits"
# Attempt reorganization
but rub <commit1> <branch1>
but rub <commit2> <branch2>
# Result is a mess - restore to snapshot
snapshot_id=$(but oplog | grep "Before reorganizing" | awk '{print $1}')
but oplog restore $snapshot_id
# Back to pre-reorganization state!
```
### Recover from Mixed Git/But Commands
```bash
# Made changes on virtual branch
but branch new my-feature
echo "changes" > file.ts
# Accidentally used git
git add file.ts
git commit -m "oops" # WRONG!
# Recovery
but pull
# If still broken, reinitialize
but oplog snapshot --message "Before recovery"
but setup
```
---
## New in 0.19.0
### Selective Commit with `--changes`
```bash
# Check status for file/hunk IDs
but status
# ╭┄00 [Unassigned Changes]
# │ m6 A src/auth.ts
# │ p9 A src/api.ts
# │ i3 M README.md
# Commit only specific files by ID
but commit feature-auth -p m6,i3 -m "feat: add auth and update docs"
# p9 remains uncommitted
```
### Conflict Resolution with `but resolve`
```bash
# After pulling, a commit has conflicts
but pull
but status
# Shows conflicted commit with ⚠️ marker
# Enter resolution mode
but resolve abc1234
# Fix conflict markers in your editor
# Check what's left
but resolve status
# Finalize
but resolve finish
```
### Squashing with Ranges
```bash
# Squash all commits in a branch
but squash feature-branch
# Squash specific commits
but squash abc1234 def5678
# Squash a range
but squash abc1234..ghi9012
```
### Absorb with Preview
```bash
# Preview where changes would be absorbed
but absorb --dry-run
# Absorb into new commits instead of amending
but absorb --new
```
### Push with Preview
```bash
# See what would be pushed without pushing
but push --dry-run
# Push a specific branch
but push feature-auth
# Push all unpushed branches
but push
```
---
## Tips and Patterns
### Branch Naming
```bash
# Agent-based naming
but branch new claude-feat-user-auth
but branch new droid-fix-api-timeout
# Task-based naming
but branch new feature-authentication
but branch new bugfix-timeout
```
### Snapshot Cadence
```bash
but oplog snapshot --message "Before major reorganization"
but oplog snapshot --message "Before multi-agent coordination"
but oplog snapshot --message "Before complex stack changes"
```
### File Assignment Discipline
```bash
# Good: Assign immediately
echo "code" > file1.ts
but rub <id> my-branch # Right away
```
### JSON Output
```bash
# Get branch commits
but show feature-branch --json | jq '.commits[] | .id'
# Workspace overview
but status --json | jq '.stacks'
```
@@ -0,0 +1,534 @@
# GitButler Reference
Complete CLI reference, JSON schemas, troubleshooting, and recovery patterns.
---
## Command Reference
### Global Options
```bash
but [OPTIONS] <COMMAND>
Global Options (must come BEFORE subcommand):
-C, --current-dir <PATH> Run from specified directory
-j, --json JSON output format
-h, --help Show help
```
**JSON output**: Use `--json` or `-j` per command, or as a global flag:
```bash
but status --json # Per-command flag
but --json status # Global flag (also works)
```
### Inspection Commands
| Command | Description |
|---------|-------------|
| `but status` | View uncommitted changes and file assignments |
| `but status -f` | Show modified files in each commit |
| `but status -v, --verbose` | Show verbose output with commit author and timestamp |
| `but show <id>` | Show detailed info about a commit or branch |
| `but diff` | Show diff of all uncommitted changes |
| `but diff <id>` | Show diff for a specific entity (file, branch, commit) |
| `but oplog` | View operations history (snapshots) |
| `but gui` | Open GitButler GUI for current repo |
**Status Output Example:**
```
╭┄00 [Unassigned Changes]
│ m6 A test-file.md
│ p9 M existing-file.ts
├╯
╭┄g4 [feature-branch]
│ 🔒 i3 M locked-file.ts
● abc1234 feat: initial commit
├╯
● 0c60c71 (common base) [origin/main]
```
**File Status Codes:**
- `A` — Added
- `M` — Modified
- `D` — Deleted
- `🔒` — Locked (belongs to this branch's commits)
**IDs:**
- `00`, `g4` — Branch IDs
- `m6`, `p9`, `i3` — File/hunk IDs (use with `but rub`)
### Branch Management
| Command | Description |
|---------|-------------|
| `but branch new <name>` | Create virtual branch (based on trunk) |
| `but branch new <name> --anchor <parent>` | Create stacked branch |
| `but branch new <name> -a <parent>` | Short form for stacked branch |
| `but branch delete <name>` | Soft delete (requires confirmation) |
| `but branch delete <name> --force` | Force delete |
| `but branch list` | List all branches |
| `but branch list --local` | Only local branches |
| `but unapply <name>` | Remove branch from workspace (keeps in Git) |
| `but apply <name>` | Apply an unapplied branch to workspace |
| `but pick <source> [branch]` | Cherry-pick commit from unapplied branch |
### Committing
| Command | Description |
|---------|-------------|
| `but commit -m "message"` | Commit to inferred branch |
| `but commit <branch> -m "message"` | Commit to specific branch |
| `but commit <branch> -o -m "msg"` | Only commit assigned files (`-o` flag) |
| `but commit -p <id>,<id>` | Commit specific files/hunks by CLI ID |
| `but commit --ai` | Generate commit message with AI |
| `but commit -c` | Create new branch for this commit |
| `but commit` | Opens `$EDITOR` for message |
| `but commit empty --before <target>` | Insert blank commit before target |
| `but commit empty --after <target>` | Insert blank commit after target |
**Note:** Unlike git, GitButler commits all changes by default. Use `-o/--only` to commit only assigned files, or `-p/--changes` to select specific file/hunk IDs.
### File and Commit Manipulation
#### `but rub` (Swiss Army Knife)
```bash
but rub <source> <target>
```
| Source | Target | Operation | Description |
|--------|--------|-----------|-------------|
| File ID | Branch ID | **Assign** | Move file to branch |
| File ID | Commit SHA | **Amend** | Add file changes to commit |
| Commit SHA | Branch ID | **Move** | Relocate commit to branch |
| Commit SHA | Commit SHA | **Squash** | Combine newer into older |
#### Other Editing Commands
| Command | Description |
|---------|-------------|
| `but commit empty --before/--after <target>` | Insert blank commit before or after target |
| `but reword` | Edit commit message or rename branch |
| `but absorb` | Auto-amend uncommitted changes to appropriate commits based on context |
| `but absorb --dry-run` | Preview what absorb would do without changing anything |
| `but absorb --new` | Create new commits instead of amending existing ones |
| `but squash <commits>` | Squash commits together (by IDs, range, or branch name) |
| `but move <commit> <target>` | Move commit to a different location in the stack |
| `but amend <file> <commit>` | Amend a file change into a specific commit |
| `but uncommit <source>` | Uncommit changes back to unstaged area |
| `but discard <id>` | Discard uncommitted changes from worktree |
| `but mark <branch>` | Auto-assign new changes to branch |
| `but unmark` | Remove all mark rules from workspace |
**`but absorb`**: Analyzes uncommitted changes and automatically amends them to the appropriate existing commits based on file context and change location. Similar to `git absorb` but integrated with virtual branches.
### Forge Integration (GitHub)
| Command | Description |
|---------|-------------|
| `but config forge auth` | Authenticate with GitHub via OAuth flow |
| `but config forge list-users` | List authenticated accounts |
| `but config forge forget <username>` | Remove authenticated account |
| `but push [branch]` | Push branch to remote |
| `but push -d, --dry-run` | Preview what would be pushed |
| `but push -f, --with-force` | Force push |
| `but push -r, --run-hooks` | Execute pre-push hooks |
| `but pr new [branch]` | Create PR for branch on forge |
**Push + PR workflow:**
1. Push branch to remote: `but push feature-auth`
2. Create PR: `but pr new feature-auth`
3. Or push all unpushed branches: `but push` (non-interactive)
4. Requires prior `but config forge auth` for first-time setup
### Base Branch Operations
| Command | Description |
|---------|-------------|
| `but pull --check` | Fetch remotes and check mergeability |
| `but pull` | Update workspace with latest from base |
### Operations History (Undo/Restore)
| Command | Description |
|---------|-------------|
| `but oplog` | View operation history |
| `but undo` | Undo last operation |
| `but oplog restore <snapshot-id>` | Restore to specific snapshot |
| `but oplog snapshot --message "msg"` | Create manual snapshot |
### Conflict Resolution
| Command | Description |
|---------|-------------|
| `but resolve <commit-id>` | Enter resolution mode for a conflicted commit |
| `but resolve status` | Show remaining conflicted files |
| `but resolve finish` | Finalize resolution and return to workspace |
| `but resolve cancel` | Cancel resolution and return to workspace |
**Workflow:**
1. `but status` shows conflicted commits
2. `but resolve <commit-id>` to enter resolution mode
3. Fix conflict markers in your editor
4. `but resolve status` to check remaining conflicts
5. `but resolve finish` to finalize
### Workspace Lifecycle
| Command | Description |
|---------|-------------|
| `but setup` | Initialize GitButler project from existing Git repo |
| `but setup --init` | Initialize new Git repo and set up GitButler |
| `but teardown` | Exit GitButler mode, return to normal Git |
**`but teardown`**: Creates an oplog snapshot, checks out the first active branch as a regular Git branch, and provides instructions for returning to GitButler mode.
### Configuration
| Command | Description |
|---------|-------------|
| `but config` | Show configuration overview |
| `but config user` | View user configuration |
| `but config user set name "Name"` | Set user name |
| `but config user set email "email"` | Set user email |
| `but config forge` | View forge configuration |
| `but config forge auth` | Authenticate with forge (GitHub OAuth) |
| `but config forge list-users` | List authenticated accounts |
| `but config forge forget <user>` | Remove authenticated account |
### AI Integration Commands
**Claude Code Hooks:**
| Command | Purpose |
|---------|---------|
| `but claude pre-tool` | Run before code generation/editing |
| `but claude post-tool` | Run after editing completes |
| `but claude stop` | Run when agent session ends |
**Cursor Hooks:**
| Command | Purpose |
|---------|---------|
| `but cursor after-edit` | Triggered when Cursor edits files |
| `but cursor stop` | Triggered when task completes |
**MCP Server:**
| Command | Purpose |
|---------|---------|
| `but mcp` | Start MCP server for agent integration |
---
## JSON Output Schemas
### `but status --json`
Key fields:
- `path` — Filename as ASCII array (requires decoding)
- `assignments` — Hunk-level file assignments
- `stackId` — Which stack this belongs to (null if unassigned)
**Limitations:**
- File IDs (`m6`, `g4`) not exposed in JSON
- Paths are ASCII arrays, not strings
- Parse text output for IDs
### `but show <branch> --json`
Shows detailed branch info with commits. Key fields:
- `commits` — Array of commits on the branch
- `commits[].id` — Commit SHA
### `but diff --json`
Shows diffs in JSON format for programmatic analysis.
**Useful jq patterns:**
```bash
# Get branch commits
but show feature-branch --json | jq '.commits[] | .id'
# Workspace overview
but status --json | jq '.stacks'
```
---
## GitButler vs Graphite
| Aspect | Graphite | GitButler |
|--------|----------|-----------|
| **Model** | Linear stacks of physical branches | Virtual branches with optional stacking |
| **Workflow** | Plan → Branch → Code → Commit → Stack | Code → Organize → Assign → Commit |
| **Branch Switching** | Required (`gt up`/`gt down`) | Never needed (all applied) |
| **Branch Creation** | `gt create -am "msg"` | `but branch new name [--anchor parent]` |
| **Committing** | `gt modify -cam "msg"` | `but commit -m "msg"` |
| **Stack Navigation** | ✓ `gt up`/`gt down` | ✗ No CLI equivalent (all applied) |
| **PR Submission** | ✓ `gt submit --stack` | ✓ `but push` + `but pr new` |
| **JSON Output** | Limited | ✓ Comprehensive via `--json` per command |
| **Multi-Feature Work** | Switch branches | All in one workspace |
| **CLI Completeness** | ✓ Full automation | ✓ Full automation (as of 0.19.0) |
| **Conflict Resolution** | Standard git rebase | ✓ Per-commit via `but resolve` |
**Choose Graphite when:**
- Stack navigation commands needed (`gt up`/`gt down`)
- Terminal-first linear workflow
- Established stacked PR practices
**Choose GitButler when:**
- Multiple unrelated features simultaneously
- Multi-agent concurrent development
- Exploratory coding (organize after)
- Post-hoc commit reorganization
- Per-commit conflict resolution needed
- Visual organization preferred (GUI + CLI)
**Don't use both in same repo** — incompatible models.
---
## Troubleshooting Guide
### Quick Reference
| Symptom | Cause | Solution |
|---------|-------|----------|
| Broken pipe panic | Output piped directly | Capture to variable first |
| Filename with dash fails | Interpreted as range | Use file ID from `but status` |
| Branch not visible | Not applied | `but apply <branch>` or `but pick <commit>` |
| Files not committing | Not assigned | `but rub <file-id> <branch>` |
| Mixed git/but broke state | Used git commands | `but pull` or `but setup` |
| Workspace stuck loading | Backend timeout | Check oplog, restore snapshot |
| "Workspace commit not found" | HEAD changed externally | `git checkout gitbutler/workspace` |
### Common Issues
#### Broken Pipe Panic
**Problem:** `but status` panics when output consumed partially.
```bash
✗ but status | head -5 # Panic!
status_output=$(but status)
echo "$status_output" | head -5
```
#### Filename Parsing Issues
**Problem:** Dashes in filenames interpreted as range syntax.
```bash
✗ but rub file-with-dashes.md branch # Fails
✓ but rub m6 branch # Use file ID from but status
```
#### Integration Branch Conflicts
**Problem:** Mixed `git` and `but` commands corrupted state.
**Solutions:**
1. `but pull` to resync
2. If severely broken: `but setup` to reinitialize
#### Files Not Committing
**Causes:**
1. Files not assigned to branch
2. Missing `-o` flag (only commit assigned files)
```bash
# Check assignments
but status
# Assign files
but rub <file-id> <branch>
# Commit with -o flag
but commit <branch> -o -m "message"
```
#### Workspace Stuck Loading
**Symptoms:**
- Loading spinner indefinitely
- Can see trunk/remote branches but not workspace
**Recovery:**
1. Wait 60 seconds for timeout
2. Check logs: `~/Library/Logs/com.gitbutler.app/GitButler.log` (macOS)
3. Use Operations History to restore previous snapshot
4. Last resort: Remove and re-add project
#### "GitButler workspace commit not found"
**Cause:** `gitbutler/workspace` branch modified or deleted outside GitButler.
**Recovery:**
```bash
# Return to integration branch
git checkout gitbutler/integration
# If that fails, check oplog
cat .git/gitbutler/operations-log.toml
git log <head_sha>
# Remove and re-add project to GitButler
```
### Recovery Scenarios
#### Lost Work (Accidentally Deleted Branch)
```bash
# Check oplog for deletion
but oplog
# Undo deletion (if last operation)
but undo
# Or restore to snapshot before deletion
but oplog restore <snapshot-id>
```
#### Corrupted Workspace State
```bash
# Step 1: Snapshot current state
but oplog snapshot --message "Before recovery"
# Step 2: Update base
but pull
# Step 3: Last resort - reinitialize
but setup
```
#### Recovering from Mixed Git/But Commands
**If you committed with `git commit`:**
```bash
# Work is still in working directory
# Find orphaned commit
git reflog
# Create branch from it
git branch recovered <commit-sha>
# Return to GitButler
git checkout gitbutler/integration
```
**If you checked out another branch:**
```bash
# Return to GitButler
git checkout gitbutler/integration
# GitButler will resume operation
```
#### Virtual Branches Disappeared
Virtual branches are Git refs — they're still there:
```bash
# List all virtual branch refs
git for-each-ref refs/gitbutler/
# Create regular branch from virtual branch
git branch recovered-feature refs/gitbutler/Feature-A
# Or push directly to remote
git push origin refs/gitbutler/Feature-A:refs/heads/feature-a
```
#### Extract Data from Corrupted Project
```bash
# Backup everything
cp -r .git .git-backup
# Extract all virtual branch refs
git for-each-ref refs/gitbutler/ > gitbutler-refs.txt
# Create regular branch from each
while read sha type ref; do
name=$(basename "$ref")
git branch "recovered-$name" "$sha"
done < gitbutler-refs.txt
# Extract latest oplog snapshot
LATEST=$(cat .git/gitbutler/operations-log.toml | grep head_sha | awk '{print $3}' | tr -d '"')
git archive $LATEST index/ | tar -x -C recovered-uncommitted/
```
### Operations Log (Oplog) Deep Dive
**Location:** `.git/gitbutler/operations-log.toml`
**Snapshot contents:**
```
<snapshot-commit>
├── virtual_branches.toml # Branch metadata
├── virtual_branches/ # Branch content trees
├── index/ # Working directory state
├── target_tree/ # Base branch (e.g., main)
└── conflicts/ # Merge conflict info
```
**Operation types:**
- `CreateCommit` — Made a commit
- `CreateBranch` — Created branch
- `UpdateWorkspaceBase` — Updated base branch
- `RestoreFromSnapshot` — Reverted to snapshot
- `FileChanges` — Uncommitted changes detected
- `DeleteBranch` — Deleted branch
- `SquashCommit` — Squashed commits
**Manual inspection:**
```bash
# Find oplog head
OPLOG_HEAD=$(cat .git/gitbutler/operations-log.toml | grep head_sha | awk '{print $3}' | tr -d '"')
# View snapshot history
git log $OPLOG_HEAD --oneline
# Show virtual branches config from snapshot
git show <snapshot-sha>:virtual_branches.toml
# Extract file from snapshot
git show <snapshot-sha>:index/path/to/file.txt
```
### Prevention Best Practices
**Golden Rules:**
1. **NEVER remove project to fix errors** — may delete actual source files
2. **Commit frequently** — committed work is safer than WIP
3. **Push virtual branches to remote** — backup your work
4. **Don't mix GitButler and stock Git commands** — choose one workflow
**Before risky operations:**
```bash
but oplog snapshot --message "Before major reorganization"
```
**Before GitButler updates:**
1. Commit everything
2. Push all branches to remote
3. Verify Operations History accessible