In short: jj loads the workspace, which snapshots it as usual, and locks the working copy. It writes
the current patterns to a temporary .jjsparse file, runs ui.editor, then
parses each non-blank line that doesn't start with JJ: as a workspace-relative path.
The result is sorted and de-duplicated. From there it is exactly
jj sparse set: update the files,
save the working-copy state under the same operation ID, and print the checkout stats.
The command is cmd_sparse_edit; the editing is
edit_sparse. The update itself is the shared
update_sparse_patterns_with, described in detail on
the sparse set page.
1. Command-line surface
No arguments or flags (SparseEditArgs). The global
--config ui.editor=… picks the editor for one run.
2. Configuration
| Key | Default | Effect |
|---|---|---|
ui.editor | nano on Unix, Notepad on Windows | The editor that opens the file, loaded before the working copy is locked (source, text_editor, default). $VISUAL or $EDITOR set it below your own config, and $JJ_EDITOR overrides it (source, override). |
The patterns themselves live in the workspace's working-copy state, the sparse_patterns
field of TreeState (see protobufs).
3. End-to-end flow
4. Core architecture touchpoints
| Structure | Read / write | How | Explained on |
|---|---|---|---|
Sparse patterns (TreeState) | read, write | Shown in the editor, then replaced by the edited list (source). | working-copy |
| Files on disk, file states | write | Created or deleted for prefixes whose inclusion changed. | working-copy |
| Temporary file | written, read, deleted | In the system temp directory, named editor-… with suffix .jjsparse; deleted only if editing succeeded (source). | — |
| Working-copy commit | read | Source of the checked-out files; never rewritten. | trees |
| Operation log | untouched | Saved under the existing operation ID. | operations |
5. Transaction and operation
- Transaction and operation: none. The working copy is locked while the editor is open and saved with
old_operation_id()(source). - Lock held during editing: because the editor runs inside the closure, the working-copy lock is held until you close the editor.
- On error (bad line, editor failure) nothing is written: the closure returns before
set_sparse_patternsruns (source). jj undodoesn't apply. Edit again or runjj sparse reset.
6. Algorithm and invariants
-
Render. Each stored pattern is turned into a workspace-relative filesystem path and
written on its own line. An invalid stored path doesn't block editing, but one that isn't UTF-8 is an
internal error (source). Upstream's test shows the root pattern
written as
.(source). -
Edit.
TextEditor::edit_strwrites the temporary file, runs the editor, and reads it back; errors are labelledsparse patterns(source, edit_str). -
Parse. Lines starting with
JJ:are dropped, the rest are trimmed and blank ones skipped, and each is parsed withRepoPathBuf::from_relative_path. The first failure aborts withFailed to parse sparse pattern: <line>(source). - Normalize. Sort and remove duplicates (source).
- Apply. As in
sparse set: check out added prefixes, delete removed ones, store the list.
Invariants: the saved list is sorted and has no duplicates. Saving an empty file leaves no patterns, so every tracked file is removed from disk. Commits never change.
7. Errors and edge cases
| Message | When | Source |
|---|---|---|
Failed to parse sparse pattern: <line>, caused by Invalid component "." in repo-relative path "./file1" (or ..) | A line isn't a clean workspace-relative path. . on its own is fine. | edit.rs, test |
Editor errors, labelled sparse patterns | The editor couldn't be run or exited with an error. | edit.rs |
Stored sparse path is not valid utf-8: … (internal error) | A stored pattern can't be shown as text. | edit.rs |
Failed to update working copy paths (internal error) | Writing or deleting files failed. | mod.rs |
This command must be able to update the working copy. | Run with --at-op, --ignore-working-copy or --no-integrate-operation. | cli_util.rs |
Concurrent working copy operation. Try again. | The working copy changed between loading and locking. | cli_util.rs |
8. Worked example
From upstream's test_sparse_manage_patterns, after
jj sparse reset, so the patterns are . and file1,
file2 and file3 are all on disk. The fake editor records what it was given
and writes new content:
Upstream checks both outputs and the editor's input, and then that a saved line of
./file1 fails (source):
Error: Failed to parse sparse pattern: ./file1
Caused by: Invalid component "." in repo-relative path "./file1"