尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

使用 Jujutsu (jj) 与 GitHub/GitLab 协作:从提交栈到 Pull Request 的完整实战指南

使用 Jujutsu (jj) 与 GitHub/GitLab 协作:从提交栈到 Pull Request 的完整实战指南 使用 Jujutsu (jj) 与 GitHub/GitLab 协作从提交栈到 Pull Request 的完整实战指南【免费下载链接】jjA Git-compatible VCS that is both simple and powerful项目地址: https://gitcode.com/GitHub_Trending/jj/jjJujutsu简称 jj是一款 Git 兼容的版本控制系统它改变了先有分支、再在其上提交的传统心智模型——你可以先自由地堆叠提交直到需要推送时再创建 bookmark。本文以 web/docs/src/content/docs/github.md及其完整版 docs/github.md为主线结合 cli/src/commands/git/push.rs 等源码实现完整讲解如何在 GitHub / GitLab 项目上使用 jj 完成从本地开发、推送、评审响应到多远端协作的全流程。读完本文你将掌握两种 bookmark 推送工作流、同步远端更新的标准做法、三种响应评审意见的方式以及多 remote、GitHub CLI 与 Git push option 的实战配置。前置基础bookmark 与 Git 分支的映射在进入 GitHub/GitLab 工作流之前需要先理解 jj 的 bookmark 概念。正如 docs/bookmarks.md 所述bookmark 是指向某个修订revision的命名指针等价于 Git 中的分支。它与 Git 分支的区别在于bookmark 可以在不影响目标修订身份的前提下自由移动当修订被重写例如jj rebase时bookmark 会自动跟随移动jj 中没有当前检出的分支active/current/checked-out bookmark的概念。当与 Git 仓库交互时jj 会将 bookmark 映射为 Git 分支jj git push --bookmark foo会把foobookmark 推送到远端的foo分支反过来在 colocated 工作区中你在 Git 仓库里创建的bar分支经过自动jj git import后也会变成barbookmark。远端 bookmark 的最后已知位置会以bookmarkremote的形式记录如mainorigin这与 Git 的 remote-tracking 分支类似。基本工作流先堆叠提交再创建 bookmarkjujutsu 的核心建议是先创建一叠提交stack只有需要推送时才创建 bookmark。这对应两种主流程让 jj 自动生成 bookmark 名或显式命名 bookmark。方式一使用自动生成的 bookmark 名# 基于默认 bookmark 开始一个新的提交working copy $ jj new main # 重构一些文件添加描述并开始新的提交 $ jj commit -m refactor(foo): restructure foo() # 添加一个功能添加描述并开始新的提交 $ jj commit -m feat(bar): add support for bar # 让 jj 自动生成 bookmark 名并推送到 GitHub。 # 注意我们推送的是 working-copy 提交的 *父提交*- # 因为 working-copy 提交本身是空的。 $ jj git push --change - # 即 -c -这里的关键参数是--change简称-c它会为指定提交自动生成一个 bookmark 名并推送。从 cli/src/commands/git/push.rs 的参数定义可以看到生成的 bookmark 会自动被跟踪tracked其名称默认由模板push- change_id.short()生成例如push-mwmpwkwknuz。如果你希望生成的名称带有个人前缀可以在配置中覆盖模板详见后文自动生成的 bookmark 名小节。方式二使用命名 bookmark# 基于默认 bookmark 开始一个新的提交 $ jj new main # 重构一些文件添加描述并开始新的提交 $ jj commit -m refactor(foo): restructure foo() # 添加一个功能添加描述并开始新的提交 $ jj commit -m feat(bar): add support for bar # 创建一个 bookmark指向 working-copy 提交的 *父提交* # 因为 working copy 本身是空的。此时 bar 包含前面两个提交。 $ jj bookmark create bar -r - # 设置该 bookmark 在远端被跟踪 $ jj bookmark track bar # 推送到 GitHub只推送 bar $ jj git push需要特别提醒的是虽然你可以像 Git 那样提前创建 bookmark 并在其上继续提交但jj 不会像 Git 那样自动移动 bookmark。每创建一个新提交你都必须手动把 bookmark 移到新位置否则 bookmark 会停留在旧提交上。同步远端更新jj git fetchjj rebase截至本文写作时jj 尚没有与git pull等价的单一命令项目跟踪的同步问题见 issue #1039。更新你的提交需要两步# 第一步抓取远端所有变化 $ jj git fetch # 第二步把你的提交变基到主 bookmark 之上 $ jj rebase -o mainjj rebase -o main的默认行为等价于-b 即只变基当前工作区涉及的提交。如果你有多个未合入的分支需要为每个分支再执行一次jj rebase -b bookmark -o main或一次传入多个-b参数。从源码角度看jj git fetch的远端选择逻辑位于 cli/src/commands/git/fetch.rs默认读取git.fetch配置未配置且只有一个 remote 时使用该唯一 remote会打印提示否则回退到名为origin的 remoteDEFAULT_REMOTE。抓取时默认遵循remotes.name.fetch-bookmarks/fetch-tags配置未配置则读取 Git 自身的默认 refspec。在 Git colocated 工作区中协作jj git init默认创建的是colocated 工作区.jj与.git目录并存二者共享同一个工作副本。这一点可以从 cli/src/config/misc.toml 中的默认配置git.colocate true得到印证。在这种模式下Git 会处于 detached HEAD 状态——这对习惯命名分支的 Git 用户来说很反常因为 jj 没有当前分支的概念。colocated 工作区的关键特性是自动同步每个jj命令都会自动执行 Git 与 Jujutsu 视图之间的导入导出。例如jj commit会更新 Git 仓库的 HEAD这让你可以渐进式迁移现有 Git 仓库。典型流程$ nvim docs/tutorial.md $ # 继续做一些工作 $ jj commit -m Update tutorial # 在 working-copy 提交的父提交上创建 bookmark $ jj bookmark create doc-update -r - $ jj bookmark track doc-update $ jj git push关于 colocated 模式的更多细节如何禁用、优缺点、如何用jj git colocation命令转换可参见 docs/git-compatibility.md。另外请注意docs/config.md 说明git.colocate是布尔开关设为false即可让jj git init/jj git clone默认创建非 colocated 工作区。在纯 Jujutsu 仓库中工作如果你不需要与他人混用 Git 命令纯 Jujutsu 仓库的工作流更简洁因为 jj 可以为任意修订生成 bookmark无需显式命名直接用--change即可$ # 完成你的工作 $ jj commit $ # 推送修订 mw让 jj 自动创建一个名为 push-mwmpwkwknuz 的 bookmark $ jj git push --change mw注意这里--change接受的是修订参数change ID 前缀或 revset它会为该修订创建 bookmark 并推送。定制自动生成的 bookmark 名如果你希望推送后自动创建的 bookmark 名更具可读性可以覆盖templates.git_push_bookmark模板默认值为push- change_id.short()。例如模拟常见的用户名前缀约定[templates] git_push_bookmark martinvonz/push- change_id.short()该模板必须包含change_id之类的表达式以保证名称唯一且稳定。完整说明见 docs/config.md。处理评审意见的三种方式响应 GitHub/GitLab 上的评审意见时不同项目有不同偏好许多项目典型的 GitHub 工作流偏好向 bookmark 追加新提交而另一些项目如 Jujutsu 与 LLVM偏好重写提交、保持提交历史干净然后强制推送。方式一追加新提交GitHub 风格# 在上面的 your-feature bookmark 之上创建新提交 $ jj new your-feature # 根据意见修改代码然后查看改动 $ jj diff # 为修复添加描述并创建新的 working copy $ jj commit -m address pr comments # 把 bookmark 移到新提交 $ jj bookmark move your-feature --to - # 推送到远端 $ jj git push方式二不新建提交直接描述并移动 bookmark上面的流程会创建一个新提交。如果不希望产生新提交可以这样做——但需要注意此后所有编辑仍会被追加amend到当前提交因此强烈建议在下面的示例执行完后执行一次jj new$ jj new your-feature # 根据意见修改代码然后查看改动 $ jj diff # 直接修改当前提交的描述 $ jj describe -m address pr comments # 把 bookmark 移到当前提交 $ jj bookmark move your-feature --to # 推送到远端 $ jj git push方式三重写提交保持历史干净如果项目要求提交干净可以先跳到你需要修改的那个提交改完再 squash 进父提交# 在 your-feature 的倒数第二个提交之上创建新提交 # 因为评审者要求在那里修改。注意尾部连字符不是笔误 $ jj new your-feature- # 根据意见修改代码然后查看改动 $ jj diff # 把改动 squash 进父提交 $ jj squash # 推送更新后的 bookmark。jj 会自动将其变为 force push $ jj git push --bookmark your-featureyour-feature后面的连字符来自 revset 语法rev-表示该修订的父提交。推送时的自动安全检查无论采用哪种方式jj git push都会在真正移动/创建/删除远端引用前做一系列安全检查实现于 cli/src/commands/git/push.rs 的CommitsValidator默认拒绝推送空描述、缺少作者/提交者信息、包含冲突以及属于git.private-commits集合的提交。可用--allow-empty-description、--allow-conflicts、--allow-private显式放行。此外jj git push的更新语义类似git push --force-with-lease只有当远端当前状态与 jj 上次抓取的状态一致时才会更新远端引用见 push.rs 的命令文档。推送前还可以用--dry-run预览将发生的变更。与其他贡献者的 bookmark 协作默认情况下jj git clone只导入远端的默认 bookmark通常是main或master而jj git fetch不会把新的远端 bookmark 导入为本地 bookmark。因此如果你想检出并测试其他贡献者的 bookmark需要显式指定$ jj new bookmarkremote如果你希望把包括非活跃 bookmark 在内的所有远端 bookmark 都自动导入并跟踪可以在配置文件中设置[remotes.origin] auto-track-bookmarks *设置后即可直接用jj new bookmark而无需写remote后缀。auto-track-bookmarks的值是一个字符串模式string pattern同时作用于本地新建与远端抓取的新 bookmark。该配置的详细说明与使用场景见 docs/config.md。常见的用法是按前缀过滤多人共用同一个远端时每个人只跟踪自己前缀的 bookmark如alice/*从而避免跟踪他人全部 bookmark、也避免误推送本地专用 bookmarkGitHub fork 场景则可对 origin 跟踪全部、对 upstream 只跟踪main。另外还有只作用于本地创建的auto-track-created-bookmarks选项。如果你希望贡献者的 bookmark 在jj git fetch时就被抓取也可以结合remotes.name.fetch-bookmarks配置见 docs/config.md。让 GitHub CLI 在 jj 仓库中正常工作在非 colocated 的 jj 仓库中ghGitHub CLI会无法找到正确的 Git 仓库路径相关讨论见 issue #1008。解决方法是指定$GIT_DIR环境变量指向 jj 内部的 Git 仓库$ GIT_DIR.jj/repo/store/git gh issue list # 等价写法jj 会自动解析仓库根路径 $ GIT_DIR$(jj git root) gh issue list如果不想每次手动设置可以借助 direnv在仓库根目录创建.envrc文件加入一行export GIT_DIR$PWD/.jj/repo/store/git然后运行direnv allow批准它生效。此后即使工作区不是 colocatedgh issue list等命令也能正常运行。注意jj git root也是获取仓库根目录的便捷命令实现见 cli/src/commands/git/root.rs。实用的 revset 查询配合jj log -r使用 revset可以快速筛选出值得推送或需要关注的提交# 列出所有本地 bookmark 上、但既不在主 bookmark 也不在任何远端上的修订 $ jj log -r bookmarks() ~(main | remote_bookmarks()) # 列出你创作的、位于 bookmark 上且尚未出现在任何远端的修订 $ jj log -r mine() bookmarks() ~remote_bookmarks() # 列出你创作或提交过的所有远端 bookmark $ jj log -r remote_bookmarks() (mine() | committer(youremail.com)) # 列出当前 working copy 的所有祖先中、尚未出现在任何远端的修订 $ jj log -r remote_bookmarks()..这些表达式可帮助你快速判断还有哪些提交需要推送。revset 的完整语法参见 docs/revsets.md。合并冲突的处理jj 把冲突视为仓库中的一等公民并将其建模在提交树中详见 docs/conflicts.md 与 docs/tutorial.md。在推送遇到冲突提交时jj git push的默认安全检查会拒绝推送除非显式加--allow-conflicts因此通常的流程是先用jj resolve或jj squash等手段解决冲突后再推送。完整的冲突处理教程请回顾 tutorial。同时使用多个 remoteupstream 与 fork为共享仓库做贡献时常见做法是同时配置多个远端upstream 指向变更最终会通过 Pull Request 合入的上游仓库origin 指向你的私有 fork。# 以 upstream 为远端名克隆上游仓库 $ jj git clone --remote upstream https://github.com/upstream-org/repo $ cd repo # 添加你自己的 fork 作为 origin $ jj git remote add origin gitgithub.com:your-org/your-repo-fork克隆后会自动设置对上游主 bookmark 的跟踪通常是mainupstream或masterupstream。接下来你大概率会从 upstream 抓取、向 origin 推送这可以通过配置默认远端来完成例如写在仓库级配置.jj/repo/config.toml或用jj config set --repo设置[git] fetch upstream push origingit.fetch与git.push的默认值都是origin。源码中对应的默认值见 cli/src/commands/git/fetch.rs 与 cli/src/commands/git/push.rs。关于git.fetch/git.push的完整配置说明包括命令行设置方式、glob 与正则模式见 docs/config.md。如果你在多台电脑上工作还可以让jj默认从多个远端抓取以通过 origin 同步你自己的 bookmark[git] fetch [upstream, origin] push origin注意git.fetch支持字符串或数组以及 glob / 正则模式而git.push目前只能是单个远端名这是一个已知限制未来可能放开。推送选项Push Options对接 GitLab CI 与 Merge Requestjj git push支持通过-o/--option向服务端传递 Git 的推送选项push options这些选项会原样转发给远端并被托管平台解释如果平台支持的话。参数定义与底层传递分别见 cli/src/commands/git/push.rs 和 lib/src/git.rs 中的GitPushOptions结构——它最终被拼装进git push --push-option子进程参数见 push_refs 的实现。用法要点语法jj git push -o push_option或jj git push --option push_option可重复jj git push -o foo -o barval可发送多个选项引号如果选项值包含空格请用双引号包裹推送选项的支持情况取决于服务端GitLab 支持用推送选项控制 CI 与 Merge Request其他平台可能不支持。以下均为 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至此你已经掌握了 jj 在 GitHub/GitLab 协作中的完整工具链先用jj newjj commit自由堆叠提交推送时用--change自动生成 bookmark 或jj bookmark create/track命名 bookmark同步用jj git fetchjj rebase响应评审用追加提交、原地描述或重写 squash 三种方式多 remote 用git.fetch/git.push配置GitLab 场景还可以用-o推送选项直接驱动 CI 与 Merge Request。这些能力的底层行为都能在 cli/src/commands/git/push.rs 与 cli/src/commands/git/fetch.rs 中找到对应实现配置默认值则集中在 cli/src/config/misc.toml。如果你想验证这些命令在真实仓库中的行为仓库的 cli/tests/test_git_push.rs 与 cli/tests/test_git_fetch.rs 是很好的参考。【免费下载链接】jjA Git-compatible VCS that is both simple and powerful项目地址: https://gitcode.com/GitHub_Trending/jj/jj创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表