Jujutsu (jj) 修订选择参数全解析:-r / -s / -f / -b / -o / -A / -B / -t 的语义与用法

📅 发布时间:2026/9/10 8:14:09
Jujutsu (jj) 修订选择参数全解析:-r / -s / -f / -b / -o / -A / -B / -t 的语义与用法
Jujutsu (jj) 修订选择参数全解析-r / -s / -f / -b / -o / -A / -B / -t 的语义与用法【免费下载链接】jjA Git-compatible VCS that is both simple and powerful项目地址: https://gitcode.com/GitHub_Trending/jj/jjJujutsujj为选择修订提供了一整套 CLI 选项它们在各个命令中用法一致却容易混淆。本文以 cli/docs/guides/cli-revision-options.md 为核心骨架结合 cli/src/commands/rebase.rs、cli/src/cli_util.rs 等源码实现系统讲解「源选择参数」-r/-s/-f/-b与「目标定位参数」-o/-A/-B/-t的区别、适用场景与特殊约定帮助你读完即可准确写出jj rebase、jj diff、jj squash、jj restore、jj git push等命令。阅读前建议先熟悉 revsets 语法如REV::、REV、REV-、。总览两套各司其职的参数jj的修订选择参数分成两组一组用于指定操作的来源source一组用于指定目标destination。记住这个分组就能理解为什么有的命令接受-r而另一些命令强制使用-s或--from。来源类参数Source长选项短选项含义--revision/--revisions-r精确选取 revset 中的修订不多不少。适用于大多数无需指定目标的命令。--source-s指定的修订及其全部后代语义上等价于-r REV::。--from-f选取某个修订的文件内容内容视角而非修订本身。--branch-b相对于目标destination的一整条拓扑分支。目标类参数Destination长选项短选项含义--onto-o把选中的修订变成指定修订的子提交。--insert-after-A把选中的修订插入到指定修订与其子提交之间。--insert-before-B把选中的修订插入到指定修订与其父提交之间。--to/--into-t把选中的内容放置到哪个修订用于内容型操作。两个版本的文档在--from的描述上略有差异web/docs/src/content/docs/guides/cli-revision-options.md侧重“内容的选取”而cli/docs/guides/cli-revision-options.md额外补充了“或某个修订上的书签移动”这一用途jj bookmark move --from ... --to ...。操纵修订-r与-s的选择大多数命令通过-r接受一个 revset-r精确选择 revset 命中的修订不会连带其后代。例如jj log -r REV只展示REV中的修订jj split -r REV把修订REV拆分成多个修订。而-s--source用于必须连同所有后代一起处理的命令。-s REV本质上等同于-r REV::REV及所有后代。例如jj log -r xyz展示修订xyzjj fix -s xyz在xyz及其全部后代上运行 fix 工具——该命令必须作用于整棵后代树所以它只接受-s而刻意不提供-r以此向用户传达“这会影响所有后代”的事实。源码印证在 cli/src/commands/rebase.rs 中RebaseArgs通过ArgGroup::new(to_rebase).args([branch, source, revisions])将-b、-s、-r声明为互斥三选一cli/src/commands/fix.rs 的FixArgs则只有source: VecRevisionArg而没有revision与文档“jj fix只接受-s”的描述一致。为什么是-s而不是-r文档明确指出凡是-s的命令是因为它必须处理一个修订及其全部后代-r会让用户误以为可以只挑其中一部分。这是jj参数设计上的“以选项类型约束操作边界”思想如果命令在语义上不允许“只动中间某一段”它就不暴露-r。指定目标-o/-A/-B三种插入位置移动修订的命令还需要指明“挪到哪里去”。目标类参数提供三种互斥的定位方式--onto REV-o REV把选中的修订作为REV的子提交children--insert-after REV-A REV把选中的修订作为REV的子提交、REVREV的子提交集合的父提交——即插在REV与其子提交之间--insert-before REV-B REV把选中的修订作为REV-REV的父提交集合的子提交、REV的父提交——即插在REV与其父提交之间。典型用法jj rebase -r REV -o main把REV中的修订变基为main的子提交jj rebase -r REV -B yyy把修订REV插入到yyy与其父提交之间jj rebase -r REV -A main -B yyy把修订REV插入到main与yyy之间-A与-B可同时使用分别指定上方与下方的衔接点jj revert -r xyz -o main生成一个撤销xyz的新修订再把它变基到main之上。源码印证RebaseDestinationArgscli/src/commands/rebase.rs定义了onto短选项-ovisible_alias destination、visible_short_alias d、insert_after-A与insert_before-B并声明conflicts_with onto即-o与-A/-B不能同时出现。三种位置最终统一交给 cli/src/cli_util.rs 的compute_commit_location()计算“新父提交集合 / 新子提交集合”仅指定onto新父 目标修订新子为空同时指定insert_after与insert_before新父 after 集合新子 before 集合仅指定insert_after新子通过RevsetExpression::children()自动推导仅指定insert_before新父取 before 集合各提交的父提交flat_map(|c| c.parent_ids())保持顺序并去重。操作内容--from/--to/--into当命令查看或修改的是修订的文件内容而非修订本身时使用--from与--to或--intojj diff --from F --to T比较修订F与修订T的文件差异jj restore --from F --to T把文件内容从F复制到TT中受影响路径的内容变成F中的样子jj squash --from F --into T把F中的文件改动移动到T。--into与--to完全等价接受--into的命令也接受--to拿不准时永远可以用--to。两者并存纯粹是语言可读性考虑——jj squash --from X --into Y比jj squash --from X --to Y读起来更自然。源码印证SquashArgscli/src/commands/squash.rs同时提供from: VecRevisionArg与into: OptionRevisionArg默认--from RestoreArgscli/src/commands/restore.rs同理。此外 cli/src/commands/interdiff.rs 还指出jj interdiff --from A --to B与jj diff --from A --to B不同前者把A先 rebase 到B的父提交上再比较避免混入双方父提交之间的差异。特殊情况一内容型命令使用-r「与其父提交比较」有些命令操作的是内容但允许用-r此时-r的含义是**“与其父提交比较”**。例如jj diff -r R表示“把修订R与其父提交R-对比”。同样地jj diff -r B::D等价于jj diff --from A --to D见 cli/src/commands/diff.rs 的注释。特殊情况二允许省略-r的命令大多数命令把修订放在选项里、把路径作为位置参数。例如查看某个修订中某个文件的差异$ jj diff -r REV file.txt但有些命令无法接受路径参数因此允许省略-r直接把修订作为位置参数传入。典型例子是jj new xyz——规范写法是jj new -r xyz但由于该用法太常见jj直接允许省略-r。允许省略-r的命令清单jj abandonjj describejj duplicatejj metaeditjj newjj parallelizejj show特殊情况三-c与-b的非常规语义还有三个容易记混的特殊选项jj git push --change REV-c REV表示 (a) 用自动生成的名字创建一个新书签bookmark并 (b) 立即把它推送到远程。这里-c接收的是**变更集change**而非普通修订。相关实现见 cli/src/commands/git/push.rs“--change基于特定变更集的 change ID 生成书签名”。jj restore --changes-in REV-c REV表示“撤销REV中给定文件的全部改动”。它刻意不用-r因为jj restore -r REV容易被误读成“把文件从REV恢复到工作副本”实际含义是“与父提交比较后的内容操作”。cli/tests/test_restore_command.rs 中的测试正好记录了这一点执行jj restore -r-会报错jj restoredoes not have a--revision/-roption并提示“要修改当前修订请用--from要撤销某修订相对其父提交的改动请用--changes-in”。jj rebase --branch REV-b REV以某个基为参照rebase 一整条拓扑分支。这是极常见操作的便捷写法。以下四条命令完全等价jj rebase -o main -b jj rebase -o main -r (main..)::jj rebase -o main -s roots(main..)jj rebase -o main因为太常用-b 被设为 rebase 的默认“源”省略不写即等价源码印证plan_rebase_branch()cli/src/commands/rebase.rs在branch为空时默认解析RevisionArg::AT即随后用new_parent_ids.range(branch_ids).roots()求出分支根提交印证了“默认-b ”的行为参数注释cli/src/commands/rebase.rs也明确说明jj rebase -bbr -odst等价于jj rebase -sroots(dst..br) -odst且未指定-b/-s/-r时默认-b 。速查按命令快速回忆该用哪个参数想做的事情推荐命令形式只看某个修订的日志jj log -r REV对某修订及全部后代统一处理如格式化jj fix -s REV把若干修订变成某修订的子提交jj rebase -r REV -o DST把若干修订插到某修订与其父之间jj rebase -r REV -B REV把若干修订插到两个修订之间jj rebase -r REV -A UP -B DOWN比较两个修订的内容jj diff --from F --to T把某修订内容整体还原成父提交的样子jj restore -r R等价于与R-比较撤销某修订自身的改动jj restore --changes-in R把改动并入父提交jj squash --from --into -推送某变更并自动建书签jj git push --change REV把当前分支整条变基到 mainjj rebase -o main默认-b 总结jj修订选择参数的核心心法是**“先分来源与目标再看是‘修订’还是‘内容’”**-r精确选修订、-s连带后代、-b选整条分支、--from/--to选内容移动修订用-o/-A/-B定位移动内容用--to/--into。再辅以三条特殊约定内容型-r表示与父比较、部分命令可省略-r、-c/-b的非常规含义即可准确、自信地写出各类jj命令。如需继续深入 revset 表达式::、、-、roots()、..等符号可查阅仓库的 revsets 参考 与 revset 实现。【免费下载链接】jjA Git-compatible VCS that is both simple and powerful项目地址: https://gitcode.com/GitHub_Trending/jj/jj创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考