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
4. Core architecture touchpoints
| Piece | Role here |
|---|---|
ConfigEnv::repo_configs_root_dir | The directory that holds one subdirectory per repo config ID. |
ConfigEnv::workspace_configs_root_dir | The same for workspace config IDs. |
secure_config::read_metadata, metadata_path | Decode a subdirectory's metadata.binpb and return the repo or workspace path it records. |
ConfigMetadata | The protobuf message: an optional absolute path to the repo's .jj/repo (or a workspace's .jj) directory. |
secure_config::remove_config_dir | Deletes config.toml and metadata.binpb, then removes the directory without recursing. |
Ui::prompt_yes_no | The 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
| Situation | Result |
|---|---|
| No repos or workspaces config directory yet | Prints both headings, each with (none) (test). |
| Every recorded repo and workspace still exists | The same (none) output, no prompt (test). |
| Root cannot be checked or read | Failed to check PATH or Failed to read PATH (source). |
| Extra file in a config directory | The two known files are removed, the directory stays: Warning: Failed to delete PATH: … and Deleted 0 config directories. (test). |
| No user config directory | No 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).