I’ve been playing with jujutsu recently, and I’ve been impressed by its customization system.
For instance, you can set custom log templates to see jj log
output in any format you like,
and the built-in log templates are in the same format,
so they can be easily copied into your own config and tweaked.
I made one today based off of the builtin builtin_log_detailed
template
which I called log_detailed_with_stats
.
It adds changed lines to its output, like this:
@ Commit ID: 6e7e9d46ff2069162999b3c78c841340ec95bb74
│ Change ID: vnwwlnrwxplylsmyslokqvpnxmlyysnr
│ Author : Micah R Ledbetter <me@micahrl.com> (2025-09-24 06:29:57)
│ Committer: Micah R Ledbetter <me@micahrl.com> (2025-09-24 06:42:48)
│ Changes : 2 files, 29 insertions(+), 30 deletions(-)
│
│ (no description set)
Here are a few screenshots to compare, all of my dotfiles repo in the same state.

git log

jj gitlog

jj statlog
Notes about these:
- I have some uncommitted changes in my git working tree, but in jj these are shown in a new commit with no description set.
- I use an alias
jj gitlog
forjj log -r 'all()' -T builtin_log_detailed
— aside from specifying that template, it also shows logs even for immutable changes, making it more analogous togit log
which shows all commits back to the beginning. - I use an alias
jj statlog
forjj log -r 'all()' -T log_detailed_with_stats
to see my custom template with theChanges : ...
lines
To do this, I found the builtin_log_detailed
template
definition
copied it, and added the Changes : ...
output line.
This was super easy because the builtin templates use the same
template language
as user config files do — no magic.
Here’s the configuration in my ~/.config/jj/config.toml
:
[template-aliases]
# Adapted from the builtin_log_detailed template
# https://github.com/jj-vcs/jj/blob/main/cli/src/config/templates.toml#L255
# but with a line that shows added/removed lines of code
log_detailed_with_stats = 'log_detailed_with_stats(self)'
'log_detailed_with_stats(commit)' = '''
concat(
"Commit ID: " ++ commit.commit_id() ++ "\n",
"Change ID: " ++ commit.change_id() ++ "\n",
surround("Bookmarks: ", "\n", separate(" ", commit.local_bookmarks(), commit.remote_bookmarks())),
surround("Tags : ", "\n", commit.tags()),
"Author : " ++ format_detailed_signature(commit.author()) ++ "\n",
"Committer: " ++ format_detailed_signature(commit.committer()) ++ "\n",
if(config("ui.show-cryptographic-signatures").as_boolean(),
"Signature: " ++ format_detailed_cryptographic_signature(commit.signature()) ++ "\n"),
"Changes : " ++
if(commit.empty(), "empty",
concat(
commit.diff().files().len() ++ " file" ++ if(commit.diff().files().len() != 1, "s") ++ ", ",
commit.diff().stat().total_added() ++ " insertion" ++ if(commit.diff().stat().total_added() != 1, "s") ++ "(+), ",
commit.diff().stat().total_removed() ++ " deletion" ++ if(commit.diff().stat().total_removed() != 1, "s") ++ "(-)"
)
) ++ "\n",
"\n",
indent(" ",
if(commit.description(),
commit.description().trim_end(),
label(if(commit.empty(), "empty"), description_placeholder)) ++ "\n"),
"\n",
)
'''
[aliases]
# A 'git log' like experience
gitlog = ["log", "-r", "all()", "-T", "builtin_log_detailed"]
# Use the custom template with file statistics
statlog = ["log", "-r", "all()", "-T", "log_detailed_with_stats"]