ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

jj 与 Sapling(Meta 的版本控制系统)深度对比:工作副本、冲突模型、撤销机制与 Git 互操作差异全解析

jj 与 Sapling(Meta 的版本控制系统)深度对比:工作副本、冲突模型、撤销机制与 Git 互操作差异全解析 jj 与 SaplingMeta 的版本控制系统深度对比工作副本、冲突模型、撤销机制与 Git 互操作差异全解析【免费下载链接】jjA Git-compatible VCS that is both simple and powerful项目地址: https://gitcode.com/GitHub_Trending/jj/jjJujutsujj是一款与 Git 兼容的版本控制系统VCS而 Saplingsl是 Meta 在 jj 开始开发约三年后发布、基于 Mercurial 深度修改而来的版本控制系统。本文以仓库内的 sapling-comparison.md 为骨架逐项对比两者在工作副本working copy处理、冲突模型、撤销机制、Git 互操作、打磨程度polish以及 Forge 工作流上的根本差异并辅以 jj 仓库源码与配置作为实现级证据帮助你理解 jj 的核心理念以及在不同团队与协作场景下如何选择。由于 jj 从 Mercurial 借鉴了大量设计两者共享不少相似点包括用户友好的 CLI、用于选择修订的 revset 语言、对堆叠提交stacked commits的良好支持跟踪匿名 head、没有 Git 那种 detached HEAD 状态、支持split命令、amend 一个提交后自动 rebase 其后代提交以及通过 templates 灵活定制输出。核心差异总览维度jjSaplingsl工作副本每次命令自动快照snapshot新文件自动纳入跟踪显式告知工具何时提交、包含哪些文件冲突处理可将冲突状态提交进 commit可推迟解决提交前必须解决冲突撤销由 operation log 驱动jj op log可见全仓历史MetaLog 类似但sl debugmetalog偏向单个 commit 历史Git 互操作可克隆/推送/拉取且支持与 Git 仓库共享同一工作副本支持远程 Git 仓库操作Forge 工作流无直接 forge 集成靠jj git push --change等sl pr submit --stack支持 GitHub PR 栈工作副本自动快照 vs 显式提交jj每次命令都是提交Sapling与大多数 VCS 一样要求用户显式告诉工具何时创建提交、包含哪些文件。jj 则完全不同工作副本会被每条命令自动快照新文件自动被跟踪被删除的文件自动被取消跟踪。这一设计由 working-copy.md 详细描述大多数jj命令在运行时都会把工作副本的变化提交成一个新的提交得到的 revision 会替换之前的工作副本 revision。从配置看快照行为由 cli/src/config/misc.toml 控制[snapshot] max-new-file-size 1MiB auto-track all() auto-update-stale falsesnapshot.auto-track控制哪些路径会被自动跟踪默认all()语法为 fileset匹配 ignore 文件.gitignore的路径永远不会被自动跟踪。若将其设为非默认值未跟踪文件可用jj file track手动跟踪jj file untrack可取消跟踪但保留文件在工作副本需先 ignore 或从 auto-track 模式中移除否则会立刻被再次跟踪。自动快照带来三方面优势工作副本被有效备份每次运行命令都会留下一个快照提交即使误删内容也可从 operation log 恢复没有命令因工作副本有改动而失败不会再出现 abort: 1 conflicting file changes: ... 这类报错也不需要sl shelveCLI 更简单一致因为工作副本被当作一个普通 commit 对待所有命令对它的处理方式统一。底层支撑快照的完整流程从源码结构看几乎所有命令都经过三个主要步骤见 working-copy.md快照工作副本记录为一个 operation在内存中创建新提交等记录为新的 operation更新工作副本以匹配新 operation即应指向的提交。如果第 3 步因故未完成工作副本会被视为 stale过期可用jj workspace update-stale更新。快照的实际解析逻辑位于 cli/src/cli_util.rs它从snapshot.auto-track读取配置并打印解析诊断信息cli/src/commands/run.rs 也提到该配置与重写提交相关。冲突处理可提交的冲突 vs 必须先行解决jj 将冲突作为一等公民与大多数 VCS 一样Sapling 要求用户在提交前解决冲突。jj 则允许你直接提交冲突。需要注意的是提交的是冲突的逻辑表示而不是冲突标记等。详见 conflicts.md。例如当你 rebase 一个提交并产生冲突时冲突会被记录在 rebase 后的提交里rebase 操作本身照样成功之后你想什么时候解决都行。这带来一系列优势合并冲突不会阻止你切换checkout其他提交可以随时解决冲突不必立刻处理rebase 后代提交总是成功jj 和 Sapling 都会自动 rebase但 Sapling 在出现冲突时会失败合并提交可以被正确 rebaseSapling 有时会失败包括合并提交里做的冲突解决——这直接覆盖了git rerere的常见用例也让 evil merge 不再那么邪恶冲突本身及其解决过程都可以被 rebaseCriss-cross merges 与 octopus merges两个以上父提交在实现上变得平凡部分 Git 无法处理或会产生嵌套冲突标记的情形可以被自动解决支持协作式冲突解决前提是你分享的对象也能用 jj 读取冲突表示若对方用 Git 与你协作则不建议。冲突在文件系统中的具体形态虽然冲突可以提交但文件系统不理解冲突。jj 的解决方案是在把冲突写入工作副本时加上冲突标记同时跟踪参与冲突的各部分通常为 3 个之后每次扫描工作副本时解析这些标记并重建冲突状态。你通过把冲突标记替换为解析后的文本来解决冲突不必一次全部解决甚至可以只更新部分冲突内容。用jj resolve可以调用外部合并工具解决 2 侧 1 个 base 的冲突jj restore可以选取某一侧但目前还没有好的方式解决目录、文件与符号链接之间的冲突见 working-copy.md。标准的解决工作流是jj new commit在冲突提交之上创建工作副本提交 → 解决冲突 →jj diff检查 →jj squash把解决结果移回冲突提交也可以直接jj edit commit原地编辑缺点是较难检查解决结果。冲突标记的格式jj 的冲突标记采用 snapshot diff 风格示例docs/conflicts.md中apple/grape/orange示例A 提交把 grape 改为 grapefruitB 提交把所有行改为大写合并后 conflict 1 of 1 %%%%%%% diff from: vpxusssl 38d49363 merge base \\\\\\\ to: rtsqusxu 2768b0b9 commit A apple -grape grapefruit orange ysrnknol 7a20f389 commit B APPLE GRAPE ORANGE conflict 1 of 1 ends与标记冲突起止标记快照snapshot起点%%%%%%%标记要应用到快照上的 diff 起点\\\\\\\只是让标签跨行更易读。相比直接罗列各侧内容这种风格的好处是你无需手动对比各侧找差异尤其对多侧冲突合并 3 个及以上提交只需逐一把 diff 应用到快照上。jj 还支持另外两种标记风格通过ui.conflict-marker-style配置切换snapshot直接展示各侧完整内容gitGit 的 diff3 风格兼容部分外部工具但只支持 2 侧冲突超过 2 侧时回退到 snapshot 风格。此外当文件内容本身包含疑似冲突标记的行时jj 会使用更长的标记以保证无歧义当冲突缺少结尾换行符时jj 会为每一侧补一个换行、并去掉结束标记的换行来补偿详见 conflicts.md。撤销机制operation log 驱动的 undojj 的撤销由 operation log 驱动。每个修改仓库的操作都会被记录进 operation log可用jj op log查看每个 operation 对象包含一个仓库在操作结束时的快照称为 view记录每个 bookmark、tag、Git ref 指向、仓库 head 集合以及每个 workspace 的当前工作副本提交还包含指向前置 operation 的指针与元数据时间戳、用户名、主机名、描述等。基于 operation log 你可以jj undo逐条撤销操作jj op revert撤销一个并非最新的特定操作jj op restore把整个仓库恢复到更早时间点的样子。引用 operation 时可用表示当前操作并支持x-父操作、x子操作运算符顶层--at-op/--at-operation选项可加载指定 operation 时的仓库状态该模式下不会自动快照工作副本适合理解仓库如何演变成当前状态。Sapling 也有类似功能 MetaLogsapling-scm.com/docs/internals/metalog功能似乎相近但 jj 还向用户暴露了完整的日志jj op log让你能明确看到要回退多远Sapling 的sl debugmetalog更偏向显示单个 commit 的历史而非整个仓库的历史。另一个关键差异是得益于工作副本自动快照jj 可以撤销工作副本的改动。例如jj undo一个jj commit之后jj diff会重新显示与 commit 前相同的改动而sl undo一个sl commit后工作副本会是干净的改动已丢失。operation log 还有一个深层好处它支撑了无锁并发。并发执行多个jj命令不会损坏仓库即使在不同机器通过分布式文件系统访问同一仓库只要文件系统保证写入可见性顺序。每个命令启动时加载最新 operation 的仓库状态看不到并发命令的写入若有冲突随后的jj st/jj log会提示仓库发生了分叉divergence。Git 互操作共享工作副本 vs 远程操作Sapling 支持从远程 Git 仓库克隆、推送、拉取jj 同样支持并且额外支持与 Git 仓库共享同一个工作副本——你可以在同一个仓库里交替使用jj和git命令。这被称为 colocated workspace同驻工作区是jj git init/jj git clone创建的默认形态jj 会在每条命令执行时自动从 Git 仓库导入/导出 refs见 git-compatibility.md。colocation 的便捷性在于构建工具等期待一个 Git 仓库存在时非常方便但混用命令也有代价文档列出的劣势包括更容易出现分支冲突或 divergent change id不会丢数据但烦人分支/ref 数量极大时自动 import 会拖慢命令可用jj util gc缓解Git 工具难以处理含冲突的提交jj 在仓库内以非人类可读方式存储冲突树jj会忽略 Git 的暂存区staging area。若不需要可用--no-colocate或git.colocate false关闭也可随时用jj git colocation status/enable/disable查看与切换。在 Git 仓库格式映射层面见 git-compatibility.mdjj 创建的提交带refs/jj/前缀的 ref 以防止 GC含冲突的提交在 Git 中以.jjconflict-base-*/、.jjconflict-side-*/根目录呈现仅用于防止相关 tree 被 GC权威信息在非标准的jj:treescommit header 中Change ID 以 reverse hex 编码写入 git commit header可用git cat-file -p commit ref验证默认写入自 0.30.0 起可用git.write-change-id-header关闭。打磨程度与 Forge 工作流文档也坦率承认Sapling 更打磨、功能更完整。Sapling 有非常漂亮的內建 Web UI Interactive Smartlog支持拖拽提交进行 rebase 等操作。jj 目前没有对应的内置 Web UI。在 ForgeGitHub/GitLab 等托管平台工作流上Sapling 的sl pr submit --stack可以把一摞提交作为独立的一组 GitHub PR推送包括设置 base 分支但只支持 GitHubjj 没有与任何 Forge 的直接集成但提供了jj git push --change为指定提交自动创建分支。你需要用jj git push --change X --change Y ...逐个指定要为哪些提交创建分支并手动在 GitHub或 GitLab 等界面上设置 base 分支之后的推送可以一次性更新全部例如jj git push -r main..这条命令会把当前提交栈从main分叉点以来的所有提交上的所有分支一次推送。从 push.rs 的源码看jj git push的选项体系远比文档示例更丰富--bookmark/--tag按名推送支持 glob 模式、--all推送所有 bookmark 与 tag、--tracked推送所有已跟踪的 bookmark/tag、--deleted推送删除、--change为提交创建 bookmark名称由templates.git_push_bookmark模板控制默认值为push- change_id.short()见 cli/src/config/templates.toml、--named NAMEREVISION、--revision/-r、--dry-run、--allow-empty-description、--allow-private、--allow-conflicts等。其中--allow-conflicts与--allow-private等开关与 jj 可提交冲突、可配置 private commits 的理念一脉相承-r与--change的组合正是文档中jj git push -r main..这类一次性推送全部栈上分支命令的实现基础。值得注意的是jj git push并不像 Git 那样从已跟踪的远程 bookmark 推导推送目标必须用--remote显式指定远程见 push.rs 的 doc 注释推送前会做多项安全检查行为类似git push --force-with-lease仅当远端状态与 jj 上次 fetch 一致时才更新这与 jj 整个设计对安全地重写历史的追求是一致的。小结两者各自的适用场景综合来看这份对比反映了两套设计哲学的分野工作副本即提交jj 把工作副本视为普通提交自动快照消灭了 conflicting file changes 类错误也让撤销能覆盖工作副本改动Sapling 延续显式提交的经典模式。冲突可提交jj 以逻辑表示提交冲突rebase 永不在冲突处失败可推迟解决、可 rebase 冲突本身Sapling 要求提交前解决。可审计的撤销jj 通过jj op log把整个仓库的变更历史暴露给用户支持精确回退到任意操作Sapling 的 MetaLog 定位不同。Git 共栖jj 支持与 Git 共享同一工作副本、交替使用两种 CLI但也因此带来 colocation 下的若干取舍两者都支持从远程 Git 仓库克隆/推送/拉取。生态成熟度Sapling 在打磨程度与 Forge 集成GitHub PR 栈上领先jj 的优势在于理念统一的 CLI 与可编程的冲突/撤销模型Forge 集成则依赖jj git push的灵活选项手工搭建。如果你的工作流高度依赖 GitHub PR 栈、需要开箱即用的 Web UISapling 可能更顺手如果你重视冲突可提交、撤销可精确回溯、Git 仓库可双 CLI 共栖这些能力并愿意用jj git push --change等命令自行编排 Forge 流程那么 jj 的模型在长期重写与并发协作场景下会更有底气。相关细节可在 working-copy.md、conflicts.md、operation-log.md、git-compatibility.md 与 git-comparison.md 中继续深入。【免费下载链接】jjA Git-compatible VCS that is both simple and powerful项目地址: https://gitcode.com/GitHub_Trending/jj/jj创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表