Jujutsu 中的 GitHub Stacks

Lobsters Hottest 工具

摘要

关于使用 GitHub 的堆叠拉取请求功能与 Jujutsu 版本控制系统结合使用的技术入门指南,涵盖先决条件、jj 配置以及创建和链接堆叠的手动工作流程。

<p><a href="https://lobste.rs/s/keiw21/github_stacks_jujutsu">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/08/13 15:24

# Jujutsu 中的 GitHub Stacks 来源:https://alan.norbauer.com/articles/github-stacks-with-jujutsu/ GitHub 于 2026-07-30 将其 堆叠拉取请求(PR)功能(https://github.blog/changelog/2026-07-30-stacked-pull-requests-are-now-in-public-preview/) 公开预览。该功能主要面向 git 用户,但也记录了对其他兼容 git 的版本控制系统的支持,比如 Jujutsu(jj)(https://docs.jj-vcs.dev/)。这是一份使用 jj 配合 GitHub stacks 的入门指南。 ## 前提条件(https://alan.norbauer.com/articles/github-stacks-with-jujutsu/#prerequisites) ### 安装 CLI(https://alan.norbauer.com/articles/github-stacks-with-jujutsu/#install-clis) - 你需要安装 `git`(安装说明(https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)) 和 `jj`(安装说明(https://docs.jj-vcs.dev/latest/install-and-setup/)) CLI。 - 你需要安装 `gh` GitHub CLI(安装说明(https://cli.github.com/))。 - 使用 `gh extension install github/gh-stack` 安装 stacking 扩展。 本文撰写/测试时使用的版本: - jj v0.43.0 - git v2.52.0 - gh v2.96.0 - github/gh-stack v0.1.0 ### 配置 jj(https://alan.norbauer.com/articles/github-stacks-with-jujutsu/#configure-jj) 我将复用上一篇文章《Jujutsu 中的 Stacks》(https://alan.norbauer.com/articles/stacks-in-jujutsu#full-configuration)中定义的一些 jj 别名和 revset 别名。 ### 额外福利:学习 `jj` 的书签别名(https://alan.norbauer.com/articles/github-stacks-with-jujutsu/#bonus-learn-jjs-bookmark-aliases) GitHub 的 Stacked PRs 要求每个 PR 都有一个 `jj` 书签(git 分支),因此你需要创建很多书签。未来的 UI 工具必定会自动在底层创建分支名称,但现在,先学习用于轻松管理书签的 `jj` 别名: | 命令 | 描述 | |------|------| | `jj b l` | 列出书签 | | `jj b s -r ` | 创建(或移动)书签到指定提交 | | `jj b a` | 将最近的书签推进到当前提交(类似 `jj tug`) | | `jj b --help` | 包含所有命令别名的文档 | 💡 题外话:你知道吗?你可以通过自定义 revset 来改进默认的 `jj bookmark advance`(`jj b a`)行为。如果你位于一个带有代码的提交之上的新空白提交,你可能希望将书签推进到下方包含代码的提交。你可以通过以下配置实现: ``` [revset-aliases."closest_pushable(to)"] definition = 'heads(::to & mutable() & ~empty() & description(regex:".+"))' doc = "Closest mutable, non-empty, described commits at or behind to" [revsets] bookmark-advance-to = "closest_pushable(@)" ``` jj 使得通过覆盖内置的 `bookmark-advance-to` revset 来自定义行为变得非常简单,你可以将其设置为任何你想要的内容。 ## 手动工作流(https://alan.norbauer.com/articles/github-stacks-with-jujutsu/#manual-workflows) `gh stack` CLI 有一堆子命令,其中大部分用于管理或消费本地对 stack 的跟踪(例如 `init`、`view`)。在 jj 仓库中,你只会使用少数几个用于管理 GitHub 上远程 stack 的子命令(例如 `link`、`push`),具体如下: ### 创建一个 stack(https://alan.norbauer.com/articles/github-stacks-with-jujutsu/#create-a-stack) 1. 为 stack 中的每个提交创建一个书签: ``` # 使用我们的 revset 别名转到 stack 底部 jj edit -r "stack_bottom()" # 为提交命名 jj b c # 转到下一个提交 jj next --edit # 为提交命名 jj b c # ... 对 stack 中的每个提交重复操作 ``` 2. 将你的书签上传到 GitHub,为每个书签创建草稿 PR,并将它们全部链接到一个 stack 中: 使用我们的 stack 别名(https://alan.norbauer.com/articles/stacks-in-jujutsu#stack): ``` gh stack link $(jj sb -r "stack()") ``` 或者,使用 jj 修订版本范围: ``` gh stack link $(jj sb -r commit1::commitN) ``` 或者,由于 `jj sb` 默认使用你的 substack(https://alan.norbauer.com/articles/stacks-in-jujutsu#substack),你可以转到顶部(https://alan.norbauer.com/articles/stacks-in-jujutsu#top-and-bottom)(此时你的 stack 和 substack 是同一回事),然后链接整个 stack: ``` jj top --edit gh stack link $(jj sb) ``` 最后一种可能是最容易记的。 ### 在 stack 的**顶部**添加新提交(https://alan.norbauer.com/articles/github-stacks-with-jujutsu/#add-a-new-commit-to-the-top-of-the-stack) 假设新提交的变更 ID 是 `abc`: 1. 确保你正在编辑你的新提交: 2. 为新的、当前提交创建一个书签: 3. 如果你修改了任何 downstack 提交,你需要推送更新(因为 `jj git push` 会执行 `--force-with-lease` 推送,但 `gh stack link` 不会): 4. 使用所有 stack 书签重新运行 link: 现有的 PR(用于所有 downstack 的)将被跳过,新分支将获得一个新的草稿 PR,并被链接到 stack 中。 ### 在 stack 的**底部**或**中间**添加新提交(https://alan.norbauer.com/articles/github-stacks-with-jujutsu/#add-a-new-commit-to-the-bottom-or-middle-of-the-stack) 你不能在 stack 的中间添加内容(否则会收到错误:“无法更新 stack:新的 PR 必须添加到现有 stack 的顶部”),因此你必须删除你的 stack 并重新创建它。假设新提交的变更 ID 是 `abc`: 1. 转到 GitHub Web UI 并移除该 stack: 截图:GitHub stack UI 显示“Unstack pull requests”“ 按钮 2. 为新提交创建一个书签: 3. 由于你修改了已变基的 upstack 提交,请重新推送所有内容: 4. 使用所有 stack 书签(包括新的书签)重新运行 link: ``` jj top --edit gh stack link $(jj sb) ``` 现有的 PR 将被跳过,新分支将获得一个新的草稿 PR,并被链接到 stack 中。 ### 从 stack 中移除一个提交(https://alan.norbauer.com/articles/github-stacks-with-jujutsu/#remove-a-commit-from-the-stack) 你必须删除你的 stack 并重新创建它。假设要移除的提交的变更 ID 是 `abc`: 1. 转到 GitHub Web UI 并移除该 stack: 截图:GitHub stack UI 显示“Unstack pull requests”“ 按钮 2. 确保你位于 stack 的顶部: 3. 如果你还没有放弃该提交,请放弃它: 4. 推送你的更新: 5. 使用所有 stack 书签重新运行 link: ``` jj top --edit gh stack link $(jj sb) ``` 现有的 PR 将被跳过,stack 将被重新创建。 6. 你移除的提交将在 GitHub 上留下一个孤立的 PR。如果你愿意,可以手动关闭它和/或删除远程分支。或者,使用 `jj git push --deleted` 推送*所有*已删除的书签。 注意:删除远程分支会关闭其 PR,因此如果你在重新运行 `gh stack link ...` *之前* 运行 `jj git push --deleted`,你最终会同时关闭被删除分支上方的 PR。在链接之后删除以避免这种情况。 ### 更新现有 stack 的现有提交(https://alan.norbauer.com/articles/github-stacks-with-jujutsu/#update-the-existing-commits-of-an-existing-stack) 1. 重新推送你的 stack: ### 合并你的 stack(https://alan.norbauer.com/articles/github-stacks-with-jujutsu/#merge-your-stack) 与取消堆叠一样,理论上可以从 CLI 执行,但太复杂了: ``` gh stack link --open $(jj sb -r "stack()") # draft => published gh stack merge $(gh pr view "$(jj sb -r "stack()" | awk '{print $NF}')" --json number --jq .number) --yes --squash ``` 所以,干脆从 Web UI 操作吧。反正你可能也会在那里查看 CI 信号。🤷🏽‍♀️ ## 更新(https://alan.norbauer.com/articles/github-stacks-with-jujutsu/#updates) 几乎可以肯定有改进上述工作流的方法,而我完全没有想到。如果你有好的建议,请联系我(https://alan.norbauer.com/contact),我会更新这篇文章。 ## 印象与结语(https://alan.norbauer.com/articles/github-stacks-with-jujutsu/#impressions-and-closing) 我希望的未来改进: 1. 基于上述手动步骤构建的 GUI 工具,自动消除繁琐操作。我个人使用*出色的* VisualJJ VSCode 扩展(https://www.visualjj.com/)来完成我 80% 的 jj 命令,我猜想开发者们正在努力添加 GitHub stack 支持。 2. `gh stack` 扩展能获得一个单一的 `gh stack submit` 子命令,自动搞定一切,让上面的所有内容变得过时。 3. 对需要删除 stack 并重新创建的工作流的改进,例如向 stack 中间添加提交。 就目前而言,这些东西大体上能工作,我对 GitHub 中获得 stacking 功能感到*非常*兴奋。我最初的印象是,人们可以立即将这个功能用好,我很感谢开发这个功能的开发者们。话虽如此,让我们承认房间里的大象:这是一个缺乏雄心的 stacked PR 实现。GitHub 的 stacked PRs 完全建立在现有、有缺陷的 GitHub PR 模型之上,没有改变任何基础: > 我为我的直接表示道歉,但你们参考了哪些先例?为什么让人们为 stack 中的每个变更创建一个分支?为什么开发者在迭代 PR 时必须创建新的提交?对 interdiffs 的适当支持在哪里?变更 ID 呢? > ——sunshowerson Hacker News(https://news.ycombinator.com/item?id=49117162) 没有自动的变更 ID,我们得到的是手动分支。没有自动的 `gh stack submit`(如 graphite 的(https://graphite.com/docs/cheatsheet#syncing-and-submitting) 或 git-branchless 的(https://github.com/arxanas/git-branchless/wiki/Command:-git-submit) submit 命令),你只能手动将分支列表喂给 `gh stack`。等等。 简而言之,对开发者体验期望放低一些,你会对最终结果感到满意:一个能在 GitHub 中正常工作的 PR stack。 ## 生产说明(https://alan.norbauer.com/articles/github-stacks-with-jujutsu/#production-notes) AI 事实 每容器 1 份 份量约 1 篇文章 每份含量 机器手写文字 0% % 机器* - 散文手写。机器校对。手工应用修改。0% - 代码与配置0% - 创作所有代码/配置均为手工编写。0% - 验证所有代码/配置均由 Claude Opus 5 进行程序化验证,确保正确性和一致性。手工应用修复。100% - 人工审查100%* % 机器 告诉你这篇文章有多少是由机器编写的。数值是随意估计的,并非精确测量。本标签未经美国食品药品监督管理局评估。

相似文章

Evan的Jujutsu教程

Lobsters Hottest

面向熟悉Git的用户,关于版本控制系统Jujutsu (jj)的简明教程。

jujutsu v0.42.0 发布

Lobsters Hottest

Jujutsu (jj) 版本控制系统发布了 v0.42.0。Jujutsu 是一款开源 VCS,以 Git 作为存储后端,同时提供更符合人体工程学的操作界面,其功能设计灵感来源于 Mercurial、Sapling 和 Darcs。

用Jujutsu战胜Git严谨疲劳

Hacker News Top

本文介绍了一种使用Jujutsu版本控制系统的工作流程,旨在克服在Git中保持严格提交纪律的疲劳感,允许开发者先进行杂乱提交,最后再整洁地重新组织它们。

spr:GitHub上的堆叠拉取请求

Lobsters Hottest

spr 是一个 CLI 工具,可将 Git 分支上的每个提交转换为 GitHub 上的独立拉取请求,无需手动管理分支即可实现堆叠式 PR。