jj 项目 Demos 指南:用可复现脚本生成终端截图,展示 Jujutsu 核心特性
【免费下载链接】jjA Git-compatible VCS that is both simple and powerful项目地址: https://gitcode.com/GitHub_Trending/jj/jj
demos目录是 Jujutsu(jj)项目随仓库自带的可复现演示与截图生成工具集。它以demo_*.sh脚本形式逐个演练jj的 Git 兼容、工作副本自动提交、操作日志与撤销、冲突解决等核心功能,并通过run_scripts.sh在标准化环境中运行这些脚本、自动生成 SVG/PNG 图片,供文档与主页展示。读完本篇,你将掌握如何在自己的机器上重放这些演示、如何复现官方仓库中的终端截图,以及每个演示脚本背后的jj命令调用链与设计意图。
一、demos 目录里有什么
先看一下目录构成(demos/README.md 即本指南的说明文档):
demo_*.sh演示脚本:每个脚本针对jj的一个特性,运行后会在终端输出带 ANSI 颜色的命令回放:- demo_git_compat.sh:演示
jj与 Git 的兼容性(克隆、书签跟踪、日志、diff、git format-patch兼容输出); - demo_working_copy.sh:演示"工作副本即提交"(working copy as a commit)模型;
- demo_operation_log.sh:演示操作日志(operation log)与
jj op revert/jj op restore/--at-op; - demo_resolve_conflicts.sh:演示冲突记录在提交中并在工作副本解决;
- demo_juggle_conflicts.sh:演示重新排序提交、制造冲突并验证"顶提交无冲突"的冲突传播特性。
- demo_git_compat.sh:演示
run_scripts.sh:批量运行演示脚本并生成 SVG/PNG 的编排器。helpers.sh:被各演示脚本source的公共工具函数(new_tmp_dir、run_command、comment、blank等)。setup_standard_config.sh:为演示生成隔离的JJ_CONFIG与GIT_CONFIG_GLOBAL,保证输出可复现。- 产物:
*.svg与*.png(如git_compat.png、working_copy.png、operation_log.png、resolve_conflicts.png、juggle_conflicts.png),其中 PNG 直接用于 README.md 特性章节配图。
二、快速上手:一条命令跑完所有演示
run_scripts.sh可以接收任意数量的demo_*.sh作为参数。文档给出的推荐用法是把输出管道交给less边看边检查:
cd demos ./run_scripts.sh demo_*.sh |less对每个传入的脚本,run_scripts.sh会依次完成三件事(对应 run_scripts.sh):
- 以
term-transcript capture捕获脚本在终端中的彩色输出,生成<script_base>.svg(如demo_git_compat.sh→git_compat.svg); - 把捕获的原始输出通过
tee同时回显到当前终端,方便你直接观察演示过程; - 若检测到 ImageMagick 的
magick命令可用,则进一步把 SVG 转换为 PNG。
2.1 前置依赖
term-transcript-cli:必备。它是把 ANSI 终端输出渲染成 SVG 的工具。缺少时会报错并给出安装提示(如cargo binstall term-transcript-cli)。run_scripts.sh通过which term-transcript检查,缺失时直接失败退出。- ImageMagick 的
magick:可选,仅用于生成 PNG。缺失时脚本会打印提示"只有 SVG 会被生成",但不会中断 SVG 流程。 - Inkscape:在 Debian 类系统上推荐
sudo apt install inkscape,因为 ImageMagick 生成 PNG 时可能依赖 Inkscape 或其依赖库(源码注释里也说明可以用 Inkscape 手工完成 SVG→PNG 转换)。 - Fira Code 字体(推荐):
sudo apt install fonts-firacode。默认在 Debian 上生成截图时使用 Fira Code;未安装时回退到 Liberation Mono(效果也可以),再不行则按 CSS 字体栈回退到系统monospace。
2.2 一条命令、两种产物
每个演示脚本最终产出同名的.svg与.png两个文件,二者的定位在文档中有明确说明:
- PNG:仓库中自带的 PNG 可能略微过时,因为体积较大不便于频繁更新提交;
- SVG:差异(diff)是人类可读的、便于维护;但不同机器因安装字体不同渲染可能略有差异。
三、脚本如何保证"可复现":标准化环境
3.1setup_standard_config.sh:注入隔离配置
演示的输出必须在不同机器上尽量一致,为此 setup_standard_config.sh 为每次运行注入两份临时配置文件(通过环境变量指向mktemp生成的临时文件,不污染用户的真实配置):
# JJ_CONFIG(jujutsu 用户配置) [user] name = "JJ Fan" email = "jjfan@example.com" [operation] hostname = "jujube" username = "jjfan" [ui] color="always" paginate="never" log-word-wrap=true # 需要配合 COLUMNS 使用要点说明:
[user]固定作者身份,保证提交元数据一致;[operation]固定操作记录的 hostname 与 username,保证操作日志渲染一致;[ui] color="always"强制输出 ANSI 颜色(终端截图必需);paginate="never"关闭分页,避免交互卡住脚本;log-word-wrap=true配合RUN_COMMAND_COLUMNS=80实现日志换行。
同时生成GIT_CONFIG_GLOBAL并设置[color] ui=always,确保底层 Git 命令(如git log --graph)也输出颜色,与jj侧保持一致。
3.2helpers.sh:演示脚本的"脚手架"
helpers.sh 提供四个关键函数:
new_tmp_dir:用mktemp -d创建一次性临时目录并cd进入,脚本退出时自动清理(trap ... EXIT),保证演示不污染用户环境;run_command:先回显$ 命令,再以COLUMNS=${RUN_COMMAND_COLUMNS:-80}执行命令。80 列是既定的换行宽度——term-transcript在 80 列处换行,而 80 也恰好是移动设备上可读的最大宽度;run_command_output_redacted:执行命令但把真实输出替换成灰色提示... (output redacted) ...,用于隐藏会破坏演示对仗的输出(如工作副本描述的变更);run_command_allow_broken_pipe:把jj在管道破裂时的退出码 3 视为成功(对应jj | head场景);comment/blank:输出绿色注释行与空行,构成截图中的解说文案。
从源码结构看,
run_scripts.sh之所以用RUN_COMMAND_COLUMNS而非COLUMNS,是因为bash会重置$COLUMNS,改用自定义变量后由helpers.sh中的run_command()解释,从而稳定控制换行。
四、各演示脚本详解:命令调用链与设计意图
4.1demo_git_compat.sh:Git 兼容性
脚本核心流程(demo_git_compat.sh):
jj git clone https://github.com/octocat/Hello-World cd Hello-World jj bookmark list --all jj bookmark track octocat-patch-1 --remote=origin jj log jj log -r 'all()' jj diff -r b1 jj diff -r b3 jj show --git --template git_format_patch_email_headers git log --graph --all --decorate --oneline它演示的要点:
- 用
jj git clone直接克隆 GitHub 仓库,克隆后默认只为远程master创建本地书签master并跟踪远程分支,其余远程分支仅以远程跟踪书签形式存在; jj bookmark track octocat-patch-1 --remote=origin把某个远程分支纳入本地跟踪;- 默认
jj log会排除未跟踪的远程分支,聚焦"我们自己的"提交;jj log -r 'all()'则显示全部提交(all()是 revset 表达式); jj diff -r b1查看指定提交的差异;jj show --git --template git_format_patch_email_headers生成与git format-patch兼容的补丁输出;- 最后用原生
git log --graph --all --decorate --oneline证明"仓库底层就是真实的 Git 仓库"(Jujutsu 以 Git 仓库作为存储后端,见 README.md 的 "Compatible with Git" 一节)。
4.2demo_working_copy.sh:工作副本即提交
该脚本用jj git clone进入 Hello-World 仓库,然后依次演示(demo_working_copy.sh):
- 初始时工作副本位于
master之上、标记为(empty); - 修改
README、新增new-file后,jj status显示工作副本不再为空,且其提交 ID(以蓝色字符开头)发生变化——因为工作副本本身就是一个提交,每次快照都会生成新的提交 ID; jj bookmark create goodbye为当前工作副本提交打上书签;jj new master从 master 开出新的空提交,原goodbye提交保留——无需git stash,切换即"干净";jj describe -m可设置任意提交的描述(不只是工作副本),体现"提交是唯一可见对象、工作副本并无特权"的设计(对应 README 中 "The working copy is automatically committed" 一节)。
4.3demo_operation_log.sh:操作日志与撤销/恢复
脚本先克隆并做一点清理,随后执行(demo_operation_log.sh):
jj op log # 查看操作日志 echo stuff > new-file jj describe -m stuff jj rebase --onto test jj new master jj describe -m "other stuff" jj op log --limit 4 rebase_op=$(jj --color=never op log --no-graph -T 'id.short(5)' --limit 1 --at-op @--) jj op revert $rebase_op # 只撤销那次 rebase jj --at-op $rebase_op log # 查看 rebase 之后、后续操作之前的仓库状态 jj op restore $rebase_op # 恢复整个仓库到 rebase 之后的状态演示意图:
jj op log展示 Jujutsu 记录每一次操作(快照、describe、rebase、new 等);jj op revert <op>精确撤销某一次操作——示例中只回退了 rebase,而后续的 "other stuff" 提交不受影响;jj --at-op <op> log以只读方式查看"某个历史时点"的仓库视图;jj op restore <op>则把整个仓库状态回滚到该操作之后;- 对应 README 中 "Entire repo is under version control" 一节——整个仓库都在版本控制之下,可以逐条撤销或定向恢复。
4.4demo_resolve_conflicts.sh:冲突的提交内记录与解决
流程(demo_resolve_conflicts.sh):
- 克隆后清理测试书签,在工作副本修改
README(Hello Earth!)并 describe; jj rebase --onto b1——rebase 成功返回,但提示产生冲突;jj log/jj status显示冲突被记录在提交中;工作副本的README呈现冲突标记内容;- 直接
echo "Hello earth!" > README解决冲突,jj status不再报告冲突。
要点:冲突不会导致操作失败,而是作为提交的一部分被记录(first-class conflict,参见 README.md 的 "Conflicts can be recorded in commits" 一节与 docs/conflicts.md)。无论哪个命令引发冲突,都收敛到"在提交里记录冲突、稍后统一解决"这一条工作流,无需git rebase --continue之类的中断续接机制。
4.5demo_juggle_conflicts.sh:冲突的"腾挪"
这是最能体现 Jujutsu 冲突传播能力的演示(demo_juggle_conflicts.sh):
- 先用
jj debug init-simple在临时目录初始化一个"简单后端"仓库,创建三个连续提交first/second/third,都修改同一行文件; jj rebase -s third --onto first与jj rebase -s second --onto third交换二、三提交的顺序——结果"third" 提交出现预期冲突,而最顶上的提交没有冲突,因为它聚合了三个提交的全部变更;jj new second后cat file验证内容确为third的最终状态;- 换个玩法:让
second与third成为兄弟提交并用jj new second third -m merged合并——合并提交同样因聚合了全部变更而无冲突。
这个演示背后是 Jujutsu 将冲突作为一等对象建模的机制:rebase 时冲突信息被携带并传播到后代提交;当某个提交聚合了冲突各方的全部变更时,冲突自动消失。这也是 "Automatic rebase and conflict resolution"(README.md)中"透明版的git rebase --update-refs+git rerere"能力的直观体现,底层实现可参考 lib/src/conflicts.rs、lib/src/merged_tree.rs 与 cli/src/commands/rebase.rs。
五、run_scripts.sh生成图片的技术细节
5.1 SVG 生成:term-transcript capture
run_scripts.sh 中关键调用:
term-transcript capture \ --no-inputs --pure-svg --palette powershell \ --font "Fira Code, Liberation Mono, SFMono-Regular, Consolas, Menlo" \ --out "$script_base".svg "$script_base" < "$outfile"- 之所以用
term-transcript capture而非term-transcript exec,是为了能通过tee把脚本输出同时展示出来; --palette powershell指定配色;--font指定字体优先级列表——term-transcript的默认字体栈是SFMono-Regular, Consolas, Liberation Mono, Menlo,脚本把"经验证包含全部相关 Unicode 符号"的 Fira Code 等字体排在前面(脚本里有关于字体渲染的注释说明)。
5.2 PNG 生成:magick
SVG 默认按 1 SVG 单位 = 1 像素输出,宽度 720 单位。转 PNG 时:
magick -background black "$script_base".svg \ -type Palette -colors 63 -resize 100% \ "$script_base".png-background black很关键:SVG 用透明实现圆角,若不指定背景,透明区域默认会变成白色;-type Palette -colors 63做调色板量化压缩;-resize 100%目前是空操作,改为-resize 700x10000可把宽度压到 700px 并保持宽高比;- 脚本注释特别提醒:PNG 透明与这里的操作顺序是"反直觉"的,编辑时需小心(并引用了 ImageMagick 的讨论线索)。
最终,README.md中各个特性小节直接引用了这些产物图片(demos/git_compat.png 用于 "Compatible with Git",demos/working_copy.png 用于 "The working copy is automatically committed",demos/operation_log.png 用于 "Entire repo is under version control",demos/resolve_conflicts.png 与 demos/juggle_conflicts.png 用于 "Conflicts can be recorded in commits")。
六、字体与输出差异的注意事项
文档明确提醒:PNG 的最终渲染取决于本机安装的字体。官方截图通常在 Debian Linux 上生成,使用 Fira Code 字体;convert -list Fonts可以列出 ImageMagick 能识别到的所有字体。如果某台机器没有 Fira Code,会退而使用 Liberation Mono(也够用),SVG 在网页上查看时则依赖 CSS 字体栈逐级回退。因此,如果你在本地重新生成截图,看到的字体渲染可能与仓库内置 PNG 略有不同——这是预期行为,不必视为异常。
七、小结:这套 Demos 的价值
demos/是一套"自带文档的演示基础设施",其价值在于:
- 可重放:任何人在装好
term-transcript(+ 可选magick)后,都能一键复现与官方完全一致的演示输出; - 可校验:脚本中的每条命令都真实执行,若某条
jj命令行为变化导致输出异常,脚本会以退出码或异常输出暴露问题(配合set -euo pipefail); - 即文档:
helpers.sh的comment()把解说词直接嵌入脚本,截图本身就是图文并茂的教程;而 README.md 又把这些截图作为特性说明的配图,形成"脚本 → 截图 → 文档"的闭环。
如果你想深入了解这些演示涉及的jj命令的完整参数,可查阅 cli/docs/cli-reference.md(jj help的文本版)与 cli/docs/tutorial.md(入门教程);想研究底层冲突机制,可从 lib/src/conflicts.rs 与 docs/conflicts.md 入手。
【免费下载链接】jjA Git-compatible VCS that is both simple and powerful项目地址: https://gitcode.com/GitHub_Trending/jj/jj
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考