使用Jujutsu进行补丁格式的编辑修改
Editing changes in patch format with Jujutsu

原始链接: https://www.knifepoint.net/~kat/kb-jj-patchedit.html

## 使用自定义补丁编辑器修改Jujutsu变更 作者需要重命名Jujutsu变更中的一个方法,但发现Python LSP重命名不可靠。虽然Git提供了`git format-patch`和`git am`等解决方案,但Jujutsu对此没有直接支持。`jj diffedit`提供了一个接近的替代方案,允许编辑变更内容,但其内置编辑器功能有限,外部合并工具也不起作用。 为了克服这个问题,作者创建了一个与`jj diffedit`集成的自定义工具。该工具从变更生成一个补丁文件,在用户定义的编辑器中打开它(默认使用nano),然后重新应用修改后的补丁来更新变更的内容。它巧妙地通过先从“右”目录(已应用的变更)中取消应用原始补丁,然后再应用编辑后的版本来工作,从而避免对只读的“左”目录的写入访问。 可以通过`jj config edit --user`配置Jujutsu来设置脚本的路径,从而启用此功能。配置完成后,`jj diffedit --tool=patch`将打开补丁进行编辑,并自动保存以更新Jujutsu中的变更。这提供了一种灵活有效的针对性编辑单个变更的方法。

黑客新闻 新 | 过去 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 使用Jujutsu以补丁格式编辑更改 (knifepoint.net) 4点 由 cassepipe 1小时前 | 隐藏 | 过去 | 收藏 | 讨论 帮助 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请YC | 联系 搜索:
相关文章

原文

Recently, I wanted to search and replace a word in the contents of a single Jujutsu change. I had introduced a method in said change which I retroactively wanted to rename, and renaming the method with LSP is not reliable for Python code in my experience, which is what I was working on at the time.

The obvious solution (albeit a not really nice one) is to look at the change with jj show to see what it changed, and running a global find/replace in your editor, replacing only the locations that the change touched. Alternatively, I could have replaced all the occurrences of the word, including those I didn’t want, and then used the --into argument to jj absorb to tell it to only modify that one change, then abandon the leftover changes.

However, this is either still a lot of manual effort or feels really unclean for something that can be done with relatively minimal effort in Git: using git format-patch to export the patch file, editing it, and then resetting and re-applying the patch with git am.

Jujutsu currently has support for neither of these two commands, however it has something that comes really close to what I want to achieve with potentially less friction than Git: jj diffedit. This command lets you edit the contents of a single change. However, the builtin editor only lets you pick which lines to keep or discard, with no way to otherwise change or rearrange their contents, and external merge tools like KDiff3 (admittedly, the only one I tried), don’t really work well for this purpose.

However, it is possible to add custom external tools to use with jj diffedit via Jujutsu’s configuration file. Jujutsu supplies two directories to the tool: the state of the repository prior to the change to edit (“left”), and the state with it applied (“right”). It is then the responsibility of the tool to modify the “right” directory, which will form the new contents of the change. To make this generate a patch file and then open it in an editor is relatively straight-forward to stick together with a simple shell script, so that’s what I did.

This is the script I came up with. It can surely be improved a bit, but it works fine as-is and I have used it a couple times since – in fact, I used it while splitting the changes to the website for this very article.

#!/usr/bin/env bash
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: 2025 Katalin Rebhan <[email protected]>

set -e

if (( $# != 2 )); then
echo "Usage: $0 LEFT RIGHT" >&2
exit 1
fi

: ${EDITOR:=nano}

left="$1"
right="$2"

tmpdir="$(mktemp --directory)"

echo "Working directory: ${tmpdir}"

ln -s "$left" "$tmpdir"/a
ln -s "$right" "$tmpdir"/b

( cd "$tmpdir" && diff --new-file --text --unified --recursive a/ b/ ) \
> "$tmpdir"/current.patch || (( $? == 1 ))

cp "$tmpdir"/current.patch "$tmpdir"/orig.patch

"$EDITOR" "$tmpdir"/current.patch

cp -r "$right" "$tmpdir"/result
patch --reverse --directory="$tmpdir"/result --strip=1 \
< "$tmpdir"/orig.patch \
> /dev/null
patch --directory="$tmpdir"/result --strip=1 \
< "$tmpdir"/current.patch

mv "$right" "$tmpdir"/oldright
mv "$tmpdir"/result "$right"

rm -r "$tmpdir"

Listing 1: edit-patch (direct link), the script that acts as the glue between diff/patch and Jujutsu.

Notably, one thing it does is taking the “right” directory as a template, from which it first un-applies the original diff, then applies the modified version the user edited. This is because the “left” directory is marked read-only by Jujutsu, and I didn’t want to mark files writable while being careful not to touch other attributes.

To make this actually work, it’s necessary to register the tool with Jujutsu by editing its configuration file with jj config edit --user, adding the following snippet, with the file path adjusted to wherever you put it.

[merge-tools.patch]
program = "/Users/YOU/.local/bin/edit-patch"
edit-args = ["$left", "$right"]
Listing 2: The entry in the Jujutsu configuration file to register the script with the VCS.

After this, it’s possible to run jj diffedit with --tool=patch to open up your editor containing the patch for the selected change, and after saving and closing the editor, the change’s contents will be replaced with the edited patch. Perfect!

联系我们 contact @ memedata.com