In short: jj loads the workspace, which snapshots it as usual, asks the working copy for its
patterns, and prints each one as a path relative to the workspace root. The root pattern, which
covers every file, prints as .. An empty list prints nothing, and means no file of the
working-copy commit is on disk.
The command is cmd_sparse_list, sixteen lines. The
patterns it shows are changed by its siblings
jj sparse set,
jj sparse edit and
jj sparse reset; the
working-copy page explains what they control.
1. Command-line surface
No arguments or flags (SparseListArgs {}). The help
text: "List the patterns that are currently present in the working copy", adding that a newly
cloned or initialized repo has one pattern matching all files from the repo root, rendered as
. (source).
2. Configuration
None of its own. There is no template and no sort or format option: each line is the pattern's
path, nothing more (source). The command doesn't ask for a
pager. The patterns themselves are workspace state, not configuration: the
sparse_patterns field (3) of the TreeState message in
.jj/working_copy/tree_state (see
protobufs), so each workspace of a
repo has its own list.
3. End-to-end flow
LocalWorkingCopy implements the trait method as
self.tree_state()?.sparse_patterns(), which
returns the vector TreeState keeps (source).
The same vector backs the PrefixMatcher that
decides which files are checked out and snapshotted.
4. Core architecture touchpoints
| Structure | Read / write | How | Explained on |
|---|---|---|---|
Sparse patterns (TreeState) | read | The only thing the command itself reads (source). | working-copy |
tree_state file | read | Decoded whole, though only one field is shown (source). | protobufs |
| Working-copy commit, repo view | loaded | By the shared lifecycle, for the snapshot; the command doesn't use them. | cli |
| Files on disk, operation log | untouched | Apart from a snapshot, which happens before the command runs. | operations |
5. What it reads, and snapshotting
- No transaction, no lock, no operation of its own (source).
- Snapshot:
workspace_helpersnapshots the working copy first and prints the snapshot stats (source). A snapshot never changes the patterns, so it can't change the output. - Per workspace. The list belongs to the workspace you run in. A new workspace gets
the current one's list when created with
jj workspace add --sparse-patterns copy, which reads it through the same trait method (source; seeworkspace add). jj undohas nothing to revert, except the snapshot if one was taken. Pattern changes aren't operations either, sojj undodoesn't bring back an earlier list.
6. Algorithm and invariants
The loop is a straight print (source). Each pattern is a
RepoPathBuf, a workspace-relative path stored with / separators. It is
rendered with to_fs_path_unchecked against an empty
base, so the output is workspace-relative even when you run the command from a subdirectory, and uses
the platform's separator. The root has no components, which would give an empty string, so it is
rendered as .. The function's doc comment reserves it for display, which is all this is.
The order is the stored order. The writers keep it sorted: sparse set collects the new
list in a HashSet and sorts it
(source), and sparse edit
sorts and removes duplicates (source).
So the output is sorted and has no repeats, but list itself doesn't enforce either.
Invariants: nothing is written by the command. A pattern is a path prefix, not a glob:
lib covers lib/a.rs and lib/x/b.rs. Prefixes can overlap
(. with lib, say); the list shows them as stored.
7. Errors and edge cases
| Message | When | Source |
|---|---|---|
| (no output) | The list is empty, for example after jj sparse set --clear. Not an error. | test |
. | The default: the root pattern, which a new working copy starts with. | local_working_copy.rs |
Failed to read working copy state, caused by Reading tree state from <path> or Decoding tree state from <path> | The tree_state file can't be read or isn't a valid message. | load, errors |
(prints .) | No tree_state file: jj creates an empty state with the root pattern and saves it. | load, init |
(prints .) | The state has no sparse_patterns field, which only a working copy older than the field lacks. | local_working_copy.rs |
A stored prefix that isn't a valid repo path is converted with unwrap(), so a corrupted
pattern would crash rather than report an error (source). The
writers only store valid paths, since sparse set parses its arguments as
workspace-relative repo paths.
8. Worked example
From upstream's test_sparse_manage_patterns, in a repo with
file1, file2 and file3. The later commands run from a
subdirectory sub/, to show that patterns are workspace-relative both ways.
$ jj sparse list
.
$ jj sparse set --remove .
Added 0 files, modified 0 files, removed 3 files
$ jj sparse list
$ cd sub
$ jj sparse set --add file2 --add file3
Added 2 files, modified 0 files, removed 0 files
$ jj sparse list
file2
file3
Sources: the default and the empty list (source), the list from
sub/ (source). The file2 above is the
root's file2, not sub/file2. After a jj sparse edit that leaves
file3, file2 and file3 in the editor, the list is again
file2, file3: sorted, one line each (source).