| name | but |
| version | 0.19.9 |
| description | Commit, push, branch, and manage version control with GitButler. Use for: commit my changes, check what changed, create a PR, push my branch, view diff, create branches, stage files, edit commit history, squash commits, amend commits, undo commits, pull requests, merge, stash work. Replaces git - use 'but' instead of git commit, git status, git push, git checkout, git add, git diff, git branch, git rebase, git stash, git merge. Covers all git, version control, and source control operations. |
| author | GitButler Team |
GitButler CLI Skill
Use GitButler CLI (but) as the default version-control interface.
Non-Negotiable Rules
- Use
but for all write operations. Never run git add, git commit, git push, git checkout, git merge, git rebase, git stash, or git cherry-pick. If the user says a git write command, translate it to but and run that.
- Always add
--status-after to mutation commands.
- Use CLI IDs from
but status -fv / but diff / but show; never hardcode IDs.
- Start with
but status -fv before mutations so IDs and stack state are current.
- Create a branch for new work with
but branch new <name> when needed.
- For history optimization, do not rebuild state with
git diff + git apply. Use GitButler primitives (but rub, but squash, but move, but reword, but uncommit) to reshape commits and branches. If you think native git is required, stop and explain the exact GitButler limitation before doing it.
- There is no production-pressure excuse for bypassing GitButler. If the right command is unfamiliar, explore the local skill/reference or
but --help after checking the reference, then use the GitButler-native operation.
Core Flow
Every write task should follow this sequence.
but status -fv --json
but branch new <name>
but status -fv --json
but <mutation> ... --status-after
Command Patterns
Add --json when consuming GitButler output programmatically. It is easier to parse than compact TUI-style text and avoids brittle scraping. Human-readable output is still fine when showing state directly to a person.
-
Status: but status -fv --json
-
Diff: but diff --json or but diff <change-id> --json
-
Branch detail: but show <branch-id> --json or but branch show <branch-name> -f --json
-
Pull check: but pull --check --json
-
Branch list: but branch list --json
-
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)
-
Move a commit to another branch: but move <source-commit-id> <target-branch-name> --status-after or but move <source-commit-id> <target-branch-id> --status-after. The target branch must be applied/visible in but status -fv; if it is currently listed under unapplied branches, run but apply <target-branch-name> --status-after first, then move the commit.
-
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> and but branch move --unstack <branch-name>
-
Push: but push or but push <branch-id>
-
Pull: but pull --check --json then but pull --status-after --json
-
Operation log / recovery: but oplog to inspect recent GitButler workspace operations before undo/recovery decisions.
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-after
Use -c to create the branch if it doesn't exist. Omit IDs you don't want committed.
- Check the
--status-after output 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 (or but show <branch-id>)
- Locate file ID and target commit ID.
but amend <file-id> <commit-id> --status-after
Optimize a messy branch before PR
Use GitButler as the commit-composition tool. Do not export a patch and apply it to a new branch unless GitButler cannot represent the operation and you have said why.
- Inspect the stack with
but status -fv and but show <branch-id> / but branch show <branch-name> -f.
- Decide the target atomic commits: which files/hunks belong together and in what order.
- Use
but rub for moving material:
but rub <file-id> <commit-id> --status-after — amend a file/hunk into the right commit.
but rub <file-in-commit-id> <commit-id> --status-after — move a committed file from one commit to another.
but rub <commit-id> <commit-id> --status-after — squash one commit into another when they are the same logical change.
but rub <commit-id> zz --status-after — uncommit a bad commit to unassigned changes, then recommit selected files/hunks.
- Use
but squash <commits> -m "message" --status-after for straightforward collapse.
- Use
but move <commit-id> <target-commit-id> --status-after for ordering, and but reword <commit-id> -m "message" for message cleanup.
- Re-run
but status -fv after each mutation because CLI IDs can change.
- Validate, then
but push <branch>.
If a clean replacement branch is still warranted, prefer GitButler-native reconstruction: create the branch with but branch new, then use file tools to edit the working tree and but commit --changes .... Avoid git apply; patch replay hides whether you understood the GitButler object model.
Inspect GitButler operation history
Use but oplog when you need to understand or recover recent workspace mutations — especially after move/rub/absorb/unapply/reapply operations, confusing hunk ownership, or before deciding whether but undo is safe. It is the GitButler-native operation history and is often more useful than guessing from git log alone.
but oplog
Reorder commits
but move supports both commit reordering and branch stack operations. Use commit IDs when reordering commits.
but status -fv
but move <commit-a> <commit-b> --status-after — uses commit IDs like c3, 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.
Proven-bad applied branch: unapply first, then diagnose
If runtime evidence proves that an applied GitButler branch is the regression — for example nixos-rebuild --rollback or unapplying a stack immediately restores the broken service — stop patching forward in the same dirty workspace.
Preferred recovery:
-
Preserve the evidence in the response or notes: which rollback/unapply action restored behavior, and what symptom disappeared.
-
Unapply the suspect branch/stack from the workspace:
but unapply <branch-name> --status-after
-
If unapply leaves tiny unassigned residue caused by your attempted repair, inspect it with but diff; discard only residue that is clearly from the failed repair:
but discard <change-id> --status-after
-
Only after the workspace is back to known-good should you decide whether to create a fresh narrower branch, revert a specific commit, or ask for direction.
Do not keep surgically editing config after the user has provided decisive rollback evidence that the whole branch is bad. That is patch-forward tunnel vision and risks extending the outage.
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 commit succeeds but the file still appears in unassignedChanges in the --status-after output
- 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.
--changes accepts 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 redundant but status -fv unless 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 status does NOT include per-commit file counts. Use but show <branch-id> or git show --stat <commit-hash> to get them.
- Avoid
--help probes; use this skill and references/reference.md first. Only use --help after a failed attempt.
- Run
but skill check only when command behavior diverges from this skill, not as routine preflight.
- Edge case:
but branch delete <name> can fail to remove an unapplied/stale branch with not found in any stack, and after applying it can refuse with would leave an anonymous segment. First try GitButler-native cleanup (but apply, but unapply, but uncommit --discard as appropriate). If GitButler still cannot delete the branch and the intent is only stale branch cleanup, state the limitation, then use the narrow native fallback: delete the local branch/ref and any stale remote-tracking ref (git branch -D <name>, git branch -dr origin/<name>). Do not use this fallback for history reshaping.
- For command syntax and flags:
references/reference.md
- For workspace model:
references/concepts.md
- For workflow examples:
references/examples.md