In short: without --name, jj prints the root of the workspace it found when it started, without
loading the repo. With --name, it loads the repo without snapshotting, checks that the name is
one of the view's workspaces, and reads that workspace's recorded path from
.jj/repo/workspace_store/index. A missing record is an error; a recorded path that no longer
exists is only a warning, and the path is still printed.
The command is cmd_workspace_root. The help text:
"Show the workspace root directory" (source). It is the
Root(WorkspaceRootArgs) variant of WorkspaceCommand
(source, dispatch). To see every
workspace's root at once, use jj workspace list.
1. Command-line surface
| Flag | Meaning |
|---|---|
--name NAME | Name of the workspace; the current one if absent (source). Shell completion offers workspace names, which it gets by running jj workspace list with its own template (source). |
-R chooses which workspace is "current". --at-op matters only with
--name: it picks the view whose workspace names are checked. The path itself comes from the
workspace store, which is not versioned by operation.
The global flags are on the CLI page.
2. Configuration
None. The output is the path's bytes and a newline, with no template and no colour (source).
3. End-to-end flow
4. Core architecture touchpoints
| Piece | Role here |
|---|---|
workspace_loader() | The loader for the workspace found at startup by searching up from the current directory (or given by -R); its workspace_root() is the answer without --name. See the jj root page. |
View::wc_commit_ids | The list of workspaces the repo knows about; --name must be a key in it. See the view page. |
SimpleWorkspaceStore | The map from workspace name to root path, kept in .jj/repo/workspace_store/index. jj workspace add writes an entry, remove deletes it (source) and rename moves it (source). forget deliberately leaves it, so that jj undo can point the workspace back at its directory (source). |
5. What it reads, and snapshotting
It never snapshots. Without --name it reads nothing beyond what startup already found: the
repo is not loaded. With --name it
calls workspace_helper_no_snapshot, which loads the
repo at the head operation (or --at-op) to read the view, then reads the workspace store index
and checks whether the path exists. It starts no transaction and writes nothing.
6. Algorithm and invariants
The current workspace
command.workspace_loader()?.workspace_root() (source), the
same call jj root makes; the two commands print the same thing. From a subdirectory or a
secondary workspace, the answer is that workspace's own root (test).
A named workspace
The name must be in the loaded view's wc_commit_ids, else "No such workspace"
(source, error). Then the
workspace store gives the recorded path, joined to the repo directory and normalized
(source). Two checks are kept separate: being in the view
decides whether the workspace exists, and the store only says where it lives. That matters because a forgotten workspace keeps its store entry: without the view check, its old path would still be printed.
A path that is gone
If the recorded path does not exist, jj prints "Cannot access workspace path" as a warning and still
prints the path (source). This is the strict check that
jj workspace list's root keyword leaves out: upstream's comment there points
here for it.
7. Errors and edge cases
| Situation | Result |
|---|---|
| Name not in the view | Error: No such workspace: <name>, including a workspace's old name after a rename (test). |
| Workspace created before the workspace store existed | Error: Workspace has no recorded path: <name> (source, test). |
Workspace restored by jj undo after jj workspace remove | Also "no recorded path": remove deleted the store entry, which undo does not restore. Forget it and add it again (test). |
| Recorded directory deleted | Warning on stderr, path on stdout, exit 0 (test). |
| Path not valid as bytes on this platform | A user error from path_to_bytes (source). |
| Not in a workspace | As for jj root. |
8. Example output
From upstream's tests, with workspaces at $TEST_ENV/main and $TEST_ENV/secondary
($TEST_ENV is the test's temporary directory;
source, source):
main/subdir$ jj workspace root
$TEST_ENV/main
main$ jj workspace root --name secondary
$TEST_ENV/secondary
main$ rm -r ../secondary
main$ jj workspace root --name secondary
Warning: Cannot access workspace path: $TEST_ENV/secondary
$TEST_ENV/secondary