jj / How jj config gc works

How jj config gc works

jj config gc lists per-repo and per-workspace config directories whose repo or workspace no longer exists, and deletes them if you confirm.

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. Finding missing repos and workspaces
  8. Confirming
  9. Deleting
  10. 7. Errors and edge cases
  11. 8. Example output

In short: repo and workspace config live outside the repo, in one directory per repo or workspace under your config directory, next to a metadata file that records its path. When a repo or workspace is deleted, its directory is left behind. This command scans both sets of directories, keeps the ones whose recorded path is gone, prints them in two lists, and asks once before deleting them all. The answer defaults to no. It never loads a repo and never snapshots.

The command is cmd_config_gc. Its help text: "Find and optionally delete repo and workspace config directories whose paths no longer exist." (source). It is the Gc variant of ConfigCommand (source, dispatch).

1. Command-line surface

It takes no arguments of its own: ConfigGcArgs is empty (source). One limit is recorded upstream as a TODO: there is no path argument to restrict which repo paths are considered (source).

The global flags are on the CLI page.

2. Configuration

No config setting changes what it does. The directories it scans are jj/repos and jj/workspaces under the platform's user config directory (source, repos, workspaces, REPO_CONFIG_DIR, WORKSPACE_CONFIG_DIR), the same places config path --repo and --workspace point into. If there is no user config directory, the command fails with "No repo configs directory found" (source).

3. End-to-end flow

jj config gc: call flow The command finds the repos and workspaces config roots. find_configs_with_missing_paths runs on each, reading every subdirectory's metadata and keeping those whose recorded path does not exist. Both lists are printed. If together they are empty the command stops. Otherwise it asks once whether to delete them all, defaulting to no; no prints "Aborted; nothing was deleted." Yes removes each directory's two known files and then the directory, warning about any that fail, and prints how many were deleted. repo and workspace config roots <user config dir>/jj/repos and …/jj/workspaces find_configs_with_missing_paths × 2 read metadata; keep dirs whose path is gone print both lists config dir and its path, or "(none)", per list both empty: stop nothing to ask prompt "Delete N …?" (yN) default no, also without a terminal no: abort "Aborted; nothing was deleted." yes: remove_config_dir two known files, then a non-recursive rmdir "Deleted K config directories." a warning for each one that failed

4. Core architecture touchpoints

PieceRole here
ConfigEnv::repo_configs_root_dirThe directory that holds one subdirectory per repo config ID.
ConfigEnv::workspace_configs_root_dirThe same for workspace config IDs.
secure_config::read_metadata, metadata_pathDecode a subdirectory's metadata.binpb and return the repo or workspace path it records.
ConfigMetadataThe protobuf message: an optional absolute path to the repo's .jj/repo (or a workspace's .jj) directory.
secure_config::remove_config_dirDeletes config.toml and metadata.binpb, then removes the directory without recursing.
Ui::prompt_yes_noThe confirmation, with no as the default.

5. What it reads, and snapshotting

It reads the repos and workspaces config roots, each subdirectory's metadata file, and whether each recorded path exists (source). It never loads a repo or a working copy, so there is no snapshot. It writes nothing unless you answer yes, and then only deletes.

6. Algorithm and invariants

Finding missing repos and workspaces

The same function, find_configs_with_missing_paths, scans the repos root and then the workspaces root (source). If a root does not exist, its list is empty (source). Otherwise every entry is checked, and anything uncertain is kept rather than proposed for deletion: entries that are not directories, directories whose metadata cannot be read or decoded, and metadata with no path or a path that cannot be decoded are all skipped (source). A path whose existence cannot be checked, for example because of a permission error, counts as still existing (source). The result is sorted (source).

Confirming

The two lists are joined into one, and a single prompt covers both: "Delete N missing config directories?" (source). The prompt defaults to no. Without a terminal, the default is taken automatically, so a non-interactive run only reports (source, test).

Deleting

Each directory is removed by deleting its two known files, ignoring either one being absent, and then calling remove_dir, which fails if anything else is left inside. So a file you put there yourself is never deleted; the directory stays, with a warning (source, test). A failure on one directory does not stop the others, and the final count includes only those removed (source).

7. Errors and edge cases

SituationResult
No repos or workspaces config directory yetPrints both headings, each with (none) (test).
Every recorded repo and workspace still existsThe same (none) output, no prompt (test).
Root cannot be checked or readFailed to check PATH or Failed to read PATH (source).
Extra file in a config directoryThe two known files are removed, the directory stays: Warning: Failed to delete PATH: … and Deleted 0 config directories. (test).
No user config directoryNo repo configs directory found (source).

8. Example output

From upstream's test, after the repo at $TEST_ENV/repo and its second workspace at $TEST_ENV/secondary (which had workspace config set) were deleted and y was typed at the prompt (source):

$ jj config gc
Missing repo configs (repo path no longer exists):
  $TEST_ENV/home/.config/jj/repos/8e4fac809cbb3b162c95
    repo path: $TEST_ENV/repo/.jj/repo
Missing workspace configs (workspace path no longer exists):
  $TEST_ENV/home/.config/jj/workspaces/d043564ef93650b06a70
    workspace path: $TEST_ENV/secondary/.jj
Delete 2 missing config directories? (yN): Deleted 2 config directories.

The typed answer comes from stdin, so it does not appear in the captured stderr.

Without a terminal a similar run answers n and prints Aborted; nothing was deleted. (test).