/blog/

2025 0924 jj statlog

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.

screenshot
git log
screenshot
jj gitlog
screenshot
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 for jj log -r 'all()' -T builtin_log_detailed — aside from specifying that template, it also shows logs even for immutable changes, making it more analogous to git log which shows all commits back to the beginning.
  • I use an alias jj statlog for jj log -r 'all()' -T log_detailed_with_stats to see my custom template with the Changes : ... 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"]

Responses

Webmentions

Hosted on remote sites, and collected here via Webmention.io (thanks!).

Comments

Comments are hosted on this site and powered by Remark42 (thanks!).