For developers entrenched in version control systems, jj has emerged as a powerful alternative to Git, offering immutable history and flexible workflows. But its true power lies in customizable configurations that few master. André Arko, maintainer of Ruby's Bundler and jj evangelist, recently aggregated ingenious—and sometimes delightfully 'stupid'—tricks from GitHub, Discord, and blogs, revealing how to elevate jj from a tool to a tailored productivity engine.

The Foundation: Smarter Defaults

Basic tweaks can drastically reduce friction. Globally set context-aware identities with path-based email switching, eliminating manual toggles between work and personal projects:

[[--scope]]
--when.repositories = ["~/work"]
[--scope.user]
email = "[email protected]"

Enhance diff clarity with syntax-aware tools like Difftastic or Delta, and replace default editors with GUIs like Meld for conflict resolution. These adjustments prevent cognitive load, letting engineers focus on code, not tooling quirks.

Templates: Your Secret Weapon for Automation

jj's templating engine unlocks bespoke workflows. Embed live diffs in commit messages to contextualize changes—no more switching terminals:

[templates]
draft_commit_description = ''
  concat(
    coalesce(description, default_commit_description, "
"),
    surround(
      "
JJ: This commit contains the following changes:
", "",
      indent("JJ:     ", diff.stat(72)),
    ),
    "
JJ: ignore-rest
",
    diff.git(),
  )
''

Override subtemplates for UTC timestamps or machine-readable outputs. The escape_json() function enables seamless integration with external tools, like generating parseable commit logs for CI pipelines. This turns jj into a data source, not just a VCS.

Revsets and Aliases: Crafting Your Workflow Language

Define custom revsets to filter commits intelligently. Exclude WIPs or private changes with descriptive prefixes:

'wip()' = 'description(glob:"wip:*")'
'private()' = 'description(glob:"private:*")'

Build aliases for complex routines—like tug, which automates bookmark management by pushing to the nearest 'pushable' commit. Or create GitHub PRs directly from tracked branches:

pr = ["util", "exec", "--", "bash", "-c", """
gh pr create --head $(jj log -r 'closest_bookmark(@)' -T 'bookmarks' --no-graph | cut -d ' ' -f 1)
"""]

These aliases abstract repetitive tasks, turning multi-step processes into single commands.

Game-Changing Commands You Might Miss

Underutilized features like jj absorb redistribute diffs across historical commits automatically, while jj fix preemptively resolves formatting conflicts by running linters over entire histories. Configure it to enforce consistency:

[fix.tools.black]
command = ["/usr/bin/black", "-", "--stdin-filename=$path"]
patterns = ["glob:'**/*.py'"]

Such tools shift left quality control, ensuring reordered commits won’t break pipelines—a boon for trunk-based development.

Why This Matters for Modern Engineering

These configurations aren’t just parlor tricks; they address real pain points in collaborative coding. Automated conflict resolution with tools like Mergiraf slashes review cycles, while machine-readable logs enable audit trails for compliance. As Arko notes, the jj community’s ingenuity—from ThoughtPolice’s revsets to Scott2000’s push indicators—showcases how extensibility fosters innovation. In an era of sprawling codebases, tailoring your VCS isn’t luxury—it’s essential for sustaining velocity. Start experimenting; your most 'stupid' tweak might become your team’s secret weapon.

Source: André Arko’s original post, featuring contributions from jj community members.