but▌
gitbutlerapp/gitbutler · updated Apr 8, 2026
Use GitButler CLI (but) as the default version-control interface.
GitButler CLI Skill
Use GitButler CLI (but) as the default version-control interface.
Non-Negotiable Rules
- Use
butfor all write operations. Never rungit add,git commit,git push,git checkout,git merge,git rebase,git stash, orgit cherry-pick. If the user says agitwrite command, translate it tobutand run that. - Always add
--status-afterto mutation commands. - Use CLI IDs from
but status -fv/but diff/but show; never hardcode IDs. - Start with
but status -fvbefore mutations so IDs and stack state are current. - Create a branch for new work with
but branch new <name>when needed.
Core Flow
Every write task should follow this sequence.
# 1. Inspect state and gather IDs
but status -fv
# 2. If new branch needed:
but branch new <name>
# 3. Edit files (Edit/Write tools)
# 4. Refresh IDs if needed
but status -fv
# 5. Perform mutation with IDs from status/diff/show
but <mutation> ... --status-after
Command Patterns
- Commit:
but commit <branch> -m "<msg>" --changes <id>,<id> --status-after - Commit + create branch:
but commit <branch> -c -m "<msg>" --changes <id> --status-after - Amend:
but amend <file-id> <commit-id> --status-after - Reorder commits:
but move <source-commit-id> <target-commit-id> --status-after(commit IDs, not branch names) - Stack branches:
but move <branch-name-or-id> <target-branch-name-or-id> --status-after(branch names or branch CLI IDs) - Tear off a branch:
but move <branch-name-or-id> zz --status-after(zz= unassigned; branch name or branch CLI ID) - Equivalent branch subcommand syntax remains available:
but branch move <branch-name> <target-branch-name>andbut branch move --unstack <branch-name> - Push:
but pushorbut push <branch-id> - Pull:
but pull --checkthenbut pull --status-after
Task Recipes
Commit files
but status -fv- Find the CLI ID for each file you want to commit.
but commit <branch> -m "<msg>" --changes <id1>,<id2> --status-afterUse-cto create the branch if it doesn't exist. Omit IDs you don't want committed.- Check the
--status-afteroutput for remaining uncommitted changes. If the file still appears as unassigned or assigned to another branch after commit, it may be dependency-locked. See "Stacked dependency / commit-lock recovery" below.
Amend into existing commit
but status -fv(orbut show <branch-id>)- Locate file ID and target commit ID.
but amend <file-id> <commit-id> --status-after
Reorder commits
but move supports both commit reordering and branch stack operations. Use commit IDs when reordering commits.
but status -fvbut move <commit-a> <commit-b> --status-after— uses commit IDs likec3,c5- Refresh IDs from the returned status, then run the inverse:
but move <commit-b> <commit-a> --status-after
Stack existing branches
To make one existing branch depend on (stack on top of) another, use top-level move:
but move feature/frontend feature/backend
This moves the frontend branch on top of the backend branch in one step.
Equivalent subcommand syntax:
but branch move feature/frontend feature/backend
DO NOT use uncommit + branch delete + branch new -a to stack existing branches. That approach fails because git branch names persist even after but branch delete. Always use but move <branch> <target-branch> (or the equivalent but branch move ...).
To unstack (make a stacked branch independent again):
but move feature/logging zz
Equivalent subcommand syntax:
but branch move --unstack feature/logging
Note: branch stack/tear-off operations use branch names (like feature/frontend) or branch CLI IDs, while commit reordering uses commit IDs (like c3). Do NOT use but undo to unstack — it may revert more than intended and lose commits.
Stacked dependency / commit-lock recovery
A dependency lock occurs when a file was originally committed on branch A, but you're trying to commit changes to it on branch B. Symptoms:
but commitsucceeds but the file still appears inunassignedChangesin the--status-afteroutput- The file shows as "unassigned" instead of being staged to any branch
Recovery: Stack your branch on the dependency branch, then commit:
but status -fv— identify which branch originally owns the file (check commit history).but move <your-branch-name> <dependency-branch-name>— stack your branch on the dependency. Uses full branch names, not CLI IDs.but status -fv— the file should now be assignable. Commit it.but commit <branch> -m "<msg>" --changes <id> --status-after
If but move <branch> <target-branch> fails: Do NOT try uncommit, squash, or undo to work around it — these will leave the workspace in a worse state. Instead, re-run but status -fv to confirm both branches still exist and are applied, then retry with exact branch names from the status output.
Resolve conflicts after reorder/move
NEVER use git add, git commit, git checkout --theirs, git checkout --ours, or any git write commands during resolution. Only use but resolve commands and edit files directly with the Edit tool.
If but move causes conflicts (conflicted commits in status):
but status -fv— find commits marked as conflicted.but resolve <commit-id>— enter resolution mode. This puts conflict markers in the files.- Read the conflicted files to see the
<<<<<<</=======/>>>>>>>markers. - Edit the files to resolve conflicts by choosing the correct content and removing markers.
but resolve finish— finalize. Do NOT run this without editing the files first.- Repeat for any remaining conflicted commits.
Common mistakes: Do NOT use but amend on conflicted commits (it won't work). Do NOT skip step 4 — you must actually edit the files to remove conflict markers before finishing.
Git-to-But Map
| git | but |
|---|---|
git status |
but status -fv |
git add + git commit |
but commit ... --changes ... |
git checkout -b |
but branch new <name> |
git push |
but push |
git rebase -i |
but move, but squash, but reword |
git rebase --onto |
but branch move <branch> <new-base> |
git cherry-pick |
but pick |
Notes
- Prefer explicit IDs over file paths for mutations.
--changesaccepts comma-separated values (--changes a1,b2) or repeated flags (--changes a1 --changes b2), not space-separated.- Read-only git inspection (
git log,git blame,git show --stat) is allowed. - After a successful
--status-after, don't run a redundantbut status -fvunless you need new IDs. - Use
but show <branch-id>to see commit details for a branch, including per-commit file changes and line counts. - Per-commit file counts:
but statusdoes NOT include per-commit file counts. Usebut show <branch-id>orgit show --stat <commit-hash>to get them. - Avoid
--helpprobes; use this skill andreferences/reference.mdfirst. Only use--helpafter a failed attempt. - Run
but skill checkonly when command behavior diverges from this skill, not as routine preflight. - For command syntax and flags:
references/reference.md - For workspace model:
references/concepts.md - For workflow examples:
references/examples.md