references/examples.md
3,701 tokens · o200k_base · 13,985 bytes
Source excerpt starting at line 1.# GitButler CLI Workflow Examples Real-world examples of common workflows. **Note on CLI IDs:** Examples use illustrative IDs such as `nn` and `a1`; copy actual IDs from current `but status` or `but diff` output. Real output may use longer IDs (e.g., `mzm:uvw:2e4`). Use full branch names for mutations. Commit change-ID prefixes survive history edits; SHA prefixes can go stale. ## Example 1: Starting Independent Parallel Work **Scenario:** Need to work on two independent features: a new API endpoint and UI styling updates. ```bash# 1. Check current statebut status -fv # 2. Create two independent (parallel) branchesbut branch new api-endpointbut branch new ui-styling # 3. Make changes to multiple files# (edit api/users.js and components/Button.svelte) # 4. Check what's uncommittedbut status -fv # 5. Commit specific files by passing their CLI IDs (recommended for agents)# Use full branch names plus file IDs from but status -fv output# Multiple IDs are space-separated positional arguments.but commit -b api-endpoint -m "Add user details endpoint" <api-file-id>but commit -b ui-styling -m "Update button hover styles" <ui-file-id> # Follow-up fix that belongs in a commit you just made? Amend it in.# Add --status-after only when the next step needs resulting workspace IDs or details.# but amend -t <api-commit-id> <api-fix-file-id> <api-fix-hunk-id> # 6. Create pull requests (auto-pushes the branches; -m sets the PR title so no editor opens)but pr new api-endpoint -m "Add user details endpoint"but pr new ui-styling -m "Update button hover styles"``` **Why parallel branches?** The API endpoint and UI styling are independent - neither depends on the other. They can be reviewed and merged separately. ## Example 2: Building Stacked Features **Scenario:** Need to add authentication, then build a user profile page that requires auth. ```bash# 1. Check current state and updatebut pullbut status -fv # 2. Create base branch for authenticationbut branch new add-authentication # 3. Implement auth and commit# (edit auth/login.js, auth/middleware.js)but status -fvbut commit -b add-authentication -m "Add JWT authentication" <file-ids> # 4. Create stacked branch anchored on authenticationbut branch new user-profile --above add-authentication # 5. Implement profile page (depends on auth)# (edit pages/profile.js)but status -fvbut commit -b user-profile -m "Add user profile page" <file-ids> # 6. Create stacked pull requests from the top branch once (auto-pushes its ancestors)but pr new user-profile -t``` **Result:** Two PRs where user-profile targets add-authentication, with GitButler stack information in the PR descriptions. ## Example 3: Amending Fixes Into Existing Commits **Scenario:** Made a small typo fix that should be part of an existing commit, not a new commit. ```bash# 1. Check current commits and uncommitted changesbut status -fv # Output shows:# Branch: feature-x (bu)# Commits:# nn: Implement feature logic# mm: Add feature tests# Uncommitted:# a1: fix-typo.js # 2. Decide which commit the fix belongs to# (the typo is in code introduced by nn, so it belongs in nn) # 3. Amend the file into that commitbut amend -t nn a1 # Amend just this file + get updated status``` **Why amend?** Keeps history clean. Small fixes belong in the commits they fix, not as separate "fix typo" commits. You know what you changed and why — pick the target commit yourself. ## Example 4: Reorganizing Commit History ### Scenario A: Squashing Commits **Situation:** Made 5 small WIP commits, want to combine into one logical commit. ```bash# Before (newest first):# rr: More tweaks# pp: Fix another thing# nn: Fix tests# mm: Adjust logic# kk: Initial implementation # Squash all commits in the branch into onebut squash feature -m "Implement feature" # Or squash specific commits into a target commitbut squash rr pp nn mm -t kk -m "Implement feature"``` ### Scenario B: Moving Committed Changes **Situation:** A change was committed in the wrong commit, need to move it. ```bash# 1. See which files are in which commitsbut status -fv # Output shows:# nn: Add API layer# nn:a1 api.js# nn:a2 utils.js# mm: Add config# mm:c1 config.js # 2. Move utils.js from nn to mmbut squash nn:a2 -t mm -u # Committed file nn:a2 (utils.js) → commit mm, keep mm's message # Alternatively, move only one hunk from the filebut diff nn # Read the committed hunk IDbut squash nn:a2:5 -t mm # Target message is reused # Or put that committed hunk in a new commit at a chosen positionbut move nn:a2:5 --above mm # Or move that committed hunk back to uncommittedbut squash nn:a2:5 -t @``` ### Scenario C: Moving Commit to Different Branch **Situation:** Committed to wrong branch, need to move commit. ```bash# 1. Check current statebut status -fv # Output:# Branch: feature-a (bu)# nn: This should be in feature-b!# mm: Correct commit # 2. Create or identify target branchbut branch new feature-b # Creates branch bv # 3. Move the commitbut move nn -b feature-b # Move nn to top of feature-b``` ## Example 5: Stacking Existing Branches **Scenario:** Two independent branches exist, but one now depends on the other. Stack them. ```bash# 1. Check current state — two independent branches in separate stacksbut status -fv # Output:# Stack 1: feature/backend (bu) — 2 commits# Stack 2: feature/frontend (bv) — 1 commit # 2. Frontend now depends on backend API — stack frontend on backend# IMPORTANT: Use full branch names; short IDs belong to the previous snapshotbut move feature/frontend --above feature/backend # Result: Both branches are now in the same stack:# Stack 1: feature/backend → feature/frontend (stacked) # 3. Continue working — commits go to the right branchbut status -fvbut commit -b feature/backend -m "Add caching layer" <id>but commit -b feature/frontend -m "Add dialog component" <id>``` **Key point:** branch stack moves use full branch names like `feature/frontend`. Commit reordering still uses commit IDs. ## Example 6: Conflict Resolution **Scenario:** After `but pull`, conflicts appear in a commit. ```bash# 1. Pull updatesbut pull # Output:# Summary# ────────# feature-x - conflicted# nn Add validation # 2. Enter resolution mode using the commit ID from the pull outputbut resolve nn # Output:# Checking out conflicted commit nn# Conflicted files remaining:# ✗ api/users.js# 12│<<<<<<< New base: ...# ...conflict regions with line numbers... # 3. Edit each conflicted file to resolve# IMPORTANT: You MUST edit the files — do NOT just run `but resolve finish`# NEVER use `git add`, `git checkout --theirs/--ours`, or any git write command — just edit the files directly with the Edit tool, then `but resolve finish`# (edit to remove every marker — <<<<<<< ||||||| ======= >>>>>>> — and keep correct content;# with several conflicted files, `but resolve status` re-lists what remains) # 4. Finalizebut resolve finish # Output:# ✓ Conflict resolution finalized successfully!# No conflict markers remain in the resolved files.# Workspace restored; uncommitted changes intact: ...# No follow-up status or marker scan needed — finish already reports both.``` ## Example 7: Complete Feature Development Workflow **Scenario:** Building a complete feature from start to finish. ```bash# 1. Update to latestbut pull # 2. Create branch for featurebut branch new user-dashboard # 3. Make initial changes# (create dashboard.js, add routes) # 4. Check status and gather file IDsbut status -fv # 5. First commitbut commit -b user-dashboard -m "Add dashboard route and basic layout" <file-ids> # 6. Continue iterating# (add widgets, styling)but commit -b user-dashboard -m "Add dashboard widgets" <file-ids>but commit -b user-dashboard -m "Style dashboard components" <file-ids> # 7. Make small fix# (fix typo in widget)but amend -t <commit-id> a1 # Amend fix into the commit it belongs to # 8. Clean up if neededbut squash user-dashboard -m "Add user dashboard" # Combine all commits (optional) # 9. Create pull request (auto-pushes the branch)but pr new user-dashboard -m "Add user dashboard" # Output:# Created PR #123: https://github.com/org/repo/pull/123 # 10. After PR is merged, updatebut pull``` ## Example 8: Working with Applied/Unapplied Branches **Scenario:** Have 3 branches, but two are causing conflicts. Temporarily unapply them. ```bash# 1. Check active branchesbut status -fv # Output:# Applied branches:# bu: feature-a# bv: feature-b# bw: feature-c # 2. Conflicts between feature-b and feature-c# Unapply them temporarilybut unapply feature-bbut unapply feature-c # 3. Focus on feature-a# (make changes, commit)but commit -b feature-a -m "Complete feature-a" <file-ids> # 4. Create PR for feature-a (auto-pushes)but pr new feature-a -m "Complete feature-a" # 5. Reapply other branchesbut apply feature-bbut apply feature-c # 6. Deal with their conflicts nowbut resolve ...``` ## Example 9: Fixing History Before Pushing **Scenario:** Made several commits, realized you need to reword messages and reorder. ```bash# 1. Current statebut status -fv # Output (newest first):# Branch: feature-x (bu)# rr: final commit# pp: WIP# nn: Fix stuff# mm: Another fix# kk: Initial # 2. Reword commit messages — commit refs are change-ID based and stay# valid across rewords and other history editsbut reword pp -m "Add validation logic"but reword nn -m "Fix edge case in parser"but reword mm -m "Update error messages" # 3. Move rr to be earlierbut move rr --below nn # Place rr directly below nn # 4. Squash similar commitsbut squash mm -t nn -u # Combine error handling commits; -u keeps nn's message, drops mm's # Output (newest first):# Branch: feature-x (bu)# pp: Add validation logic# nn: Fix edge case in parser# rr: final commit# kk: Initial # 5. Push clean historybut push feature-x``` ## Example 10: Daily Development Workflow **Typical day working with GitButler:** ```bash# Morning: Start daybut pull # Get latest from team # Start new taskbut branch new fix-auth-bug # Create branch for today's work # Work and commit iteratively# (make changes)but status -fv # Check changesbut commit -b fix-auth-bug -m "Identify auth bug source" <file-ids># (make more changes)but commit -b fix-auth-bug -m "Fix token expiration handling" <file-ids># (small fix to existing code)but amend -t <commit-id> a1 # Amend fix into the commit it belongs to # Mid-day: Start urgent fix on different branchbut branch new hotfix-login # Parallel branch for urgent work# (make fix)but commit -b hotfix-login -m "Fix login redirect loop" <file-ids>but pr new hotfix-login -m "Fix login redirect loop" # Push and create PR immediately # Back to original work# (continue working on fix-auth-bug)but commit -b fix-auth-bug -m "Add tests for token handling" <file-ids> # End of day: Clean up and create PRbut squash fix-auth-bug -m "Fix auth bug" # Combine into clean historybut pr new fix-auth-bug -m "Fix auth bug" # Push and create PR # After PR review: Make requested changes# (make changes based on feedback)but amend -t <commit-id> <file-id> # Amend each fix into the commit it belongs tobut push fix-auth-bug # Push updated history``` ## Example 11: Recovering from Mistakes **Scenario:** Made changes you didn't mean to, need to undo. ### Undo Last Operation ```bash# Made a mistakebut squash feature -m "..." # Oops! Didn't mean to squash # Undo itbut undo # Reverts the squash``` ### Restore to Earlier Point ```bash# View operation historybut oplog # Output (snapshot refs are git SHAs, not CLI IDs):# 9c1f2ab 2026-01-02 [SQUASH] Squashed commits# f8a3733 2026-01-02 [COMMIT] Created commit# 4b70e19 2026-01-02 [AMEND] Amended commit# 1d5c806 2026-01-02 [BRANCH] Created branch # Restore to before the squash, using the SHA from the outputbut oplog restore f8a3733``` ### Discard Uncommitted Changes ```bash# Changed a file but want to discardbut status -fv # Output:# Uncommitted:# a1: bad-changes.js # Discard itbut discard a1``` ## Tips and Tricks ### Quick Status Check ```bashbut status -fv # File-centric view for quick overview``` ### Preview Before Doing ```bashbut push my-feature --dry-run # See what would be pushed``` ### Multiple Commits From One Diff File/hunk IDs copied from the original output generally remain usable acrosscommits. Chain `but commit` calls to split a dirty diff into several commits inone go: ```bashbut diff # read the file/hunk IDs once but commit -b my-branch -m "Add parser" qs:5 qs:2 \ && but commit -b my-branch -m "Add tests" uo:d``` The commits stack in the order you write them, so `Add parser` ends up below (olderthan) `Add tests`. Chain these commit commands when each references uncommitted IDsand a full branch name. If an ID stops resolving, re-read the diff and continue.Mutation output is concise by default. Add `--status-after` only when the nextstep needs workspace IDs or details that the mutation result does not provide.History edits — `amend`, `squash`, `move`, `uncommit`, `reword` — may also run insequence off one status read when every commit ref involved is a change-ID ref;those stay stable across the edits. Run them one at a time when a ref is sha-basedor `#N`-suffixed, or when the next command needs freshly issued IDs, and add`--status-after` to get them. ### Auto-completion ```basheval "$(but completions zsh)" # Add to ~/.zshrceval "$(but completions bash)" # Add to ~/.bashrc``` ### Viewing History ```bashbut show bu # Show all commits in branchgit log bu # Traditional git log (read-only, still works)```