TIL: Show jj change-id and status in your zsh prompt
I drive several jj workspaces — see my earlier post on working with stacked PRs using jj — and wanted my zsh prompt to show the change-id plus working-copy status, in the main repo and in secondary workspaces, falling back to plain git everywhere else. Three non-obvious things bit me.
1. Use --ignore-working-copy, or the prompt snapshots the repo on every render. jj’s working copy is itself a commit, and most commands snapshot the whole tree first. In a big monorepo that’s slow and creates commit churn. jj’s own docs recommend this flag “in a command prompt”. One read-only call emits everything, tab-separated:
jj log -r @ --no-graph --ignore-working-copy -T '
change_id.shortest(8) ++ " " ++ commit_id.shortest(6) ++ "\t" ++
if(conflict,"C","") ++ if(divergent,"D","") ++ if(empty,"","M")
'
2. Call command jj, not jj. I wrap jj with a shell function that reroutes jj log through a PR-badge tool. My prompt called the bare jj log, hit the wrapper, the -T template got mangled, and the entire jj branch silently fell back to a plain git hash. command jj skips the function.
3. A secondary jj workspace has no .git. jj workspace add dirs only contain .jj — the git backend lives in the main repo. So a git-based prompt shows nothing there, but jj finds .jj by walking up and just works. That’s the case a pure-git prompt can never cover.
Wiring it into oh-my-zsh’s amuse theme without forking it — override git_prompt_info and keep the original as the fallback:
functions[_omz_git_prompt_info]=$functions[git_prompt_info]
git_prompt_info() {
if (( $+commands[jj] )); then
local rec
rec=$(command jj log -r @ --no-graph --ignore-working-copy --color=always -T '...' 2>/dev/null \
| sed $'s/\x1b\\[[0-9;]*m/%{&%}/g') # wrap ANSI so zsh counts it as zero-width
if [[ -n $rec ]]; then
local ids=${rec%%$'\t'*} flags=${rec##*$'\t'} icons
[[ $flags == *M* ]] && icons+="%{$fg[red]%}!" # working-copy change
[[ $flags == *C* ]] && icons+="%{$fg_bold[red]%}x" # conflict
[[ $flags == *D* ]] && icons+="%{$fg[yellow]%}⁇" # divergent
print -n -- " %{$fg[magenta]%}◆%{$reset_color%} ${ids} ${icons}%{$reset_color%}"
return
fi
fi
_omz_git_prompt_info # non-jj repo → original git prompt
}
Result: ~/ws/conn/backend ◆ rpprpllk 6ffda1 ! ⌚ 8:05.
The sed wrapping each ANSI escape in %{…%} matters: without it, zsh counts the color bytes as visible width and the right-prompt alignment drifts.
Let's stay connected!
Author
I'm Oliver Nguyen. A software maker working mostly in Go and JavaScript. I enjoy learning and seeing a better version of myself each day. Occasionally spin off new open source projects. Share knowledge and thoughts during my journey.