jj / How jj operation show works

How jj operation show works

jj operation show (alias jj op show) prints one operation, then what it changed in the repository compared to its parent: commits, working copies, bookmarks and tags.

On this page
  1. 1. Command-line surface
  2. 2. Configuration
  3. 3. End-to-end flow
  4. 4. Core architecture touchpoints
  5. 5. What it reads, and snapshotting
  6. 6. Algorithm and invariants
  7. The comparison base
  8. What is printed
  9. The template
  10. 7. Errors and edge cases
  11. 8. Example output

In short: jj resolves the operation (default @), loads the repository at it and at its parent, renders the operation with the templates.op_show template, and hands both repositories to the same show_op_diff that jj operation diff uses. A merge operation, one with several parents, gets the template only and no diff. It never writes a new operation head.

The command is cmd_op_show. The help text: "Show changes to the repository in an operation" (source). It is registered as Show(OperationShowArgs) in the operation group (source, dispatch). In effect it is jj op diff --op OP with the operation's own template printed above the diff instead of the "From operation" and "To operation" lines.

1. Command-line surface

FlagMeaning
OPERATION (positional)"Show repository changes in this operation, compared to its parent(s)". Defaults to @, the current operation, and completes operation ids (source).
-G, --no-graph"Show a flat list of modified changes instead of a graph" (source).
-T, --template TEMPLATERender the operation with this template instead of templates.op_show; all zero-argument methods of the Operation type are keywords (source).
-p, --patch"Show patch of modifications to changes". "If the previous version has different parents, it will be temporarily rebased to the parents of the new version, so the diff is not contaminated by unrelated changes" (source).
--no-op-diff"Do not show operation diff": print the template only. Conflicts with -p and every diff format flag (source).
Diff format flags (--summary, --stat, --git, …)The shared DiffFormatArgs (source); see jj diff. Any of them turns patches on, -p or not (source).
--show-changes-in REVSETS"Show only changed revisions matching the given revset expression", defaulting to revsets.op-diff-changes-in (source).

The global flags are on the CLI page.

2. Configuration

SettingDefaultEffect
templates.op_showbuiltin_op_log_compactThe operation's own text, labelled op_show and operation (default, source). It is the same default as templates.op_log; see jj operation log for what it prints.
templates.commit_summaryEach commit line of the diff, labelled op_show and commit (source).
revsets.op-diff-changes-inmutable() | immutable_heads()Which changed commits are listed; the rest are counted as elided (default, source). See elision.
ui.graph.style, ui.log-word-wrap, ui.diff-formatter, ui.pagerGraph style, wrapping, default diff format, and the pager, which the command requests (source, source). See jj log.

3. End-to-end flow

jj operation show: call flow After the shared lifecycle, cmd_op_show loads the workspace and snapshots it, resolves the operation and reads its parents, merges the parents into one operation with merge_operations, and loads the repository at both. It builds the commit summary template, the diff renderer and the operation template, parses the changes-in revset, and prints the operation template. With --no-op-diff, or when the operation has more than one parent, it stops there. Otherwise show_op_diff prints changed commits, working copies, and bookmarks and tags. Shared lifecycle: parse args, load config (CLI page) workspace_helper: load the repo at @, snapshot the working copy resolve_single_op(OPERATION); op.parents() the root operation has none; a merge operation has several merge_operations(parents), then load_at the merged parent and the operation no parents gives the root operation; one parent is used as is build the commit summary template, diff renderer and op_show template and parse the changes-in revset request the pager; print the operation with the template --no-op-diff, or more than one parent? yes: stop after the template (merged parents may hold commits missing from the index) Changed commits + new, − old or abandoned Changed working copy per workspace name Bookmarks and tags local, then remote no: show_op_diff

4. Core architecture touchpoints

PieceRole here
resolve_single_opResolves the operation argument against the current operation; see operation expressions.
merge_operations"If operations is empty returns the root operation, if it contains a single entry returns that entry, otherwise merges the operations into a single operation". It is passed the current workspace's name but no ui or description, so it prints nothing; the library writes a "merge N operations" operation that is never made an op head (source, source).
parse_operation_templateCompiles -T or templates.op_show against the Operation type.
diff_formats_for_logTurns -p and the format flags into the list of diff formats; an empty list means no patches (source).
show_op_diffThe comparison, shared with jj op diff and jj op log --op-diff; described on the operation diff page.

5. What it reads, and snapshotting

It goes through workspace_helper, so the working copy is snapshotted first unless --ignore-working-copy is given (source). A snapshot writes an operation, which is then @, so jj op show right after editing files shows that snapshot. It reads the operation and its parents from the op store, the views and commit indexes of both repositories, and the commits it prints; with a diff format, also their trees and file contents.

Unlike jj op diff, it does not merge one index into the other: the operation's own repository is the one commits are looked up in (source). With a single parent that is enough, since the parent's commits are already in its index. A merge operation is skipped because "Merged repo may have newly rebased commits, which wouldn't exist in the index" (source). Nothing is published; a merged parent operation is written to the op store but is not an op head.

6. Algorithm and invariants

The comparison base

The diff is always against the operation's parents, merged: no parents (the root operation) compares the root with itself and prints nothing after the template; one parent is compared directly; several are merged but then not compared (source, source). To compare any two operations, use jj op diff --from … --to ….

What is printed

First the template output, then show_op_diff's sections, each starting with a blank line and skipped when empty: changed commits, as a graph or with -G flat; changed working copies; local bookmarks and tags; remote bookmarks and tags (source, source). How commits are classified as new, rewritten or abandoned, which commits are elided, and how patches are inter-diffs against the first predecessor, is on the operation diff page.

The template

The built-in template ends with a newline, so a blank line separates it from the diff. A custom template without one runs straight into the diff's own leading newline, which upstream's test shows as "Changed commits:" directly under the template text (test).

7. Errors and edge cases

SituationBehaviour
The root operationOnly 000000000000 root() (test).
A merge operationThe template only, with no diff and no message (source).
--no-op-diff with -p or a format flagRejected by clap (source).
The operation matches nothing, or severalAn operation resolution error, as for jj op diff.
Invalid filter revsetInvalid `--show-changes-in` expression: …, or a config error Invalid `revsets.op-diff-changes-in` (source).
The filter names something missing in the parent"Warning: Could not resolve revset expression for elision" with the hint (Use --show-changes-in=all() to see all changes); the commits section is skipped and the rest still print (source, test).

8. Example output

After jj git fetch and jj bookmark track bookmark-1, upstream's test shows the latest operation (source):

$ jj op show
3ffa5350aafc test-username@host.example.com default@ 2001-02-03 04:05:10.000 +07:00 - 2001-02-03 04:05:10.000 +07:00
track remote bookmark bookmark-1@origin
args: jj bookmark track bookmark-1

Changed local bookmarks:
bookmark-1:
+ pukowqtp 0cb7e07e bookmark-1 | Commit 1
- (absent)

Changed remote bookmarks:
bookmark-1@origin:
+ tracked pukowqtp 0cb7e07e bookmark-1 | Commit 1
- untracked pukowqtp 0cb7e07e bookmark-1 | Commit 1

A snapshot operation with a Git-format patch, after writing a file and running jj new (source):

$ jj op show @- -p --git
494872ff8b1e test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00
snapshot working copy
args: jj new

Changed commits:
○  + qpvuntsm 6b57e33c (no description set)
   - qpvuntsm/1 e8849ae1 (hidden) (empty) (no description set)
   diff --git a/file b/file
   new file mode 100644
   index 0000000000..7898192261
   --- /dev/null
   +++ b/file
   @@ -0,0 +1,1 @@ a
   +a

Changed working copy default@:
+ qpvuntsm 6b57e33c (no description set)
- qpvuntsm/1 e8849ae1 (hidden) (empty) (no description set)

See also jj operation log and operations.