Use GitButler CLI for efficient branching, committing, and diffing.

Install

mkdir -p .claude/skills/but && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/7231" && unzip -o skill.zip -d .claude/skills/but && rm skill.zip

Installs to .claude/skills/but

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Commit, push, branch, and manage version control with GitButler. Use for commits, selective dirty-file or hunk commits, branches, diffs, PRs, history edits, squashes, amends, undo, merge, apply, and unapply. For selected dirty files or hunks, inspect with `but diff`; use compact `but status` for commit order, branch/stack placement, or conflict overview; use `but status -fv` when file/hunk IDs or per-commit file details matter. Replaces git write commands.
460 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Intermediate

Key capabilities

  • Stage specific file hunks for commits
  • Manage multiple branches in a workspace
  • Amend or squash existing commit history
  • Undo recent git operations
  • Create and push branches with PRs

How it works

The tool replaces standard Git write commands with a specialized CLI that manages commit order, branch placement, and history edits through stable change IDs.

Inputs & outputs

You give it
Git repository changes
You get back
Version control state updates

When to use but

  • Stage specific file hunks for commits
  • Manage multiple branches in a workspace
  • Amend or squash existing commit history
  • Undo recent git operations

About this skill

GitButler CLI Skill

Use GitButler CLI (but) as the default version-control interface.

Start Here

Choose the narrowest first command by task; avoid ritual status checks:

# Selected dirty files/hunks:
but diff

# Commit order, branch/stack placement, conflict overview:
but status

# File/hunk IDs, per-commit files, amend/split details:
but status -fv

# Details for one known branch or commit:
but show <id>

Do not run plain but status and then but status -fv unless the compact output lacks file/hunk details needed for the task.

For "commit just/only/specific changes on a new branch", use the fast path:

but diff
but commit -b <branch> -m "<msg>" <id> <id>

but commit -b <branch> ... creates the branch when it does not exist and prints the created commit. Do not run a separate but branch new, status command, or verification diff unless the task needs workspace information that the result does not provide.

IDs

The first token on each but diff / but status line is that line's ID — pass it to commands as-is; never hardcode or invent IDs. IDs may be a single character when unambiguous; copy them exactly from command output.

  • Changes and sources are positional, space-separated IDs (but commit -b feat -m "msg" qs:5 uo). A hunk ID is written <file-id>:<hunk-id> (e.g. qs:5, copied from but diff) — the part after the colon is the hunk's ID, not a line range (qs:16-40 is invalid). Do not invent flags like --changes / --hunk / --ids, pass a line range, or comma-separate IDs — nk,pn is parsed as one ID and fails.
  • but diff is the exception: it accepts at most one target. Bare but diff shows all uncommitted files; inspect committed files or other entities one target at a time — never but diff <id> <id>.
  • A committed file is <commit-id>:<file-id> (e.g. uyr:n, shown under each commit). zz means the uncommitted area.
  • Commit IDs are stable change IDs that survive history edits (amend, squash, move, uncommit, reword). Commits without a change ID (e.g. upstream-only) lead with a sha prefix instead, and #N-suffixed refs disambiguate duplicates — both go stale after history edits, and a stale sha can silently resolve to the wrong commit. The (sha …) on verbose commit lines is informational — do not pass it to commands.
  • File/hunk IDs copied from one diff read generally remain usable across chained commits; branch IDs are stable. If an ID stops resolving, re-read but status/but diff and retry.

Chaining: mutation output is concise by default, so you may chain mutations with && off one inspection read. Add --status-after only when the next step needs workspace IDs or details that the mutation result does not provide. Chained but commit calls stack in the order written — the first is oldest, each later one goes on top. History edits may run in sequence when every commit ref involved is a change-ID ref; run them one at a time with --status-after when a ref is sha-based or #N-suffixed, or when the next command needs freshly issued IDs. Chaining but uncommit <id> && but diff is safe because bare diff needs no ID from the uncommit output.

Non-Negotiable Rules

  1. 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. Exceptions: git add -- <path> to mark a conflicted uncommitted file resolved (see "Conflicts in uncommitted files"), and a worktree-local Git commit when but commit reports that linked worktrees are unsupported. Never run but setup from a linked worktree.
  2. Mutation commands print their result without appending workspace status. Add --status-after only when the next step needs resulting workspace IDs or details; otherwise trust the mutation result and do not run a verification status/diff.
  3. Branches marked (merged upstream) have landed; run but pull to remove them, or start new work on another branch. push and mutations (commit, amend, squash, uncommit, reword, move) refuse landed branches and commits, absorb skips them with a notice, and commit skips them when picking a default target.
  4. In non-interactive CLI workflows, do not narrate progress between routine commands. Execute the needed but commands and give a concise final summary.
  5. Prefer this skill and references/reference.md over exploratory help calls. Use <command> --help when required syntax is missing or a command fails; use top-level help only when you genuinely need to discover an undocumented command.

Command Patterns

  • Commit: but commit -b <branch> -m "<msg>" <id> <id>-b <branch> creates the branch if it does not exist
  • Commit everything uncommitted: but commit -b <branch> -m "<msg>" (omit the IDs)
  • Several commits from one diff: chain but commit calls with && (commits stack oldest-first)
  • Commit at a specific history position: --above <commit-or-branch> or --below <commit-or-branch> instead of -b
  • Only one targeting flag (-b / --above / --below) per command. Targeting is required when more than one stack is applied; without it but commit fails with "Unclear where to commit. Found more than one stack". Several branches stacked together count as one stack — an untargeted commit then silently lands on the stack's top branch, so pass -b whenever the branch matters.
  • Always pass -m "<msg>" (or --no-message) to but commit, and to but squash whenever its sources are commits or branches unless the target is zz — those compose a new message, and without a flag an editor opens and blocks. Squash sources that are uncommitted or committed files reuse the target's message and need no flag; squashing into zz rejects message flags outright.
  • Amend: but amend -t <commit-or-branch> <file-or-hunk-id> <file-or-hunk-id> — a branch target resolves to its newest commit
  • Uncommit: but uncommit <commit-id> (whole commit), but uncommit <branch> (all commits and remove the branch), or but uncommit <commit-id>:<file-id> (one committed file); multiple committed-file sources in one call must come from one commit
  • Insert empty commit: but commit --empty -b <branch> -m "<msg>"
  • Squash commits: but squash <source-commit-id> [<source-commit-id>...] -t <target-commit-id> -m "<msg>"
  • Squash a whole branch into one commit: but squash <branch> -m "<msg>" (no -t)
  • Uncommit and remove a branch: but uncommit <branch>
  • Reorder commits: but move <commit-id> --below <commit-id> (--above for the other direction; commit IDs, not branch names)
  • Reorder a block: but move <commit-id> <commit-id> --below <following-commit-id> or --above <preceding-commit-id> (both anchors accept multiple space-separated sources)
  • Move commit to branch top: but move <commit-id> -b <branch>
  • Stack branches: but move <branch> --above <target-branch> (branch names or branch CLI IDs)
  • Tear off a branch: but move <branch> --unstack
  • Discard: but discard <id> [<id>...] — accepts branches, commits, committed files, uncommitted files/hunks, or zz for all uncommitted changes
  • Push: but push <top-branch> — pushes the selected branch and its ancestors; to update a stack, select its top branch once and never loop. Bare but push pushes all unpushed work when run non-interactively — one push per stack (its topmost unpushed branch, ancestors included), so output has one entry per stack, not per branch. It exits non-zero if any stack failed; stacks that already pushed stay pushed, and rerunning after fixing the failure is safe (up-to-date stacks are skipped)
  • Pull (update workspace from the target): but pull — the output reports the result; but pull --check previews without updating when a preview is actually needed
  • Create PR: but pr new <branch-id> [-m "Title..."] [-F pr_message.txt] [-t] [--draft] — auto-pushes first; do not run but push before it

Task Recipes

Update workspace from main

For "get latest from main", "update/sync this workspace", "rebase onto main", or "pull main":

  1. but pull — one command; no preflight needed. Its output reports the resulting state, it refuses safely when uncommitted changes conflict, and but undo reverts it.
  2. If commits come back conflicted, resolve them oldest-first following the printed instructions: but resolve <commit>, edit the files, then but resolve finish. Its result gives the current ID of the next conflict. Add --status-after to the finish you expect to clear the last conflict only when the task needs the complete resulting workspace. When it says no conflicted commits remain, stop; do not run a verification status. Finishing a lower commit rebases the ones above it, so always work bottom-up.

but pull --check answers "would this conflict?" without updating. Do not use it as a routine preflight; use it when the user asks for a preview, repository policy requires one, or other agents' branches may move.

Rebasing applied branches onto the latest target IS but pull — never move, config target, unapply, or raw git pull/git rebase. The base shown in status is the last FETCHED state: when git log shows main (local or remote) ahead of it, that is exactly the update but pull fetches and applies — the target setting is not stale and repointing it is never the fix. Pull carries uncommitted changes along, and its output reports the resulting state. If it refuses because uncommitted changes conflict, park them: but commit -b <branch> -m "wip" <ids>, pull again, then but uncommit the parked commit (there is no stash; do not hand-revert files).

Commit selected files or hunks

  1. but diff — shows file and hunk IDs for uncommitted changes. Do not run plain but status first.
  2. Use file IDs when whole files belong in the commit; use hunk IDs (<file-id>:<hunk-id>) when

Content truncated.

When not to use it

  • Linked worktrees
  • Conflicted commits when using amend

Limitations

  • Linked worktrees are unsupported
  • Conflicted commits do not support amend

How it compares

It provides a higher-level interface that manages staging and history mutations as atomic operations rather than requiring manual Git index manipulation.

Compared to similar skills

but side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
but (this skill)127dReviewIntermediate
resolve-conflicts818moReviewIntermediate
openspec-onboard106moReviewBeginner
codex-cli-bridge99moReviewIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

Search skills

Search the agent skills registry