资讯动态

使用 Jujutsu(jj)对接 GitHub 与 GitLab:分支推送、评审流程与多远程协作实战指南

发布时间:2026/9/10 8:56:15 来源:尧图企业网站定制
使用 Jujutsujj对接 GitHub 与 GitLab分支推送、评审流程与多远程协作实战指南【免费下载链接】jjA Git-compatible VCS that is both simple and powerful项目地址: https://gitcode.com/GitHub_Trending/jj/jj本文以 Jujutsujj一个与 Git 兼容的分布式版本控制系统的 GitHub/GitLab 协作指南 为骨架系统讲解如何用jj完成从创建提交栈、推送书签bookmark到 GitHub、更新仓库、处理评审意见、使用多个远程以及传递 Git push options 的完整流程并结合仓库源码cli/src/commands/git/push.rs、cli/src/commands/git/clone.rs、docs/config.md、docs/bookmarks.md等补充底层实现细节。读完本文你将掌握 Jujutsu 与 GitHub/GitLab 项目协作的全部核心命令与配置技巧并理解其与传统 Git 工作流的关键差异。前置知识本指南假定读者对 Git 或 Mercurial 有基本了解。在 Jujutsu 的模型中提交commit与分支branch是解耦的Jujutsu 的书签bookmark只是指向某个提交的具名引用而提交本身通过 change ID 长期存在因此你可以随时移动书签、改写提交历史而不必像 Git 那样反复 rebase 和 force-push。关于书签的完整语义可参见 docs/bookmarks.md关于 colocated 仓库的兼容性细节可参见 docs/git-compatibility.md。基本工作流先建提交栈再按需创建书签Jujutsu 入门最直接的方式是先堆叠stack提交等到需要推送到远程时才创建书签。你只需在推送时创建书签即可有两种主要流程使用自动生成的书签名或使用具名书签。流程一使用自动生成的书签名在这个示例中我们让 Jujutsu 自动创建书签# 从默认书签 main 上开启一个新提交 $ jj new main # 重构一些文件然后添加描述并开启新提交 $ jj commit -m refactor(foo): restructure foo() # 添加一个功能然后添加描述并开启新提交 $ jj commit -m feat(bar): add support for bar # 让 Jujutsu 生成书签名并推送到 GitHub。注意我们推送的是 # 工作副本提交的*父提交*因为工作副本提交本身是空的。 $ jj git push --change - # 或简写为 -c -jj git push --change revset源码中对应 push.rs 的-c/--change参数会为指定提交基于其 change ID 生成一个形如push-change_id 短哈希的书签名。该行为由templates.git_push_bookmark模板控制默认值为push- change_id.short()见 create_change_bookmarks 实现。生成的书签会被自动跟踪tracked因此下一次jj git push会默认把它纳入推送范围。为什么用-在 Jujutsu 中每次jj commit之后工作副本总是停留在一个新的空提交上工作副本本身也是一种提交。-表示当前工作副本的父提交也就是真正包含改动、需要推送的那个提交。流程二使用具名书签在这个示例中我们创建名为bar的书签然后推送到远程# 从默认书签 main 上开启一个新提交 $ jj new main # 重构一些文件然后添加描述并开启新提交 $ jj commit -m refactor(foo): restructure foo() # 添加一个功能然后添加描述并开启新提交 $ jj commit -m feat(bar): add support for bar # 创建书签以便推送到 GitHub。注意我们把书签创建在 # 工作副本提交的*父提交*上因为工作副本本身是空的。 $ jj bookmark create bar -r - # bar 现在指向前面两个提交 # 设置书签在远程上被跟踪 $ jj bookmark track bar # 推送到 GitHub只推送 bar $ jj git push也可以在 Git 风格下预先创建书签并在其上提交但你需要在创建新提交时手动移动书签——与 Git 不同Jujutsu 不会自动替你移动书签。从源码看书签的自动更新仅发生在提交被改写rebase 等或废弃abandon时见 docs/bookmarks.md而在书签上新增提交并不会推进书签。更新仓库jj git fetchjj rebaseJujutsu 目前没有与git pull直接对应的命令虽然未来可能增加类似命令参见仓库内sync相关讨论。更新分支是一个两步过程用jj git fetch拉取远程上发生的一切用jj rebase -o main把所有本地分支 rebase 到main之上。jj rebase默认等同于-b 因此如果你有多个未合并分支需要为每个分支再调用一次jj rebase -b 分支或者一次性传入多个-b参数每个分支一个。这种fetch 与 rebase 分离的设计源于 Jujutsu 的底层模型jj git fetch只是把远程引用导入本地视图见 clone.rs 中的GitFetch逻辑而提交的移动由显式的jj rebase完成避免了 Git 中 pull 隐式合并带来的歧义。在 Git colocated 工作区中协作执行jj git init后.jj与.git目录会共存称为 colocated Jujutsu/Git 仓库此时 Git 会处于 detached HEAD 状态。这很反常因为 Git 主要依赖具名分支而 Jujutsu 不需要。在 colocated 工作区中每个jj命令都会自动把 Jujutsu 的仓库视图与 Git 的视图同步。例如jj commit会更新 Git 仓库的 HEAD从而支持增量迁移逐步从 Git 切换到 jj$ nvim docs/tutorial.md $ # 做更多工作。 $ jj commit -m Update tutorial # 在工作副本提交的父提交上创建书签 $ jj bookmark create doc-update -r - $ jj bookmark track doc-update $ jj git push对应源码中jj git init的 colocate 选项在 git/init.rs 中处理clone 时默认 colocate除非配置git.colocate false见 clone.rs 的参数说明。在纯 Jujutsu 仓库中工作在纯 Jujutsu 仓库中流程进一步简化。如果无需显式命名书签直接让 jj 为一个变更change生成书签即可——Jujutsu 能够为某个修订版本创建书签$ # 做你的工作 $ jj commit $ # 推送变更 mw让 Jujutsu 自动创建一个名为 $ # push-mwmpwkwknuz 的书签 $ jj git push -c mw这里-c接受任意修订表达式revset既可以是上面示例的 change ID 前缀也可以是-等符号生成的push-change_id书签会被自动跟踪并随jj git push一并推送。处理评审意见Review Comments处理评审意见有两条路径取决于项目的偏好。许多项目GitHub 风格偏好在书签上追加提交来回应评审意见另一些项目如 Jujutsu 和 LLVM 自身偏好保持提交干净通过改写提交并强制推送来回应。脚注GitHub 风格评审之所以要求追加提交是因为 GitHub 目前只能对书签分支进行比较而 Jujutsu/LLVM 偏好干净提交的理由可参见文中引用的 stacked diffs 相关博文讨论。方式一追加新提交如果你的项目偏好通过追加提交回应评审意见可以这样做$ # 在 your-feature 书签之上创建一个新提交 $ jj new your-feature $ # 修改代码回应意见。然后审查改动。 $ jj diff $ # 为修复添加描述并开启新的工作副本 $ jj commit -m address pr comments $ # 把书签移动到新提交上 $ jj bookmark move your-feature --to - $ # 推送到远程 $ jj git push上述流程创建了一个新提交。同样的效果也可以在不创建新提交的情况下达成⚠️ 警告强烈建议在执行下面的示例后执行jj new因为后续所有编辑仍然会 amend 到之前的提交上。$ # 在 your-feature 书签之上创建一个新提交 $ jj new your-feature $ # 修改代码回应意见。然后审查改动。 $ jj diff $ # 为修复添加描述 $ jj describe -m address pr comments $ # 把书签移动到当前提交上 $ jj bookmark move your-feature --to $ # 推送到远程 $ jj git push方式二改写提交保持历史干净如果你的项目偏好保持提交干净可以这样做$ # 在 your-feature 的倒数第二个提交上开启新提交 $ # 因为评审者要求在那里修复 $ jj new your-feature- # 注意末尾的连字符不是笔误 $ # 修改代码回应意见。然后审查改动。 $ jj diff $ # 将改动 squash 进父提交 $ jj squash $ # 推送更新后的书签到远程。Jujutsu 会自动将其变为 force push $ jj git push --bookmark your-featureyour-feature-末尾的连字符来自 revset 语法表示该书签指向提交的父提交。关于 force push 的安全性需要说明的是Jujutsu 的jj git push在移动远程书签之前会做一系列安全检查详见 docs/bookmarks.md——它会先联系远程核对书签的实际位置是否与 jj 记录的最后已知位置一致若有冲突则拒绝推送类似git push --force-with-lease本地书签存在冲突conflicted时也会拒绝推送且远程已存在的书签必须是已跟踪状态。如果推送被拒绝先运行jj git fetch --remote remote name并解决产生的书签冲突再重试jj git push。对应实现可见 push.rs 中classify_bookmark_update与classify_tag_update对各种拒绝原因的判定。处理他人推送的书签默认情况下jj git clone会导入远程的默认书签通常是main或master但jj git fetch不会把新的远程书签导入为本地书签。这意味着如果你想在另一位贡献者的书签上迭代或测试需要执行jj new bookmarkremote跳到该远程书签上。如果你想导入包括非活跃书签在内的所有远程书签可以在配置文件中设置remotes.name.auto-track-bookmarks *之后就可以直接用jj new bookmark而无需写bookmarkremote了。该设置的更多细节见 docs/config.mdremotes.name.auto-track-bookmarks的值是一个字符串模式string pattern匹配需要自动跟踪的书签名同时作用于本地新建和远程拉取的书签[remotes.origin] auto-track-bookmarks *限制跟踪范围的理由很多。例如与多人共用同一远程协作时你可能不想跟踪所有协作者的书签也不想把仅供本地的书签推送到远程。很多人使用个人前缀如alice/*来区分书签归属[remotes.origin] auto-track-bookmarks alice/*如果你 fork 了 GitHub 仓库origin 是你的 fork而原仓库是 upstream可以只跟踪 fork 的全部书签、但只跟踪 upstream 的main[remotes.origin] auto-track-bookmarks * [remotes.upstream] auto-track-bookmarks main如果书签名没有可识别归属的模式可以用auto-track-created-bookmarks只对jj bookmark create/jj bookmark set创建的书签生效代价是在多台电脑协作时需要手动跟踪从远程 fetch 回来的自己的书签[remotes.origin] auto-track-created-bookmarks *另外jj git clone默认会为远程默认书签创建本地跟踪书签如mainorigin对应的main如果不需要本地更新main可以关闭[git] track-default-bookmark-on-clone false使用 GitHub CLI在非 colocated的 jj 仓库中GitHub CLI 难以找到正确的 Git 仓库路径对应 issue #1008。可以通过配置$GIT_DIR环境变量指向正确路径来解决$ GIT_DIR$(jj git root) gh issue listjj git root会输出仓库根目录的绝对路径实现见 git/root.rs。想自动化处理可以安装 direnv 并在仓库根目录的.envrc文件中定义钩子来配置$GIT_DIR。只需在.envrc中添加export GIT_DIR$(jj git root)然后运行direnv allow批准 direnv 执行。之后即使在不 colocated 的工作区中GitHub CLI 也能自动正常工作你可以直接执行gh issue list等命令。实用的 Revset 查询处理多个书签与远程时下面这些 revset 非常实用revset 完整语法见 docs/revsets.md列出所有不在main书签、也不在任何远程上的、跨越所有本地书签的修订$ jj log -r bookmarks() ~(main | remote_bookmarks())列出你创作的、跨越所有未在任何远程上的书签的修订$ jj log -r mine() bookmarks() ~remote_bookmarks()列出你创作或提交过的所有远程书签$ jj log -r remote_bookmarks() (mine() | committer(youremail.com))列出当前工作副本的所有祖先中未在任何远程上的部分$ jj log -r remote_bookmarks()..有趣的是最后一个表达式恰好与jj git push的默认推送范围一致——源码 find_default_target_revisions 显示默认推送的目标修订集正是remote_bookmarks(remoteremote)..与书签/标签的交集。合并冲突Jujutsu 对冲突的处理方式与 Git 有本质不同冲突被存储为提交树的一部分而不是工作区中的临时标记状态因此即使不解决冲突也可以继续提交、rebase、甚至推送推送时会受安全检查限制。完整的冲突处理概览请参见 docs/tutorial.md 与 docs/conflicts.md。使用多个远程Multiple Remotes在向共享仓库贡献时使用多个远程很常见。例如 upstream 指代将来通过 pull request 合入变更的远程而 origin 是你私有的 fork$ jj git clone --remote upstream https://github.com/upstream-org/repo $ cd repo $ jj git remote add origin gitgithub.com:your-org/your-repo-fork这会自动设置仓库跟踪 upstream 的默认书签通常是mainupstream或masterupstream。你可能希望从 upstream 执行jj git fetch、向 origin 执行jj git push。可以在配置文件jj config edit --user|repo|workspace中配置默认的 fetch/push 远程[git] fetch upstream push origingit.fetch与git.push的默认值都是origin。从源码看默认推送远程的解析逻辑在 get_default_push_remote优先读取git.push配置否则若仓库只有一个远程则使用该远程再否则回退到名为origin的远程。如果你习惯在多台电脑上工作可以配置jj默认从两个仓库 fetch以便通过你的origin仓库保持书签同步[git] fetch [upstream, origin] push originjj git remote add在 git/remote/add.rs 中实现关于多远程工作流的更多细节可参考 docs/guides/multiple-remotes.md。Git push options推送选项jj git push支持通过-o/--option向服务器传递 Git 的 push options。这些选项会被转发给远程由托管平台如果支持解释执行。可以重复使用-o来发送多个选项。语法jj git push -o push_option或jj git push --option push_option多个选项jj git push -o foo -o barval引号如果选项值包含空格用双引号包裹。在源码中-o/--option参数被收集为字符串列表最终封装进GitPushOptions { remote_push_options }传给底层git::push_refs见 push.rs 与 push.rslib/tests/test_git.rs 中的测试用例直接验证了merge_request.create、merge_request.draft等选项会被原样传递给远程。是否支持取决于服务器。GitLab 支持用于 CI 与 merge request 的 push options其他平台可能不支持。完整的选项列表与行为请参考你所用托管平台的文档。GitLab push options 示例详见 GitLab 文档跳过本次推送的 CIjj git push -o ci.skip向创建的流水线传递 CI 变量jj git push -o ci.variableMAX_RETRIES10 -o ci.variableMAX_TIME600推送时创建带元数据的 merge requestjj git push \ -o merge_request.create \ -o merge_request.targetmain \ -o merge_request.titleAdd feature X \ -o merge_request.descriptionImplements X with tests \ -o merge_request.draft流水线成功时自动合并并删除源分支jj git push \ -o merge_request.merge_when_pipeline_succeeds \ -o merge_request.remove_source_branch添加与移除标签jj git push \ -o merge_request.labellabel1 \ -o merge_request.labellabel2 \ -o merge_request.unlabellabel3指派与取消指派用户jj git push \ -o merge_request.assignuser1 \ -o merge_request.assignuser2 \ -o merge_request.unassignuser3小结与 GitHub/GitLab 协作时Jujutsu 的核心心智模型是提交栈 按需书签 显式 fetch/rebase 安全的自动 force push。先无负担地堆叠提交推送前用jj git push -c生成书签或用jj bookmark create命名书签并 track同步上游用jj git fetch配合jj rebase -o main回应评审既可追加提交GitHub 风格也可改写提交干净历史风格多远程场景通过[git] fetch/push配置默认行为并通过remotes.name.auto-track-bookmarks精细控制书签跟踪最后利用-o传递 GitLab CI 与 merge request 的 push options让整条流水线自动化。这些命令与配置都可以在当前仓库的 cli/src/commands/git/ 源码、docs/bookmarks.md、docs/config.md 与 docs/revsets.md 中找到对应的实现与完整说明。【免费下载链接】jjA Git-compatible VCS that is both simple and powerful项目地址: https://gitcode.com/GitHub_Trending/jj/jj创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价