如何用 GitButler but move 命令把已有分支堆叠(stack)到另一个分支之上或解除堆叠
【免费下载链接】gitbutlerThe GitButler version control client, backed by Git, powered by Tauri/Rust/Svelte项目地址: https://gitcode.com/GitHub_Trending/gi/gitbutler
当你有两个已经存在的分支,其中一个是建立在另一个之上的代码(比如前端功能依赖后端接口),GitButler 的but move命令可以直接把这个分支堆叠(stack)到依赖分支之上;反过来,用--unstack参数就能把分支从堆叠中拆出来,恢复成独立分支。整个过程不需要git rebase --onto,也不需要删除分支重建。
适用前提:仓库中已经安装 GitButler CLI(but),并且当前仓库已经用but setup转换成了 GitButler 管理的 workspace(普通 Git 仓库用 but setup 初始化;worktree 内无法运行but setup)。两个分支必须都已存在——如果子分支还不存在,应该用but branch new <name> --above <parent>直接创建,而不是move。
先确认两个分支当前的 stack 归属
在动手前,用but status查看分支、stack 和提交的全局状态:
but status输出里每个 stack 单独列出,每行第一个 token 是该行的 CLI ID。下面这段输出是 workflow examples 中文档示例:
# Stack 1: feature/backend (bu) — 2 commits # Stack 2: feature/frontend (bv) — 1 commit看到两个分支各自处于独立的 stack 中,就可以执行堆叠。注意两点:
but status显示的短 ID(如bu、bv)只在当前 workspace 快照内有效,做move这类写操作时必须用完整分支名;短 ID 只适合即时只读查看。- 分支上带有
(merged upstream)标记说明该分支已 land(合入上游),move等写操作会拒绝操作已 land 的分支和提交,需要先but pull清理或换分支。
把已有分支堆叠到另一个分支之上
命令形式是but move <子分支全名> --above <父分支全名>,让子分支依赖父分支:
but move feature/frontend --above feature/backend这会把feature/frontend整个分支移到feature/backend之上,两个分支进入同一个 stack。对应 concepts 中的模型:
main ── feature/backend ── feature/frontend (base) (stacked)执行后用but status验证,文档示例的输出为:
# Stack 1: feature/backend → feature/frontend (stacked)即两个分支从两个独立 stack 合并进同一个 stack,feature/frontend排在feature/backend之上。验证通过后可以继续正常开发,提交时用完整分支名指定目标:
but commit -b feature/backend -m "Add caching layer" <file-id> but commit -b feature/frontend -m "Add dialog component" <file-id>(<file-id>从but diff或but status -fv的当前输出中复制,不要手写。)
与创建新堆叠分支的区别
- 分支已存在:
but move <branch> --above <parent-branch>(本文场景)。 - 分支不存在:
but branch new <name> --above <parent-branch>,只有子分支还没建时用它。 - 文档明确警告:不要用
uncommit+branch delete+branch new --above的组合来模拟堆叠——git 分支名在删除后仍会残留,而且这条路径会丢失工作成果;也不要用but undo来解除堆叠(正确方式见下一节)。
解除堆叠:把分支从 stack 上拆下来
当两个分支不再需要互相依赖(例如后端已合入 main,前端可以独立存在),用--unstack把分支拆下来:
but move feature/frontend --unstack命令成功时的输出形如(来自 move 命令测试快照 的文档示例,其中C是测试分支名):
Unstacked branch 'C'再跑一次but status验证:拆下来的分支成为独立的 stack,其余分支保持在原 stack 中。测试快照中的文档示例如下(三分支 stack 拆掉顶部C之后):
╭┄ g0 [B] ● wwm add B │ ├┄ h0 [A] ● tpm add A ├╯ │ ╭┄ i0 [C] ● wlx add C ├╯也就是说C单独成了一个 stack,A → B仍是同一个 stack。--unstack不带参数,写成but move --unstack <branch>与but move <branch> --unstack等价。
参数边界与容易踩的限制
- 目标参数只有一个:
--above、--below、--branch、--unstack四选一且必填。对分支(branch)这个 source 而言,只有--above和--unstack适用;--below和无值--branch只接受 commit 或已提交变更作为 source。 - 一次只能 move 一个分支:
but move A B --unstack这类多分支写法是错误。 - 无值
--branch等价于--unstack:but move <branch> --branch会把该分支拆成独立 stack。 but move的另一个常见用法是重排提交(but move <commit-id> --below <commit-id>,用的是 commit ID 而不是分支名)。分支堆叠用分支全名,提交重排用 commit ID,两者不要混。- 如果
but commit报 "Cannot commit: N changes could not be applied",说明变更依赖了另一个分支的提交且该分支不在同一 stack 中;错误信息的 Hint 会给出精确的恢复命令but move <your-branch> --above <dependency-branch>,执行后重试原提交即可。
移动后出现冲突或需要推送时
move属于历史编辑操作,可能产生冲突:冲突不会中断操作,rebase 总会完成,发生冲突的提交会在输出和but status中标记为{conflicted}。此时按 oldest-first 逐个处理:but resolve <commit-id>进入解析模式、编辑文件去掉全部冲突标记、but resolve finish收尾;解析期间禁止git add、git commit等 git 写命令,只能用but resolve系列命令加直接编辑文件。
堆叠关系确定后发布整条 stack,只需选顶层分支推送一次(but push会连带推送其祖先分支,不要逐分支循环):
but push feature/frontend创建 PR 同理,对顶层分支执行but pr new feature/frontend -t,GitButler 会自动推送祖先分支并设置正确的 PR base 和 stack 元信息;用gh pr create会丢失这套 stack 行为。
更多命令细节可查仓库内的 reference.md(but move一节)和 SKILL.md("Stack existing branches" 一节),也可以直接运行but skill reference查看与当前二进制一致的命令参考。
【免费下载链接】gitbutlerThe GitButler version control client, backed by Git, powered by Tauri/Rust/Svelte项目地址: https://gitcode.com/GitHub_Trending/gi/gitbutler
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考