Skip to content

Instantly share code, notes, and snippets.

@nafeger
Created April 17, 2026 15:01
Show Gist options
  • Select an option

  • Save nafeger/62a269bcceb893e01dde4a9b3a81bc48 to your computer and use it in GitHub Desktop.

Select an option

Save nafeger/62a269bcceb893e01dde4a9b3a81bc48 to your computer and use it in GitHub Desktop.
Claude Code skill: get a fresh GitButler workspace synced to origin/main (triages applied branches + floating code, then pulls)
name gitbutler-get-fresh-workspace
description Use when starting new work in a GitButler repo and you want the workspace cleared and synced to origin/main. Triggers include "fresh workspace", "start fresh", "clean up workspace", "sync to main", "reset to main", or starting a new bead or feature on a stale workspace.

GitButler: Get a Fresh Workspace

Overview

Bring a GitButler workspace to a clean state: nothing applied except branches with active WIP, no floating uncommitted changes, target advanced to latest origin/main.

Core principle: every piece of workspace state must have a disposition before syncing. Applied branches that are merged or submitted as PRs are "done" — clear them locally. Anything else (local commits with no PR, unassigned changes) requires the user.

When to Use

  • Starting a new bead/feature and want a clean base
  • After merging PRs, to drop stale applied branches
  • User says: "start fresh", "clean up my workspace", "sync to main", "reset to main"

Do NOT use when:

  • Mid-conflict resolution
  • Not a GitButler-managed repo (check but status succeeds)

Disposition Rules

Read but status --json and classify each item:

State Signal Action
Applied branch, merged to main branchStatus == "integrated" Auto-unapply
Applied branch with open PR reviewId != null Auto-unapply
Applied branch, local commits, no PR, not integrated neither above STOP — ask user
Empty branch no commits, no changes handled by but clean
Unassigned changes (floating code) unassignedChanges non-empty STOP — ask user
Conflicted commits conflicted: true on any commit STOP — resolve first

Never guess a disposition for the stop-and-ask cases. The user's in-flight work and loose files are theirs to direct.

Procedure

  1. Survey. Run but status -fv for the human view, and capture but status --json for programmatic inspection.

  2. Scan for stop-and-ask triggers. If any apply, STOP and ask the user before touching anything. Show branch names, commit counts, and the floating-file list. Offer concrete options (commit+push+PR, leave applied and skip sync, or explicit discard with confirmation).

  3. Unapply done branches. For each branch with branchStatus == "integrated" OR a non-null reviewId:

    but unapply <branch-name> --status-after
    

    Use the branch name from the JSON (not the CLI ID — names are stable across refreshes).

  4. Sync to origin/main.

    but pull --check
    but pull --status-after
    

    If --check reports issues, STOP and ask the user.

  5. Remove empty branches.

    but clean --status-after
    
  6. Verify. Final but status -fv must show:

    • No unassignedChanges
    • Only branches with active WIP still applied (or none)
    • Target at latest origin/main HEAD

Report the final state back to the user with a one-line summary: "Clean workspace, target at origin/main@, N branches still applied: [...]".

Example

Write scratch files to ./tmp/ (project-local), never /tmp — many users restrict /tmp access.

Never chain commands with &&, ;, or | in this workflow. Each chained step requires a separate permission approval from the user; running them as individual Bash calls is faster and less noisy than approving a compound command. One command per call.

# Step A — set up scratch dir (one call)
mkdir -p ./tmp

# Step B — capture state (one call)
but status --json > ./tmp/bstate.json

# Step C — classify (one call)
jq '{unassigned_count: (.unassignedChanges | length), branches: [.stacks[].branches[] | {name, branchStatus, reviewId}]}' ./tmp/bstate.json

# Step D — for each done branch, one unapply per call
but unapply old-merged-feature --status-after
but unapply branch-with-open-pr --status-after

# Step E — pull in two calls (check first, then pull)
but pull --check
but pull --status-after

# Step F — sweep empties
but clean --status-after

# Step G — verify
but status -fv

Common Mistakes

  • Using git fetch / git pull / git checkout main. Forbidden — use but pull. See the gitbutler skill.
  • Auto-unapplying a branch with local unpushed commits and no PR. Those commits exist only on the branch; unapplying keeps them but the user may lose track. Always ask.
  • Discarding unassigned changes without asking. Floating files are often in-progress work, screenshots, or plans. Always ask.
  • Skipping but pull --check. Running but pull on a conflicted state makes a mess.
  • Using CLI IDs instead of branch names for unapply. CLI IDs can shift between but status calls; branch names don't.
  • Chaining commands with && / ; / |. Each chained segment costs a separate permission prompt. Run each step as its own Bash call instead.

See Also

  • gitbutler skill — base commands, workspace model, stacking/move recipes
  • but clean --help — flags for handling upstream-only branches
  • but unapply --help — branch removal from workspace (keeps branch, drops from applied set)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment