mcpField
B
but

but

github.com/gaboe开发280 次安装29 周前更新
代码仓库

关于 but

面向使用 GitButler CLI(`but`)的 Agent,提供工作区模式下的代码变更与版本管理流程指导。重点说明多分支栈操作、精确提交以及保护其他会话的变更。

主要功能

  1. 01同步并检查工作区状态
  2. 02创建与管理并行或堆叠分支
  3. 03按文件或代码块提交变更
  4. 04整理提交历史
  5. 05推送并创建 Pull Request

适用场景

  1. 01在 GitButler 工作区开始新任务
  2. 02将不同变更分配到对应分支
  3. 03提交特定文件或代码块
  4. 04处理合并后的拉取与工作区同步

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/gaboe/opencode-gitbutler --skill but

安装后在 Claude Code 中输入/but确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
cheatsheet.md
concepts.md
examples.md
reference.md
tutorial.md

详细介绍

GitButler CLI 技能

帮助用户在工作区模式下使用 GitButler CLI(but 命令)。

新会话工作流

每个涉及代码更改的新 Agent 会话都必须遵循此流程:

  1. 先同步 → 执行 but pull 获取最新上游更改(避免冲突和基线过时)
  2. 检查状态 → 执行 but status 查看现有分支和未暂存的更改
  3. 决定分支 →
    • 如果有与任务匹配的现有分支 → 复用该分支(更改已应用)
    • 如果是新工作 → 执行 but branch new <task-name>(例如:feat/add-auth、fix/login-bug)
    • 如果需要恢复尚未应用的工作 → 执行 but apply <branch>
  4. 进行更改 → 按需编辑文件
  5. 暂存并提交 → 执行 but commit <branch> -m "message" --changes <id>,<id>
  6. 完善 → 使用 but absorb 或 but squash 清理历史记录
  7. 准备就绪后推送 → 执行 but push <branch>
  8. 创建 PR → 执行 but pr new <branch> -t(使用默认目标分支)

分支命名: 使用约定前缀:feat/、fix/、chore/、refactor/

尽早提交,经常提交。 不要犹豫,放心创建提交——GitButler 让编辑历史记录变得轻而易举。之后可以随时将更改 squash、reword 或 absorb 到现有提交中。小型原子提交优于大量未提交的更改。

使用写入/编辑工具后

准备提交时:

  1. 运行 but status --json 查看未提交的更改并获取其 CLI ID
  2. 直接提交相关文件:but commit <branch> -m "message" --changes <id>,<id>

可以批量编辑多个文件后再提交,无需每次更改后都提交。

核心概念:工作区模型

GitButler ≠ 传统 Git

  • 传统 Git:一次处理一个分支,使用 git checkout 切换
  • GitButler:在一个工作区中同时使用多个栈,并将更改分配给各个栈

这意味着:

  • ❌ 不要使用 git status、git commit、git checkout
  • ✅ 使用 but status、but commit、but 命令
  • ✅ 可以使用只读的 git 命令(git log、git diff)

严格安全规则(必须遵守)

  1. 绝不丢弃由你之外的人创建的更改。
    • zz(未分配)中通常包含其他会话、Agent 或用户的工作。
    • 如果存在无关更改,请保持原样,并在执行任何丢弃操作前征求许可。
  2. 工作结束时,绝不要将你自己的更改留在 zz 中。
    • 编辑后,运行 but status --json,并通过 but stage 或 but commit --changes 将文件/代码块 ID 移至正确的分支。
  3. 提交前验证分支归属。
    • 确认每个已更改的文件/代码块都属于预期分支/任务,然后只提交相应 ID。
  4. 尊重跨会话的分支归属。
    • 在多 Agent 环境中,分支可能属于其他 Agent 会话。绝不要重写提交信息、重命名或推送你在本会话中未创建的分支。
    • 如果需要修改其他会话的分支,请先征求用户许可。

快速开始

安装:

curl -sSL https://gitbutler.com/install.sh | sh
but setup                          # Initialize in your repo
but skill install --path <path>    # Install/update skill (agents use --path with known location)

给 AI Agent 的注意事项:

  • 以编程方式安装或更新此技能时,始终使用 --path 指定准确的安装目录。如果存在多个安装项,--detect 标志需要用户交互。
  • 所有命令都使用 --json 标志,以获取结构化且可解析的输出。这对于使用 but status --json 可靠地解析工作区状态尤为重要。

核心工作流:

but status --json       # Always start here - shows workspace state (JSON for agents)
but branch new feature  # Create new stack for work
# Make changes...
but commit <branch> -m "…" --changes <id>,<id>  # Commit specific files by CLI ID
but push <branch>       # Push to remote

核心命令

有关详细的命令语法和所有可用选项,请参阅 references/reference.md。 有关实践学习指南,请参阅 references/tutorial.md。 有关单页速查表,请参阅 references/cheatsheet.md。

AI Agent 须知: 为所有命令添加 --json 标志,以获取结构化、可解析的输出。

了解状态:

  • but status --json - 概览(从这里开始,Agent 始终使用 --json)
  • but status --json -f - 包含完整文件列表的概览(需要查看所有已更改文件时使用)
  • but show <id> --json - 有关提交/分支的详细信息
  • but diff <id> - 显示差异

标志说明:

  • --json - 输出结构化 JSON,而不是人类可读的文本(Agent 始终使用)
  • -f - 在状态输出中包含详细的文件列表(与 --json 组合使用:but status --json -f)

组织工作:

  • but branch new <name> - 独立分支
  • but branch new <name> -a <anchor> - 堆叠分支(有依赖关系)
  • but stage <file> <branch> - 预先将文件分配到分支(可选,用于提交前整理)

进行更改:

  • but commit <branch> -m "msg" --changes <id>,<id> - 提交指定的文件或代码块(推荐)
  • but commit <branch> -m "msg" -p <id>,<id> - 同上,使用短标志
  • but commit <branch> -m "msg" - 将所有未提交的更改提交到分支
  • but commit <branch> --only -m "msg" - 仅提交预暂存的更改(不能与 --changes 组合使用)
  • but amend <file-id> <commit-id> - 将文件修改纳入指定提交(显式控制)
  • but absorb <file-id> - 将文件修改纳入自动检测到的提交(智能匹配)
  • but absorb <branch-id> - 将暂存到某个分支的所有更改纳入提交
  • but absorb - 纳入所有未提交的更改(谨慎使用)

获取 --changes 所需的 ID:

  • 文件 ID:but status --json - 提交整个文件
  • 代码块 ID:but diff --json - 提交单个代码块(当一个文件有多处更改时,用于精细控制)

编辑历史记录:

  • but rub <source> <dest> - 通用编辑操作(暂存/修正/压缩/移动)
  • but squash <commits> - 合并提交
  • but reword <id> - 更改提交消息/分支名称

远程操作:

  • but pull - 与上游同步
  • but push [branch] - 推送到远程
  • but pr new <branch> - 推送并创建拉取请求(自动推送,无需先行推送)
  • but pr new <branch> -m "Title..." - 内联 PR 消息(第一行为标题,其余为描述)
  • but pr new <branch> -F pr_message.txt - 从文件读取 PR 消息(第一行为标题,其余为描述)
  • 对于堆叠分支,自定义消息(-m 或 -F)仅适用于所选分支;依赖分支使用默认消息

核心概念

有关工作区模型、依赖跟踪和设计理念的深入介绍,请参阅 references/concepts.md。

CLI ID:每个对象都有一个短 ID(例如,提交的 c5、分支的 bu)。将这些 ID 用作参数。

并行分支与堆叠分支:

  • 并行:彼此独立的工作
  • 堆叠:有依赖关系的工作,一个功能建立在另一个功能之上

but rub 基元操作:核心操作,根据组合对象的不同而执行不同操作:

  • 文件 + 分支 → 暂存
  • 文件 + 提交 → 修正
  • 提交 + 提交 → 压缩
  • 提交 + 分支 → 移动

工作流示例

有关完整的分步工作流和实际场景,请参阅 references/examples.md。

开始独立工作:

but status --json
but branch new api-endpoint
but branch new ui-update
# Make changes, then commit specific files to appropriate branches
but status --json  # Get file CLI IDs
but commit api-endpoint -m "Add endpoint" --changes <api-file-id>
but commit ui-update -m "Update UI" --changes <ui-file-id>

提交指定代码块(精细控制):

but diff --json             # See hunk IDs when a file has multiple changes
but commit <branch> -m "Fix first issue" --changes <hunk-id-1>
but commit <branch> -m "Fix second issue" --changes <hunk-id-2>

整理提交:

but absorb              # Auto-amend changes
but status --json       # Verify absorb result
but squash <branch>     # Squash all commits in branch

解决冲突:

but resolve <commit>    # Enter resolution mode
# Fix conflicts in editor
but resolve finish      # Complete resolution

管理工作区:

but config target origin/test   # Set default PR target (requires unapply all branches first)
but unapply <branch>            # Remove branch from workspace (keeps commits)
but apply <branch>              # Bring branch back into workspace
but teardown                    # Exit GitButler mode → normal git
but setup                       # Re-enter GitButler mode
but discard <ids>               # Discard unstaged changes

PR 合并后的流程

在 GitHub 上 squash 合并 PR 后,请严格按以下顺序操作:

but unapply <merged-branch>    # MUST do BEFORE pull - prevents orphan branch errors
but pull                        # Pull merged changes from remote

重要:如果在取消应用已合并的分支之前执行 but pull,GitButler 会因孤立分支冲突而报错。务必先取消应用。

如果 but unapply 失败(使用 --delete-branch 远程删除后,分支已从工作区消失),but pull 也可能因内部仍存在幽灵堆栈而出现“resolution mismatch”错误。此时可以使用 GitButler 桌面应用处理——告知用户从 GUI 运行 but pull。或者,使用 but teardown → but setup → but config target origin/<branch> 重置。

执行 but teardown → but setup 后:目标配置会重置。请再次运行 but config target origin/<branch>。

安全使用 --no-hooks

当预提交钩子因与更改无关的既有错误而失败时,可以使用 --no-hooks。但这也会跳过格式化程序:

bun run format                                    # Format FIRST
but commit <branch> -m "msg" --changes <ids> --no-hooks  # Then commit without hooks

或者,正常提交并吸收格式化修复:

but commit <branch> -m "msg" --changes <ids>      # Commit (hooks may fix formatting)
but absorb                                         # Absorb any auto-formatted changes

已知问题和解决方法

问题发生情况解决方法
but resolve 丢失目标配置进入 resolve 模式后,but config target 会重置为“未设置”在 but resolve finish 后再次运行 but config target origin/<branch>。如果 finish 失败,则执行 git checkout gitbutler/workspace → but teardown → but setup
but absorb 区块锁定如果某个区块被另一个分支上的提交锁定,Absorb 会将其分配给错误的提交使用 but amend <file> <commit> 进行明确控制,而不是使用 absorb
but pr new 没有 --base 标志始终针对默认目标创建 PR先设置目标:but config target origin/<branch>
but config target 需要先取消应用有已应用的分支时无法更改目标对所有分支运行 but unapply → 更改目标 → 运行 but apply
but config forge auth 是交互式的无法在非交互式 Agent 模式下运行用户必须在终端中运行,并在 GitHub 上授予组织访问权限
but commit 的预提交钩子失败钩子因与所做更改无关的既有错误而失败如果错误并非由你的更改导致,则使用 but commit --no-hooks。务必先运行 bun run format,因为 --no-hooks 会跳过格式化程序
but branch delete 删除最后一个片段如果删除后会留下匿名片段,则无法删除使用 but unapply,而不是 delete
but stage 前缀匹配分支名可以缩写but stage <id> ch 可用于 chore/gitbutler-setup
but discard 区块范围错误丢弃文件级更改时,有时会出现区块范围错误对文件级更改使用 git checkout -- <file>,而不是 but discard
but teardown + but setup 重置目标teardown/setup 周期结束后,目标配置会丢失setup 后再次运行 but config target origin/<branch>
Lefthook 的 pre-commit.old 不断累积Lefthook 会创建 pre-commit.old 备份,并在下次安装时产生冲突在 package.json 的 prepare 脚本中添加 rm -f .git/hooks/pre-commit.old
在取消应用前运行 but pull仍有已合并分支处于应用状态时拉取,会导致孤立错误运行 but pull 前,务必先运行 but unapply <merged-branch>
远程分支删除后运行 but unapply远程删除分支时(例如合并时使用 --delete-branch),but unapply 会因“branch not found”失败,随后 but pull 会因“resolution mismatch”失败使用 GitButler 桌面应用拉取,或执行 but teardown → but setup → but config target origin/<branch>
拆分区块的文件卡在 zz 中文件包含锁定到不同分支上提交的区块——GitButler 会将 stack_id 设为 None,插件则根据锁定引用将文件视为“已处理”手动提交每个区块:运行 but diff --json 获取区块 ID,然后针对每个区块运行 but commit <branch> -m "msg" --changes <hunk-id>
插件自动清理未清除空分支ge-branch-* 清理失败率约为 12%;用户命名的空分支永远不会自动清理运行 /b-branch-gc 命令,或手动运行 but unapply <branch-id>
通知未送达 Agent插件通知送达率约为 55%(观察到的会话中,259 条已排队,142 条已送达)务必使用 but status --json 验证状态——不要只依赖 <system-reminder> 通知
工作区投影不匹配but status 显示分支/堆栈,但 but unapply <branch> 或 GUI stack_details 表示在工作区中找不到该堆栈将其视为 GitButler 元数据损坏,而不是 Git 历史问题。停止在原处进行修改,收集日志、项目和提交图以供支持排查,然后执行 but teardown → 备份 .git/gitbutler → but setup。如果问题仍然存在,请使用全新克隆/工作树。
多次 resolve/rebase 后出现许多 (no changes) 提交堆栈累积了与上游补丁等效或重放重复的合成提交不要继续在原处进行 resolve。冻结引用,使用 git cherry -v 找出补丁等效的提交,并从逻辑基点重建干净分支,而不是保留损坏的历史。
应用一个堆栈时自动取消应用另一个堆栈GitButler 表示,为了应用所请求的堆栈,它必须取消应用另一个堆栈这些堆栈在内容或祖先关系上有重叠。先取消应用当前已激活的冲突堆栈,或者重建预期的堆栈边界,确保一次只应用一条逻辑链。
投影错误导致 but push 受阻工作区/堆栈元数据已损坏,但原始 Git 引用正常如果目标是修复远程祖先关系,请使用原始 Git 验证分支引用,并在万不得已时使用 git push --force-with-lease。之后返回 gitbutler/workspace,并使用 but setup 重新初始化元数据。
诊断卡在 zz 中的文件

当文件卡在 zz(未分配)中且无法自动恢复时:

  1. 找出原因:

    but status --json -f    # Look for files in zz with [LOCKED] markers
    but diff --json          # Get hunk-level IDs and see lock targets
    
  2. 如果代码块被锁定到不同分支(拆分代码块场景):

    • 每个代码块都必须单独提交到其锁定的分支
    • 对每个代码块执行 but commit <branch> -m "msg" --changes <hunk-id>
    • 或执行 but rub <hunk-id> <commit-id>,将其修改并入已锁定的提交
  3. 如果文件没有锁定,但仍在 zz 中:

    • 插件的 after-edit 可能静默失败了——请手动暂存
    • 执行 but stage <file-id> <branch>,或使用 --changes 提交
  4. 如果执行 but cursor stop 后有许多文件卡住:

    • 对每个文件执行 but rub <file-id> <branch-id>,强制分配
    • 这是最可靠的恢复方法

关键要点: 自动恢复无法修复锁定到多个分支的文件。如果在 zz 中看到 [LOCKED],就需要手动处理。

对损坏的堆栈进行精准修复

如果堆栈损坏过于严重,无法通过常规 but resolve 快速收敛——例如:

  • 反复出现 conflicted 提交,
  • git cherry -v 显示大量补丁等效的重复项,
  • GitButler 显示许多标记为 (no changes) 的提交,
  • 或单个提交带入了 .auto-resolution/** 或其他明显无关的快照文件,

请使用精准修复,而不是尝试保留损坏的历史。

适合进行精准修复的情况
  • 原始 Git 图易于理解,但 GitButler 元数据/历史重放难以理解。
  • 即使当前分支历史已无法清晰反映,你仍能明确识别出这项工作的预期逻辑层次。
  • 一个混合提交包含真正的功能文件,以及明显意外混入的无关内容。
外科式修复工作流
  1. 先冻结所有内容

    • 为当前损坏的分支创建备份引用。
    • 暂存工作区中的未提交改动和钩子刷新产生的噪声。
  2. 找到干净的逻辑基点

    • 使用 git cherry -v <base> <branch> 区分补丁等效的重复提交和真正独有的提交。
    • 使用 git log --reverse <base>..<branch> 按顺序查看分支的提交层次。
  3. 从干净的基点重建,而不是沿用损坏的分支历史

    • 从预期的基点创建临时分支。
    • 只挑选干净的提交。
    • 如果提交受到污染(例如添加了 .auto-resolution/**),则只从该提交或现有分支顶端对预期路径执行文件级检出,然后创建新的干净提交。
  4. 独立验证每个重建层

    • 使用 git diff --name-only <base>..<layer> 比较各层之间的文件差异。
    • 在替换引用前,在重建后的提交栈上运行项目验证(bun run check、构建/测试/分析器等)。
  5. 只有在确认干净的提交栈无误后才替换引用

    • 将实际分支引用移至重建后的临时引用。
    • 只有在确认祖先关系和检查结果后,才使用 --force-with-lease 强制推送。
为什么实际操作中这样更快

外科式修复听起来比反复解决冲突更费力,但一旦提交栈陷入重复重放、(no changes) 或元数据损坏的境地,重建逻辑差异通常比保留所有历史产物更快、更安全。

关键安全规则

  1. 绝不要丢弃你没有创建的改动。 zz 中未分配的改动可能属于其他 Agent、会话或用户。对任何你无法确认的改动,运行 but discard 或 git checkout -- 前,务必先询问用户。在 GitButler 工作区中,多个参与者会并行工作——把改动视为“过时”或“已合并”并将其丢弃,是一种有破坏性的假设。
  2. 始终立即将你的改动分配到分支。 不要将编辑内容留在 zz(未分配)中。编辑文件后,使用 but stage <file-id> <branch> 将其暂存到你的工作分支,或直接使用 --changes 提交。

指南

  1. 始终先运行 but status --json 了解当前状态(Agent 应始终使用 --json)。
  2. 每个独立的工作主题都创建一个新的提交栈。
  3. 使用 --changes 直接提交指定文件,无需先暂存。
  4. 尽早并频繁提交——不要等到尽善尽美。与传统的 Git 不同,GitButler 使用 absorb、squash 和 reword 可以轻松修改历史。先创建小型、原子化的提交,之后再完善,胜过积累大量未提交改动。
  5. 作为 Agent 运行时,所有命令都使用 --json 标志——这样会提供结构化、可解析的输出,而不是面向人的文本。
  6. 不确定时使用 --dry-run 标志(push、absorb)。
  7. 频繁运行 but pull——在会话开始时、创建分支前以及推送前都要运行。工作区过时会导致合并冲突。
  8. 更新此技能时,使用 but skill install --path <known-path> 以避免出现提示。
  9. 完成工作前检查带锁的 zz 文件。 运行 but status --json -f,查找 zz 中带有 [LOCKED] 标记的文件。这些文件不会自动恢复——你必须使用 --changes <hunk-id> 将每个代码块手动提交到正确的分支。详情请参阅 references/concepts.md — 区块锁定。
  10. 不要只相信通知——插件通知的送达率约为 55%。在推断分支分配或提交状态前,始终使用 but status --json 核实工作区状态。

插件自动行为(幕后操作)

GitButler 插件会自动执行一些操作。你无需亲自执行这些操作——但你应该了解它们会发生,以免重复操作或对意外的状态变更感到困惑。

行为触发条件执行内容
文件自动分配每次文件编辑后查找拥有该文件的分支,并运行 but cursor after-edit 或 but rub 来分配文件
自动提交会话空闲时(Agent 停止编辑)运行 but cursor stop,将所有未提交的更改提交到其分配的分支
LLM 提交信息改写自动提交后根据实际差异,使用 Claude Haiku 改写通用提交信息
分支重命名自动提交后根据用户的提示词,将 ge-branch-* 分支重命名为描述性名称
空分支清理自动提交后移除提交数为 0 的 ge-branch-* 分支(成功率约为 88%)
会话标题同步自动提交后根据分支名称更新会话标题
上下文注入每条 Agent 消息发送前注入包含工作区通知(分支已创建、提交已完成等)的 <system-reminder>
这对你意味着什么
  1. 不要手动重命名 ge-branch-* 分支——插件会在空闲后重命名
  2. 不要改写自动生成的提交信息——插件会使用 LLM 改写
  3. 如果看到意外的提交——检查插件是否在空闲事件期间自动提交
  4. 通知送达率约为 55%——并非所有注入的通知都会送达给你。请始终使用 but status --json 验证状态,而不要依赖通知
  5. 空分支清理可能失败——如果看到过时的 ge-branch-* 分支,请运行 /b-branch-gc

评论

支持 Markdown