A very limited integration between jj and pre-commit allowing you to run your pre-push hooks in a colocated jj/git repository.
I don't expect this to last forever, it's just a stopgap until some jj-native mechanism arrives that can take over.
Prior art:
- https://www.aazuspan.dev/blog/automating-pre-push-checks-with-jujutsu/
- Various comments on jj-vcs/jj#405
Use jj-pre-push push (or an alias - personally I use jj push) as a replacement for
jj git push. It takes all the same arguments, and does the following:
- Determines which bookmarks the corresponding
jj git pushwill update on the remote, and how they would change. - For each of these bookmarks in turn:
- Checks out the bookmark to the working copy
- Runs the pre-push hooks defined in your .pre-commit-config.yaml on the same set of
files pre-commit would when pushing the same change. (For existing branches that's
the files touched in the range
old...new; for new branches it's the files touched in all ancestors ofnewthat aren't present on the remote.) - Reports any failures; and if any files were modified reports the change ID(s) in which these modifications can be found.
- If all hooks succeeded on all branches, executes
jj git pushwith the arguments provided; otherwise nothing is pushed. - Returns the working copy to its original change.
If there is no .pre-commit-config.yaml in your workspace root, jj-pre-push push
immediately delegates to jj git push.
By default jj-pre-push produces no console output of its own unless hooks fail. If
you'd like to see more details about what's happening, you can use jj-pre-push --log-level=INFO push.
If you have uv installed and you're planning to use an
alias anyway, you can avoid explicitly installing at all with uvx, e.g. with this jj
configuration for jj push:
[aliases]
push = ["util", "exec", "--", "uvx", "jj-pre-push", "push"]Otherwise, install the PyPI package jj-pre-push in whichever way you prefer; e.g. uv tool install jj-pre-push or pip install jj-pre-push, and use jj-pre-push push as
described earlier.
If you're a jjui fan (I think maybe you should be!),
here's an example jjui/config.toml snippet showing how you can define custom commands
to invoke jj-pre-push: one to perform the default jj push, and one to push the
bookmarks attached to the change you have currently selected in the UI.
[custom_commands]
"jj push" = { key = ["p"], args = ["push"] }
"jj push selected bookmark(s)" = { key = ["P"], args = ["push", "-r", "$change_id"] }Note that these depend upon the jj push alias defined in the previous section.
You can use jj-pre-push with any checker that has a CLI compatible with pre-commit, for
example prek: specify the name of the checker program on
the command-line as jj-pre-push --checker prek ..., or set the environment variable
JJ_PRE_PUSH_CHECKER=prek.