Skip to content

Instantly share code, notes, and snippets.

@mystor
Last active May 27, 2026 14:38
Show Gist options
  • Select an option

  • Save mystor/10111f7bc9fd14fea1301ce1b33b593d to your computer and use it in GitHub Desktop.

Select an option

Save mystor/10111f7bc9fd14fea1301ce1b33b593d to your computer and use it in GitHub Desktop.
jj git-index diff editor (v2)
# This diff editor uses the state of the git index (staged files) to edit the diff.
# This gives an effect similar to `git commit`, which can be useful due to tooling
# often being high-quality for using the git index to split up changes.
#
# This tool is designed to be used with the commit, split, and squash commands.
# This is made easier with some aliases. A custom merge-editor definition is unneeded.
#
# LIMITATIONS:
# 1. jj doesn't allow a diff editor to edit files which are only changed in the index,
# and unchanged in the working copy, those will be discarded.
# 2. You must run this command within the worktree, such that the `git` commands
# implicitly derive the index from the working directory.
# 3. This naturally only works in colocated workspaces, and only if the source
# revision is the working copy.
[aliases]
icommit = ["commit", "--tool", "/path/to/jj-diffedit-git-index.sh"]
isplit = ["split", "--tool", "/path/to/jj-diffedit-git-index.sh"]
isquash = ["squash", "--tool", "/path/to/jj-diffedit-git-index.sh"]
#!/bin/bash
set -euo pipefail
export LC_ALL=C
TEMP=$(mktemp -d)
trap 'rm -rf -- "$TEMP"' EXIT
LEFT="$1"
RIGHT="$2"
# Snapshot the index state into a tree. This strips intent-to-add index entries
# which are treated as empty files by ls-files & restore. jj implicitly adds
# intent-to-add index entries for new files.
TREE="$(git write-tree)"
# jj checks out a sparse working copy, limit to that sparse set.
find -P "$LEFT" "$RIGHT" \( -type f -o -type l \) -printf '%P\0' |
sort -zu > "$TEMP/sparse"
# Every pathspec passed to git restore must be in $TREE
git ls-tree -rz --name-only --full-tree "$TREE" |
sort -zu |
comm -z -12 "$TEMP/sparse" - > "$TEMP/restore"
# Clear out $RIGHT, then restore $TREE state into it
rm -r -- "$RIGHT"
mkdir -- "$RIGHT"
if [[ -s "$TEMP/restore" ]]; then
git --literal-pathspecs --work-tree="$RIGHT" restore \
--source="$TREE" \
--pathspec-from-file="$TEMP/restore" \
--pathspec-file-nul
fi
@MrAnno
Copy link
Copy Markdown

MrAnno commented May 22, 2026

This is nice stuff.

Please consider adding export LC_ALL=C or anything similar to the script, as comm and sort may disagree otherwise:

comm: file 2 is not in sorted order
comm: input is not in sorted order
Error: Failed to edit diff

@mystor
Copy link
Copy Markdown
Author

mystor commented May 23, 2026

Sure, I've added it to the top of the script

@MrAnno
Copy link
Copy Markdown

MrAnno commented May 27, 2026

Thank you. I'm using this together with git gui. It's amazing :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment