on master help sign in
j/specs/main.md
2606 lines 138 kB history raw
1# j — specification
3`j` is a command-line interface to Jujutsu (jj) repositories. It is an
4interpreter for a small, pure, dynamically typed functional language. A
5repository is a value in that language; every command is an expression that
6maps the current repository value to a new one, or to something to print.
8Nothing is implicit beyond the language itself. Every shape, builtin, and
9command is declared or defined in one user-owned file, `~/.config/j/config.j`,
10written in the language. The binary provides the language (its syntax, its
11operators and their fixities, its primitive kinds), the implementations of the
12declared builtins, eleven reserved words, and the bridge to jj repositories.
13`j` does not require the `jj` binary; it uses jj's on-disk formats through
14jj-lib.
16This document is the complete specification for implementing `j`. Section 9 is
17the reference `config.j`; it is part of the specification and ships with the
18binary.
20---
22## 1. Invocation
24```
25j EXPRESSION…
26echo EXPRESSION | j
27```
29`j` takes the expression from its arguments or from standard input.
311. If standard input is not a terminal and contains at least one byte, the
32 expression is the entire content of standard input.
332. Otherwise the expression is the arguments joined with single spaces,
34 verbatim. Nothing is quoted or wrapped on the user's behalf: a `Text` is
35 a text only if it is quoted in the language, so a message is written
36 `j 'describe "fix login"'` (or `j describe '"fix"'`), while `j new` is
37 `new` and `j tree . squash` is `tree . squash`. Shell quoting is needed
38 only for characters the shell owns: double quotes, parentheses, brackets,
39 braces, a backslash, `<` `>` `|` `&` `;` `*` `$`. The operators `++`,
40 `::`, `or`, `.`, and the literals `%name`, `@id`, `./a/b` are all safe
41 unquoted.
423. If arguments are present and rule 1 also applies, exit 2 with
43 `j: expression given both as arguments and on stdin`. One byte is
44 sufficient to reject the invocation; the pipe need not reach EOF.
454. If neither is present, or the input is only whitespace, print a concise
46 usage and getting-started guide to stderr and exit 2. The guide points to
47 `j help`, `j commands`, and commands for starting or inspecting a repository.
48 It does not read or create configuration or open a repository.
495. `--help` and `-h` as the first word alias `help` (§1.1). A separate
50 argument equal to either flag after the first argument requests help for
51 the first word, before repository access or evaluation: `j abandon --help`
52 is `j help abandon`. An initial `help`, `--help`, or `-h` followed by
53 another help flag opens general help. Other flags are not supported.
54 Language comments embedded within a single argument or stdin are unchanged:
55 `j 'new --help'` executes `new`, and `j '"--help"'` prints text.
566. The expression is text: an argument that is not valid UTF-8 is a usage
57 error (exit 2) naming it, and so is an expression on standard input that
58 is not.
60### 1.1 Reserved commands
62Before the expression is parsed, its text is trimmed of leading and trailing
63whitespace and split on whitespace into words. If the first word is one of the
64eleven reserved words below, the whole text is a reserved command. A first word
65of `--help` or `-h` is treated as `help`.
67| command | operation |
68|---|---|
69| `help [NAME]` | show the command guide, or help for a reserved command or config name; §1.1.1 |
70| `commands [QUERY]` | show common tasks, search the vocabulary, or use `all` for the full catalog; §1.1.1 |
71| `setup [NAME EMAIL]` | create the complete reference configuration, optionally setting identity; §6.1.1 |
72| `init` | create a repository in the current directory; §7.8 |
73| `clone URL [DIR]` | clone `URL` into `DIR` (default: the repository's name in `URL`); §7.8 |
74| `remote URL` | set the URL of the remote `origin`, creating it if absent; §7.8 |
75| `fetch` | fetch from `origin`; §7.6 |
76| `push EXPR` | set or delete the remote bookmarks that `EXPR` selects; §7.6 |
77| `undo` | restore the repository as it was before the newest operation; §7.7 |
78| `redo` | reverse the newest undo; §7.7 |
79| `ops` | print the operation log; §7.7 |
81For every reserved command except `push` and `commands`, the remaining words
82are literal arguments, and the language is not involved. When the first
83shell argument is the command name, the remaining shell argument boundaries
84are preserved, so `j clone '/path/to/source repo' 'my project'` accepts both
85paths. A command supplied as one string or on stdin is split on whitespace;
86it has no additional quote or escape syntax. A wrong argument count is a
87usage error (exit 2). `commands` takes the remaining
88trimmed text as its optional search query, including spaces. For `push`, the
89remainder of the text is an expression, evaluated as in §1.2 steps 2–7 but
90against the repository as recorded, without snapshotting the working directory;
91its value must be a list of push records (§7.6).
93Matching is on the first word only, so an expression whose first token is one
94of these words cannot be written on the command line. `(push)` or `x fetch`
95are ordinary expressions. `config.j` may define functions with these names;
96they are reachable only inside larger expressions.
98#### 1.1.1 Help and command discovery
100`help` without a name prints a getting-started guide to stdout: repository
101setup, common commands grouped by task, examples, expression quoting and
102composition, dry runs, and how to find more commands. `help NAME` prints help
103for that reserved command or for a name in the current configuration, including
104its signature when present and available documentation. `--help [NAME]` and
105`-h [NAME]` are equivalent to `help [NAME]`. These successful requests exit 0.
106An unknown name is a usage error (exit 2) with guidance to use `j commands`.
107`j help config` is a built-in topic showing the configuration path, identity
108setup, and repair instructions. It is available even with invalid configuration.
110`commands` shows a concise catalog of common tasks and their commands.
111`commands all` lists the reserved commands and vocabulary actually declared
112or defined in the current configuration, including custom definitions without
113signatures. The concise catalog includes a bounded selection of custom
114definitions and points to the full list. `commands QUERY` searches the catalog case-insensitively by name,
115signature, documentation comments, and common task synonyms such as `commit`,
116`checkout`, and `branch`, ranking direct matches and everyday commands first.
117The `stash` query explains the save/new workflow when no custom `stash`
118definition exists. The catalog does not present an
119undeclared builtin as available merely because the binary implements it.
121General help and help for reserved commands do not depend on configuration and
122remain available if it is unreadable or invalid. Discovery of configuration
123names reads the configured file (§6.1) without creating or modifying it. If the
124file is missing, it uses the embedded reference configuration; other read or
125parse errors exit 3 rather than silently substituting a different catalog.
126The config is never evaluated for discovery, so its definitions can refer to
127repository state without preventing their documentation from being read.
129Neither command locates or opens a repository, takes a repository lock,
130resolves commit ids, snapshots the working directory, or records operations.
132### 1.2 Evaluating the expression
1341. Locate the repository (§7.1). If none, exit 2.
1352. Parse the expression (§3). On parse error, exit 3.
1363. Load and validate `config.j` (§6), except for its `Id` literals. If it is
137 missing, create the reference configuration (§6.1); if loading or
138 validation fails, exit 3.
1394. Build the current repository value `r` (§7.2). This includes snapshotting
140 the working directory into the focused commit (§7.4).
1415. Resolve every `Id` literal in `config.j` and in the expression (§4.10).
142 A failure in `config.j` is a configuration error (exit 3); one in the
143 expression is a crash (exit 1). Nothing has been evaluated.
1446. Evaluate `config.j`'s definitions (§4.1), then the expression, to a value
145 `v`.
1467. If `v` is a function, apply it to `r`, once, and let `v` be the result.
1478. If `v` is a `Repo` (§4.4): if it equals the repository value *as loaded,
148 before the snapshot of §7.4*, do nothing at all; otherwise persist it
149 (§7.5) and check out its focused commit's files (§7.4). Print nothing to stdout;
150 interactive stderr reports the outcome and focus (§1.5).
151 Exit 0.
1529. Otherwise display `v` (§5.1) on stdout. Persist nothing. Exit 0.
154If evaluation crashes (§4.7) at any point, print the crash message to stderr,
155persist nothing, leave the working directory untouched, and exit 1.
157Step 7 applies exactly once. If the result of applying a function to `r` is
158again a function, that function is displayed, not applied again.
160Step 8's equality test means `j save` (the reference alias for `id`) is a no-op when the working directory is
161unchanged and records it when it is not: the snapshot makes `r` differ from
162the loaded value, and that difference is what gets persisted. The test may be
163implemented by comparing commit and tree hashes rather than values.
165Two consequences worth knowing:
167- **Dry run.** A `Text` result is displayed and persists nothing, and `.`
168 composes a renderer after an edit, so `j tree . rebase trunk` shows
169 what a rebase would produce without doing it. `validate` in the chain,
170 `j tree . validate . rebase trunk`, additionally raises whatever
171 persistence would refuse, so the preview is of something that could
172 actually be persisted. The reference `preview EDIT` is the convenient
173 form of `tree . validate . EDIT`: `j 'preview (rebase trunk)'`. Validation
174 alone returns a `Repo`, so `validate . EDIT` persists a changed result.
175- **Do, then look.** `j squash` reports the resulting focus on an interactive
176 terminal. `j squash && j tree` displays the whole tree; there is no flag for it.
178### 1.3 Interrupts
180There is no timeout. A non-terminating expression runs until interrupted.
181Interrupting `j` (SIGINT) kills it, as SIGTERM, SIGHUP and SIGQUIT do.
182Nothing is written until the operation is recorded (§7.5 step 7), so a run
183interrupted before then persists nothing and leaves the working directory
184untouched. From the recording until the focus is checked out and the
185working copy's state is saved, those four signals wait: the checkout
186completes, the run reports what it did, and then the signal takes effect as
187it would have. A run that ends in that window regardless (SIGKILL, a crash,
188a power loss) leaves the operation recorded and the working directory
189partly updated, as a checkout that fails does: the next run carries on from
190there (§7.4), and `j undo` goes back.
192`clone` (§7.8) writes its directory from the start, so it holds the four
193signals off from creating it. One that comes while it creates the
194repository, fetches and imports lets the step in progress end (the git it
195runs, which a Ctrl-C at the terminal stops too), then fails the clone, which
196removes what it made, and then takes effect; one that comes later, once it
197makes the working-copy commit, waits for the clone to complete. A signal `j`
198was started ignoring (`nohup`, a background job) stays ignored, by the git
199it runs too.
201### 1.4 Exit status
203| status | meaning |
204|---|---|
205| 0 | success |
206| 1 | the expression crashed, or a reserved command was refused |
207| 2 | usage error: bad arguments, no repository, unsupported repository (§7.2), another `j` running (§7.7) |
208| 3 | configuration or parse error |
210If standard output is a pipe whose reader has exited (`j tree | head -1`), the
211rest of the output is dropped and `j` exits 0; any other failure to write
212output is an error, status 1. A message that cannot be written to stderr, for
213whatever reason, is dropped and the run keeps its status:
214`j 'crash "boom"' 2>&1 | true` still exits 1.
216Errors are written to stderr as a single line beginning with `j: `. Crash
217messages are the text given to `crash` (or generated by the interpreter),
218prefixed with `j: crash: `, followed on a second line by the innermost base
219definition that was executing and the top-level expression. A definition is
220executing while the body of its lambda runs, whether it has a signature or
221not, and one with a signature also while its value runs when that is a
222builtin (`squash`) and while an argument or result of it is checked (§4.13),
223so `describe 3` is in `describe`. A lambda's body is its own definition's
224under any other name: `prev = goto parents` runs goto's body, so `prev . top`
225is in `goto`. A builtin is not a definition, so a crash in one is in
226whichever definition applied it, and with none executing the line is only
227` from <expression>`.
229### 1.5 Terminal presentation
231Automatic colors are used only on a terminal, and disabled by `TERM=dumb`
232or a nonempty `NO_COLOR`. Diagnostics use the stderr terminal; displayed
233values use stdout. Error prefixes are bright red, informational prefixes
234bright cyan, and interactive successful commands have a green checkmark.
235Color adds emphasis without replacing the text of errors or values.
236Successful edits report `Saved changes` or `No changes`, followed by the
237resulting focus's copyable, unique `@` prefix and first description line
238(`(no description)` when empty). Setup reports the effective author identity.
239Undo and redo identify the affected operation and restored focus.
240After a saved edit, conflicts newly introduced anywhere in the history and
241conflicts in the checked-out focus produce a warning with counts, paths, and
242resolution guidance. This warning remains visible when output is redirected;
243the operation still succeeds. Guidance identifies `j conflicts`, editing
244conflict markers, recording the resolution with `j save` or `j id`, and
245checking again. For another commit, navigate with `by` first.
247When both stdout and stderr are capable terminals, repository operations,
248configuration evaluation, and expression evaluation (including implicit application)
249may show a temporary, color-cycling progress line on stderr. It starts after
250140 ms, advances every 75 ms, and names the current operation alongside a
251spinner, a bouncing activity bar, and elapsed time since that operation began.
252The bar is indeterminate and does not estimate completion. Each frame fits
253the current stderr terminal width with a spare column, omitting the bar and
254then the time before truncating the operation's name by display width. The
255line is cleared before the command reports its result.
256Fast operations never wait for a progress frame. It does not hide
257the cursor or change terminal modes. Signal behavior remains as in §1.3.
258Before an external renderer inherits stderr, progress is cleared and stopped
259for the remainder of the run so even an unterminated diagnostic stays visible.
261Colored multiline output is revealed in at most seven batches, with at
262most 96 ms of total pacing. Its bytes and row order are unchanged. Plain
263text is written directly. `J_ANIMATIONS=never` (also `off`, `false`, or `0`,
264case-insensitive) disables all motion while retaining colors. Motion is
265also disabled by nonempty `NO_COLOR` or `CI`, `TERM=dumb`, or either output
266stream being redirected. Success messages are omitted only when `CI` is
267nonempty or either output stream is redirected. `NO_COLOR` and `TERM=dumb`
268retain plain-text success messages on terminals; `J_ANIMATIONS` alone does
269not suppress them.
270Broken pipes and failed writes keep the behavior in §1.4.
272---
274## 2. Values
276The language has these kinds of values. The primitive kinds are part of the
277language and are not declared anywhere.
279| kind | notes |
280|---|---|
281| `Int` | arbitrary-precision integer |
282| `Text` | Unicode string |
283| `Bool` | `true` or `false` |
284| list | finite, ordered, homogeneous by convention, `[a b c]` |
285| record | unordered set of named fields, `{ a = 1, b = "x" }` |
286| function | closure, builtin, or partial application |
287| `Id` | opaque: a jj change id. Literal `@kpqx` for an existing one (a unique prefix is enough); bare `@` for a new one (§4.10) |
288| `Blob` | opaque: the content of one file, resolved or unresolved |
289| `Shape` | a type name used as a value (§4.12) |
291Records are structural. A record is not declared; it is whatever fields it
292has. The shapes in `config.j` name field sets, and a record *is* a `Commit`,
293say, exactly when its field set is `Commit`'s (§4.12). Two records are the
294same value if they have the same field names with equal values.
296---
298## 3. Syntax
300### 3.1 Lexical structure
302- **Comments.** `--` to end of line. `{-` … `-}`, nesting. A comment is
303 whitespace: a block comment ends a line (§3.3) only by containing a line break.
304- **Identifiers.** `[a-z_][A-Za-z0-9_']*`. Keywords are excluded:
305 `let in if then else or true false`.
306- **Type names.** `[A-Z][A-Za-z0-9_]*`. Declared as shapes in `config.j`;
307 usable in expressions as values (§4.12).
308- **Integer literals.** `[0-9]+`. There is no unary minus; write `0 - 1`.
309- **Text literals.** `"…"` or `'…'` with escapes `\"`, `\'`, `\\`, `\n`,
310 `\t`, `\r`. The closing quote matches the opening one, so a single-quoted
311 literal may contain unescaped `"` and a double-quoted one unescaped `'`.
312- **Id literals.** `@` immediately followed by one or more of the letters
313 `k`–`z` (jj's change-id alphabet), e.g. `@wqzt`: an existing id, given in
314 full or by a unique prefix.
315- **New id.** `@` followed by anything other than an identifier character
316 is the token `NEWID`. `@` followed by an identifier character outside
317 `k`–`z` (`@main`) is a lexical error.
318- **Label literals.** `%` immediately followed by a git branch name
319 (`[A-Za-z0-9._/-]+`, not starting with `.` or `-`, not containing `..`,
320 not ending in `/` or `.lock`), e.g. `%main`.
321- **Path literals.** `./` at the start of a token, extending to the next
322 whitespace or one of `( ) [ ] { } , ;`: `./src/lexer.rs`. This rule runs
323 before the selector and operator rules for `.`, so a `.` inside a path is
324 part of the path. The literal denotes the list of components after the
325 `./`; a trailing `/` is ignored and a bare `./` is `[]`, the root. Names
326 the literal cannot spell are built with `splitOn "/"`.
327- **Operators.** Exactly these tokens, and no others (§3.2):
328 `. * + - ++ :: == /= < <= > >= && ||`, plus the keyword
329 `or`, which is an operator syntactically.
330- **Selector.** A `.` immediately followed (no whitespace) by an identifier is a
331 single selector token `.name`. Any other `.` is the operator `.`.
332- **Punctuation.** `( ) [ ] { } , ; : \ = -> _`. The colon `:` is punctuation:
333 it separates a name from its type in declarations and record types, and
334 appears nowhere else.
336### 3.2 Operators and fixities
338The operator set and its fixities are part of the language. No others exist
339and none can be declared.
341```
342infixr 9 .
343infixl 7 *
344infixl 6 + -
345infixr 5 ++ ::
346infix 4 == /= < <= > >=
347infixr 3 &&
348infixr 2 ||
349infixl 0 or
350```
352Non-associative (`infix`) operators cannot be chained. Each symbolic operator
353is still a builtin that must be declared in `config.j` to be usable (§6.2);
354the table fixes how they parse, not whether they are in scope. `or` is a
355keyword and is always available.
357### 3.3 Layout
359Three layout rules and nothing else.
3611. **Top level.** A top-level item begins with a token in column 1. Every
362 following line whose first token is in a column greater than 1 continues
363 the item. Blank and comment-only lines are ignored.
3642. **`let` blocks.** After `let`, the column of the first token opens a block.
365 A subsequent line whose first token is in exactly that column begins a new
366 binding; a line indented further continues the current binding; the block
367 ends at `in` or at the first token in a smaller column. An `in` that begins
368 a line obeys the enclosing layout like any other token: in an item it must
369 be past column 1, and in an outer block's binding past that block's column.
370 Bindings on a single line are separated by `;`. Blank and comment-only
371 lines are ignored here too.
3723. **Selectors and updates.** A `SELECTOR` or `{` that is the first token of
373 a line never selects from or updates what precedes it. On a continuation
374 line it begins a new `postfix` (§3.4), which after another `postfix` is
375 the next application argument or list element: `r` followed by a line
376 ` .a` is `r (.a)`, and followed by ` { a = 2 }` it is `r ({ a = 2 })`.
377 So `r.a` and `r { a = 2 }` need the `.a` or `{` on the line `r` ends on.
378 `show` relies on this to break a list of records one per line with nothing
379 between them (§5.2).
381An expression given on the command line or on stdin is a single `expr`, not a
382list of items, so rule 1 does not apply to it; rules 2 and 3 do.
384### 3.4 Grammar
386```
387config := item*
388item := typedecl | signature | definition
390typedecl := TYPENAME '=' type
391signature := (ident | '(' op ')') ':' type
392definition := ident '=' expr
394type := atype ('->' type)?
395atype := TYPENAME | ident | '[' type ']' | '{' (ident ':' type (',' ident ':' type)*)? '}' | '(' type ')'
397pattern := ident | '_'
399expr := '\' pattern+ '->' expr
400 | 'if' expr 'then' expr 'else' expr
401 | 'let' bindings 'in' expr
402 | opexpr
403bindings := binding ((NEWLINE|';') binding)*
404binding := ident '=' expr
406opexpr := app (op app)* -- resolved by the fixity table
407app := postfix+ -- juxtaposition; left-associative
408postfix := atom ( SELECTOR | '{' fields '}' )* -- no SELECTOR or '{' after a line break (§3.3)
409atom := ident | TYPENAME | INT | TEXT | IDLIT | NEWID | LABELLIT | PATHLIT | 'true' | 'false'
410 | '(' expr ')' | '(' op ')' | '(' op expr ')' | '(' expr op ')'
411 | '[' postfix* ']'
412 | '{' fields '}'
413 | SELECTOR
414fields := (ident '=' expr (',' ident '=' expr)*)?
415```
417Notes:
419- A definition binds a name to a value. Functions are values made with `\`;
420 there is no separate function-definition syntax. `\x y -> e` takes two
421 parameters.
422- A signature immediately preceding a definition of the same name (blank
423 lines and comments between are fine) documents and checks that definition
424 (§4.13). A signature with no definition declares a builtin. At most one
425 signature per name.
426- `(op e)` is a right section (`\x -> x op e`), `(e op)` a left section
427 (`\x -> e op x`), `(op)` the operator as a function.
428- A bare `SELECTOR` atom `.name` is the accessor function `\x -> x.name`.
429- `postfix` binds tighter than application, as in Haskell: `f r { a = 1 }`
430 is `f (r { a = 1 })`. Consequently a record *literal* passed as an argument
431 after another atom must be parenthesised: `attach ({ root = c, children = [] }) r`.
432- List elements are separated by whitespace, not commas, and each element is
433 a `postfix` (an atom with selectors and updates): `[1 2 3]`,
434 `["src" "lexer.rs"]`, `[{ root = c, children = [] }]`. An application or
435 operator expression as an element is parenthesised: `[(up repo).root.id]`.
436 So is a record literal after another element, `[({ a = 1 }) ({ a = 2 })]`:
437 `[{ a = 1 } { a = 2 }]` is the one-element list `[{ a = 2 }]`, the first
438 record updated by the second. Records keep commas.
439- Lambda, `if`, `let`, and `or` extend as far right as possible.
440- Patterns are variables and `_` only. No literal, list, or record patterns.
441- Nesting is bounded: an expression more than 40,000 levels deep is a parse
442 error (§1.4), never a stack overflow. A name, literal, `(op)` or `.name`
443 accessor is one level; a parenthesis or section, and the braces of a record
444 or update, are two levels above what they enclose; every other construct
445 is one level above its highest part. A chain `a + b + c …`, `f x y …` or
446 `r.a.b …` is thus one level deeper per link, as are right-associative
447 operators, `or`, and `\`/`if`/`let` bodies. Lists nest 40,000 deep,
448 parentheses and records about 20,000, and a `Subtree` as `show` renders it
449 (§5.2) about 13,000: three levels a commit, the braces of its record and
450 the list around them, as a list broken over lines holds records without
451 parentheses (§3.3). A type in `config.j` is bounded the same way: one
452 level, plus one for each bracket, parenthesis, field or `->` around it.
454---
456## 4. Semantics
458### 4.1 Evaluation
460Strict, call by value, left to right. Function application is curried. All
461top-level definitions in `config.j` and all bindings of one `let` block are
462mutually recursive. A top-level definition is evaluated once, at load, in
463dependency order: a definition is evaluated after every definition its body
464refers to outside a lambda. A cycle among such references (two non-lambda
465definitions each needing the other's value) is a configuration error;
466references inside lambda bodies never form cycles, since a lambda is a value
467before it is applied. The bindings of a `let` block are evaluated by the same
468rule, with a cycle being a crash. A top-level definition is moreover evaluated
469after every definition that it reaches through a chain of references of
470either kind but that does not reach it back. Among definitions that do reach
471each other, one that refers to none of the others outside a lambda, and whose
472every lambda outside other lambdas that refers to one of them is stored, is
473evaluated before the rest, since it cannot apply their functions; an
474expression is stored when it is the whole definition, or a record field, list
475element, `if` branch or `let` body of a stored expression. So a function
476applied at load finds the definitions its body refers to, save one that
477reaches back to the definition applying the function and is not evaluated
478before the rest; the order among the rest is otherwise unspecified. A `let`
479binding is ordered the same way among the bindings of its block. A lambda
480body is evaluated on each application.
481Recursion is unbounded; the interpreter must handle deep recursion without
482stack overflow (or turn exhaustion into a crash).
484### 4.2 Scoping
486Names resolve lexically: `let` bindings, then lambda parameters, then
487top-level definitions and declared builtins. Field names are not in any
488namespace; they occur only after `.`, in record literals, and in record
489updates, so a field may be called `id` while `id` remains the identity
490function.
492There is no shadowing. A `let` binding or lambda parameter may not use a name
493already bound in an enclosing scope, including top-level definitions and
494builtins (reserved whether or not declared, §6.2); in `config.j` that is a
495configuration error (exit 3), on the command line a parse error. A lambda's
496earlier parameters enclose its later ones, and all bindings of a `let` block
497enclose each of its expressions, since they are mutually recursive (§4.1), so
498`\x x -> x` and `let a = \b -> b; b = 2 in a 1` are errors too. The one
499exception is within `config.j`, whose binders may reuse the names of its own
500top-level definitions, as the reference config's `\files ->` and
501`\old new repo ->` do: within the binder's scope the name means the binder,
502for evaluation order (§4.1) as for lookup, so a `let` binding used before it
503is evaluated is a crash there as anywhere, never the definition. Defining a
504top-level name twice, or defining a name that is also a builtin, is a
505configuration error.
507### 4.3 Records
509- `e.f` selects field `f`; crashes if absent.
510- `e { f = v, … }` returns a copy with the listed fields replaced; crashes if
511 any listed field is absent. Update never adds fields.
512- Duplicate field names in a literal or update are a parse error.
514### 4.4 Which values are a `Repo`
516A value is treated as a `Repo` in §1.2 step 8 if and only if its shape is
517`Repo` and its `root`'s shape is `Commit`, in the sense of §4.12 (exact field
518sets). Deeper shape errors surface as crashes during persistence.
520### 4.5 Equality
522`==` is structural on ints, texts, bools, lists, and records; identity on
523`Id`; content-and-mode on `Blob`; on shapes, equal field sets or the same
524primitive kind. Comparing functions crashes. `/=` is its
525negation. Ordering operators are defined on `Int` only and crash otherwise.
527### 4.6 Special forms
529`if`, `or`, `&&`, and `||` do not evaluate all operands. `&&` and `||`
530short-circuit. The interpreter recognises `&&` and `||` by name; `or` is a
531keyword. Like other builtins, `&&` and `||` must be declared. Their contracts
532check each evaluated operand and the final result; a skipped operand is
533neither evaluated nor checked.
535`a or b` evaluates `a`. If that crashes, the crash is discarded and `b` is
536evaluated and returned. Otherwise, if the value of `a` is a function, `b` is
537evaluated too, and if it is also a function the result is the function
538`\x -> a x or b x`, with the same rule applying again to its result. In every
539other case the result is the value of `a` and `b` is not evaluated. The
540lifting is what makes `edit or id` mean "try the edit, keep the repository if
541it crashes": a function value cannot crash until it is applied, so without
542lifting the `or` would catch nothing.
544### 4.7 Crashes
546`crash msg` aborts evaluation with `msg`. Every runtime error the interpreter
547detects (unbound name, wrong kind of value, missing field, out-of-range index,
548`head []`, `concat []`, comparing functions, non-`Bool` condition, arity or
549kind errors in builtins) is a crash with an interpreter-generated message, and
550is catchable by `or` exactly like a user crash. Nothing else is catchable: parse
551and configuration errors, and `Id` literal resolution, happen before
552evaluation.
554### 4.8 Overloading
556Two builtins dispatch on the kind of an argument; functions compose with `.`:
558| builtin | list | Text | function |
559|---|---|---|---|
560| `++` | concatenation | concatenation | crash |
561| `concat` | flatten `[[a]] -> [a]` | join `[Text] -> Text` | crash |
563`concat []` crashes (there is nothing to dispatch on). `map`, `filter`,
564`length`, `null`, `head`, `tail`, `nth`, `take`, `drop`, `last`, `member`,
565`foldl`, and `::` are defined on lists only.
567### 4.9 Builtins
569The following table is normative for behaviour. Each builtin is available only
570if `config.j` declares it (§6.2); the declared type is enforced at each call
571as in §4.13.
573| name | behaviour |
574|---|---|
575| `.` | composition: `(f . g) x = f (g x)` |
576| `id` | identity |
577| `const` | `const a b = a` |
578| `crash` | §4.7 |
579| `==`, `/=` | §4.5 |
580| `&&`, `||`, `not` | booleans; `&&`/`||` short-circuit |
581| `+`, `-`, `*` | integer arithmetic |
582| `<`, `<=`, `>`, `>=` | integer comparison |
583| `show` | renders any value as text in literal syntax (§5.2) |
584| `::` | cons |
585| `map`, `filter` | as usual |
586| `length`, `null` | as usual |
587| `head`, `tail`, `last` | crash on empty |
588| `nth i xs` | 0-based; crash out of range |
589| `take n`, `drop n` | clamp to list length |
590| `member x xs` | membership by `==` |
591| `range a b` | `[a (a+1) … (b-1)]`, empty if `b <= a` |
592| `foldl f z xs` | left fold: `foldl f z [x y] = f (f z x) y`; `z` for `[]` |
593| `concat`, `++` | §4.8 |
594| `startsWith p t`, `endsWith s t` | text predicates |
595| `splitOn sep t` | the pieces of `t` between occurrences of `sep`; `splitOn "/" "a/b"` is `["a" "b"]`, `splitOn "/" ""` is `[""]` |
596| `replay onto ch` | replay the change `ch` (`{ from, to }`) onto the snapshot `onto`; §7.3 |
597| `unresolved b` | `true` iff the blob is a conflict |
598| `blob t` | a resolved regular-file blob with content `t` |
599| `blobHex kind hex` | a resolved blob of kind `"regular"`, `"executable"`, or `"symlink"`, with bytes decoded from an even-length hexadecimal text; accepts either letter case, crashes for an unknown kind or invalid hex |
600| `text b` | the content of a blob as text; for an unresolved blob, its conflict-marker rendering |
601| `by i repo` | the repo refocused on the commit with id `i`; crashes if absent. Backed by the change-id index; its reference definition is in §10 |
602| `lookupCommit i repo` | `(by i repo).root`, indexed once per repository value without constructing a location for each lookup. Duplicate ids select the first preorder match; malformed trees retain `by`'s traversal behavior |
603| `lookupContent p s` | `(head (filter (\e -> e.path == p) s)).content or blob ""`, with an index for ordinary paths. The full filter's errors and first-match behavior are preserved; the reference `contentAt` uses this builtin |
604| `subtreeCommits t` | every commit of the tree `t` (anything with `root` and `children`) in preorder, in time linear in its size: the value of `t.root :: (concat (map subtreeCommits t.children) or [])`. So it crashes only if `t` has no `root`, and a node whose `children` is not a list of values that have a `root` contributes only its own. The reference `commits` is this builtin (§9) |
605| `diff a b` | a unified diff from the text of `a` to the text of `b`, split into lines after each `\n` (not at a lone `\r`), no `---`/`+++` header lines, three lines of context, each hunk headed `@@ -s,n +s,n @@` with the first line and the number of lines it shows of each side, as `diff -u` writes it, a line that has no trailing newline followed by `\ No newline at end of file`; `""` if equal; crashes if either is not UTF-8 |
606| `difft p a b` | the output of difftastic comparing `a` to `b` as the file `p`, with a unified-diff fallback when the executable is absent; §7.10 |
607| `unrecorded repo` | paths changed between the invocation's loaded and snapshotted focus files; §7.4. Returns `[]` without snapshot context, including in a push expression |
608| `treeWith o r` | the history rendered as a tree with options record `o`; §7.11 |
609| `extract S v` | every subvalue of `v` that is an `S`; §4.12 |
610| `meta i` | `{ hash, author, email, time }` for the visible commit with change id `i`: its current git hash, author name and email, committer time. Crashes for an id with no stored commit (one minted in this program) |
611| `validate repo` | `repo` unchanged if persisting it would succeed; otherwise the crash persistence would raise (§7.5 steps 1–3, the root invariant of 4, and 6). A changed repository also checks the backend's author identity (§7.9). Persistence runs the same checks |
613### 4.10 Ids: existing and new
615**Existing.** An `Id` literal `@kpqx` denotes the existing commit whose id
616begins with `kpqx`. It is resolved before evaluation, not during it:
618- In the command-line expression, every literal is resolved after parsing and
619 before evaluation (§1.2 step 5), against the ids visible when the program
620 started. A literal that matches no id or more than one is a crash that lists
621 the candidates in commit-table form (§5.1); nothing is evaluated.
622- In `config.j`, every literal is resolved at load, against the same ids. A
623 literal that fails to resolve is a configuration error (exit 3) naming the
624 definition it appears in.
626After resolution a literal is an ordinary `Id` value holding the full id, so
627`==` on ids is identity and never involves prefixes.
629**New.** The bare token `@` is an expression that yields a distinct, freshly
630minted `Id` each time it is evaluated. In a script that writes `@` once, this
631is indistinguishable from replacing it with a new id before the run. In a
632lambda body it is evaluated on each application, so `newCommit` (§9) mints a new
633id per call. A top-level definition that is a bare record containing `@` is
634evaluated once at load and holds one id for the whole program (§4.1). `show`
635renders a minted id like any other.
637### 4.11 Label literals
639`%main` denotes `labelled "main"`, a `Revset`, as if written out where it
640stands: in the scope of a `config.j` binder named `labelled` (§4.2) it applies
641the binder, and it is a reference to it for evaluation order (§4.1). It is a
642function, evaluated when applied, so it never fails at parse time: a name the
643remote does not have yields `[]`, and `goto %nope` crashes with "expected one
644revision, got 0" as any revset would.
646### 4.12 Shapes as values, and `extract`
648A type name used in an expression evaluates to a *shape*: for a `typedecl`
649whose type is a record, the set of its field names; for a primitive kind
650(`Int`, `Text`, `Bool`, `Id`, `Blob`), that kind; for a `typedecl` that is an
651alias of another type, that type's shape. A shape whose type is a function
652(`Edit`, `Revset`), a list, or undeclared is a crash when used, as is an
653alias that never reaches a type (`A = B` with `B = A`).
655`extract S v` returns every subvalue of `v` that is an `S`, as a list. It
656walks lists in order and records in ascending field-name order, descending
657into every element and field; it does not enter functions or blobs. A record
658is an `S` if its field set is exactly `S`'s (the same rule display uses to
659recognise shapes); a primitive value is an `S` if it is of that kind. Matches
660are collected in traversal order, and a matching record is also searched
661inside for nested matches.
663```haskell
664extract Commit repo -- every commit reachable from a Repo, Subtree, or Frame
665extract Id repo -- every id in it
666extract Push xs -- the Push records in a list, however nested
667```
669`extract` does not promise a meaningful order for values with several
670positional fields; a `Repo` yields its `children` before its `context` before
671its `root`. Where order matters, `commits (top repo)` is preorder.
673### 4.13 Contracts
675Every application of a function that has a signature — a builtin or a
676definition with a signature — is checked against it: each argument as it is
677supplied, against the corresponding parameter type, and the result once the
678function's own application completes (its body has run or the builtin has
679all its arguments), against the result type.
680Lambdas without a signature and the command-line expression are unchecked
681except through the functions they call. A signature covers all the arguments
682it lists, however the definition's value is curried: `describe : Text -> Edit`
683is `\m -> mapRoot …`, and the `Repo` that `describe m` is then applied to is
684checked as its second argument, and the result against `Repo`; with
685`addT : Int -> Int -> Text` and `addT = (+) . (\x -> x + 1)`, the `5` of
686`addT 1 5` is checked as its second argument, and the `7` against `Text`. A
687signature only adds checks and never changes when a body is evaluated
688(§4.1): `describe m` evaluates `mapRoot …` at once, so an `or` around it
689catches a crash there (§4.6); the value must be a function, since the
690signature lists a further argument, and shows as `describe m` (§5.2);
691`addT 1` likewise shows as `addT 1`, not as the `(+) 2` it holds. Arguments
692are numbered as the signature lists them, even when the definition's value is
693a partial application or a composition holding arguments of its own (`tree 5`
694is a violation at argument 1); when the value is an `or` of functions (§4.6),
695the check is around the lifted function, so a result that violates the
696signature is a crash, not a reason to try the other side. A signature on
697a definition that is not a function (`user`, `conflicts`) is checked once,
698against the value, when the definition is evaluated at load.
700Infix `&&` and `||` must be declared like other builtins. Their contracts
701check each operand that is evaluated and the result, including a result
702decided by the left operand alone. A skipped right operand is neither
703evaluated nor checked.
705The check is one level deep and never inspects inside a list or a record's
706field values:
708| declared type | check |
709|---|---|
710| `Int`, `Text`, `Bool`, `Id`, `Blob`, `Shape` | the value is of that kind |
711| `[T]` | the value is a list; elements are not inspected |
712| `{ a : T, … }`, or a shape name | the value is a record with exactly those field names |
713| `A -> B` | the value is a function |
714| a type variable | anything |
715| an alias (`Edit`, `Revset`, `Snapshot`) | the type it stands for; an alias of a function type is unfolded so that further arguments and the final result are checked against it (`at : Revset -> Edit -> Edit` checks three arguments and a `Repo` result); an alias the unfolding has already unfolded is not unfolded again, so `Stream = Int -> Stream` checks one argument and a function result |
717Field values and list elements are not checked because that would make every
718call cost the size of the value and would force lazily backed snapshots and
719histories (§7.2).
721A violation is a crash, catchable by `or` like any other:
723```
724j: crash: contract: describe expected Text as argument 1, got Int
725 in describe, from describe 3
726```
728For records the expected and actual field sets are shown:
729`expected { files, labels, id, message }, got { children, context, root }`.
731---
733## 5. Output
735Two renderers. **Display** is what the CLI prints; it is designed to be read.
736**`show`** is the builtin; it renders literal syntax designed to be pasted
737back. They share glyphs and colours with `treeWith` (§7.11) and are
738implemented beside it.
740### 5.1 Display
742Every kind of value has a *line* form and a *block* form. The top-level value
743prints in block form. Values nested inside another print in line form,
744indented under their key or bullet. Colour follows §7.11's rules and is used
745only when stdout is a terminal; nothing is conveyed by colour alone.
747Shapes are recognised by their exact field set, as in §4.12: `Commit`, `Entry`,
748`Subtree`, `Repo`, `Frame`, `Change`, checked in that order using their
749configured definitions. Additional type aliases do not displace these
750display forms. Any other record is generic.
752| kind | line form | block form |
753|---|---|---|
754| `Int` | decimal | same |
755| `Bool` | `true` / `false` | same |
756| `Text` | raw, first line, `…` if truncated | raw, all of it, trailing newline added if absent |
757| `Id` | shortest unique prefix (bold), remainder (dim) | same |
758| `Blob` | `‹214 B›`, `‹✖ 3.1 KB›` if unresolved | its content, raw (markers if unresolved) |
759| function | name, lambda source, or `f arg …`; first line, `…` if truncated | same, all of it |
760| `Shape` | its type name | same |
761| `Commit` | `glyph id message labels` — a `tree` line without rails | that line, then `author · age · n files`, then one changed path per line with `+ ~ − ✖` marks |
762| `Entry` | `path size`, `✖` prefix if unresolved | same |
763| `Subtree` | its top commit's line form | a tree rooted at it, no focus |
764| `Repo` | its focus's line form | `treeWith` with the config's `tree` options |
765| `Frame` | its parent's line form | parent's line, then its children's line forms in a row with `▢` at the hole |
766| `Change` | `n paths` | one touched path per line with `+ ~ − ✖` marks, as in a `Commit` block |
767| generic record | `{ a, b, … }` (field names only) | one field per line, names left-aligned and dim, values indented if multi-line |
768| list of `Id` | `n commits` | a commit table: one commit line per id, in list order |
769| list of generic records with identical field sets | `n rows` | a column table with a dim header; `true` shows as `✓`, `false` as blank; columns empty in every row are dropped |
770| list of `[Text]` | `n paths` | one per line, joined with `/` |
771| list of `Text` | `n items` | one per line |
772| list of other scalars | `a, b, c` | same, wrapped at the terminal width |
773| any other list | `n items` | one block per item, separated by a blank line |
775Column tables use copyable shortest unique `@` prefixes for Id cells and
776show the actual contents of Text-list cells (such as bookmark names), not
777item counts. Empty Text-list cells are blank. On a terminal, columns are
778fitted to the available width; if minimum column widths cannot fit, rows
779are shown vertically with wrapped values. Piped tables retain untruncated
780cell contents. These presentation choices do not change `show` or values.
782The reference status record includes `unrecorded : [Path]` alongside
783`changed : [Path]`. The display labels `changed` as `in commit` to distinguish
784changes against the commit's parent from file edits since the last recording.
785Its empty fields read `No changes`, `No conflicts`, `No labels`,
786`No description`, and `All edits recorded` for empty `unrecorded`.
787Nonempty paths and labels remain visible. Presentation does not rename the
788underlying `changed` field. Older five-field status records remain displayable.
790An empty list of any kind prints `none` (dim) in block form and `0 …` in
791line form. Author and age in a `Commit` block are read from jj's commit
792metadata by id;
793they are not fields of the value. Nor is where it stands, which is read by id
794from `r`, the repository the expression was given (§1.2 step 4, after the
795snapshot): a block's paths are those it changes against its parent's files
796there, and its glyph, in either form, is the one `tree` draws for it there,
797with `⊗` and `◌` judged by the value's own files. What a commit with no
798parent there (the root, or one the expression made) changes is not known:
799its block lists its files unmarked (but for `✖` on an unresolved one), and
800its glyph claims no `◌`. One the expression made has no metadata either
801(§7.11), so its block has no `author · age · n files` line. One the
802expression moved is still compared with its parent there. A `Repo`'s
803line draws its focus as the focus. A list of `[Text]` prints as paths because
804that is what such a list is in every base function; `show` is available
805when the literal is wanted. Alignment in tables and columns uses display
806width (East Asian wide characters count two cells, combining marks zero), not
807code-point count.
809Examples:
811```
812$ j status
813in commit src/lexer.rs
814 src/parser.rs
815conflicts src/lexer.rs
816id wqzt·kpqxmnrvyxskptlmzzzzabcd
817labels feature
818message wip
819unrecorded All edits recorded
821$ j conflicts
822⊗ wqzt wip feature
823⊗ ptlm docs
825$ j log
826 id message labels focus
827 zzzz
828 kpqx add parser main
829 mnrv fix lexer
830◉ wqzt wip feature ✓
831 yxsk
832 ptlm docs
834$ j focus
835◉ wqzt wip feature
836 Montelot · 2h ago · 2 files
838 ✖ src/lexer.rs
839 ~ src/parser.rs
841$ j files
842 Cargo.toml 214 B
843✖ src/lexer.rs 3.1 KB
844 src/parser.rs 8.7 KB
846$ j clean
847false
848```
850(`·` marks the bold/dim boundary in an id; there is no character there.)
852Crashes print the message, then the innermost base definition that was
853executing and the top-level expression:
855```
856j: crash: expected one revision, got 0
857 in goto, from goto %nope
858```
860### 5.2 `show`
862When it succeeds, `show v` renders `v` as an expression in the language, such
863that for every value except closures, unresolved blobs, and values nested past the parser's
864bound (§3.4: a list 40,000 deep, a record about 20,000), `show v` parses and
865evaluates to a value equal to `v` under the same `config.j`. It never uses
866colour and never truncates. A value holding a part the store cannot supply (a
867`files` list or a file's content, §7.2) crashes `show` as it crashes any other
868use: `show` writes no stand-in for the part.
870Binary blobs and non-regular file kinds require the declaration
871`blobHex : Text -> Text -> Blob` in `config.j`; if it is missing, `show`
872crashes with instructions to add it. Existing custom configs are not
873modified automatically.
875| kind | rendering |
876|---|---|
877| `Int` | decimal |
878| `Text` | double-quoted, escaped as in §3.1 |
879| `Bool` | `true` / `false` |
880| list | `[v1 v2 …]` |
881| record | `{ a = v, b = w }`, fields in ascending lexicographic order |
882| `Id` | `@` followed by the full id, e.g. `@wqztkpqxmnrvyxskptlmzzzzabcd` |
883| resolved regular `Blob` with valid UTF-8 content | `blob "…"` |
884| other resolved `Blob` | `blobHex "kind" "…"`, preserving file kind and bytes, with lowercase hexadecimal content |
885| unresolved `Blob` | `{- unresolved -} blob "…"` with the conflict-marker rendering |
886| builtin | its declared name, operators parenthesised: `map`, `(++)` |
887| selector | the selector itself: `.id` |
888| top-level definition with a signature whose value is a function | its name |
889| revset from a label literal | `%name` |
890| shape | its type name: `Commit`, `Id` |
891| lambda closure | its source text, exactly as written |
892| partial application | the function's rendering followed by the arguments' renderings, each parenthesised if not atomic: `describe "wip"`, `at (parents) (describe "x")` |
894A lambda's source text runs from its `\` to the last token of its body,
895comments within it included, and a section's is the section itself, which
896unlike a lambda is an atom: `map (+ 1)`, `(\x y -> x + y) 1`.
898A top-level definition with a signature whose value is a function renders as
899its name whatever that function is built from, and its partial application
900as its name followed by the arguments it was given, never by those its value
901holds: `prev`, not `prev (parents)` (with `prev = goto parents`), `tree`, not
902`treeWith ({ … })`, and `addT 1` (§4.13). Any other definition renders as its
903value: `user` as its record, and without signatures `inc = \x -> x + 1` as
904`\x -> x + 1` and `incAll = map inc` as `map (\x -> x + 1)`.
906Line breaking: one line if it fits in 80 columns (display width, as in §5.1);
907otherwise the outermost list or record breaks one element per line, two-space
908indented, with leading commas for records and nothing between list elements,
909recursively.
911Since `show` returns a `Text` and a top-level `Text` displays raw,
912`j show . focus` prints the literal of the focused commit, and
913`show . f` does the same for any `f`.
915---
917## 6. Configuration
919### 6.1 Location and loading
921`j` reads `$XDG_CONFIG_HOME/j/config.j`, defaulting to `~/.config/j/config.j`.
922Expression evaluation and `push` load the configuration; `init` and
923`clone` need `user`. When there is no repository yet (`init`, `clone`), only
924`user` is evaluated; `Id` literals are not resolved and no other definition
925is evaluated. `remote`, `fetch`, `undo`, `redo`, and `ops` do not load configuration.
926When a command needs configuration and none exists, the binary writes its
927embedded reference `config.j` (§9) to that path as an editable starting point,
928readable and writable by its owner, and reports its path. An existing file is
929never overwritten, including when it cannot be read or contains invalid
930UTF-8; such errors exit 3.
931Configuration diagnostics identify the actual file; parse errors include the
932line number and a bounded source excerpt, with a pointer to `j help config`.
933Excerpts escape terminal controls and are capped at 160 display columns and
934characters, with an ellipsis when truncated. Expression parse errors, including
935push expressions, likewise identify their source line. Runtime diagnostics may
936add typo suggestions from the actual vocabulary, quoting examples for Text
937arguments, or missing-argument guidance derived from the command signature;
938they never retry an expression or change its meaning or exit code.
939An existing user configuration is not updated when the binary changes. The
940reference file is also distributed at `<prefix>/share/j/config.j`.
942Help and command discovery are read-only exceptions (§1.1.1): general help and
943reserved-command help need no config, while the catalog and help for config
944names read it without evaluation. If it is missing they use the embedded
945reference in memory without writing a file. The empty-invocation guide does
946not read or write configuration either.
948### 6.1.1 Explicit setup
950`setup` creates the full embedded configuration at the configured path without
951opening a repository. With no arguments, it creates an editable default and
952reports the path and instructions to set `user`. With `NAME EMAIL`, it checks
953the identity rules of §6.2 and writes those values into the complete reference
954configuration, serialized as language text literals. Names containing spaces
955are supplied as a separately quoted shell argument.
957Setup never overwrites an existing file. Without identity arguments, an
958existing file reports its effective identity when valid, or guidance to
959edit it otherwise. With identity arguments, an
960existing file is a usage error (exit 2), with instructions to edit manually.
961Argument counts other than zero or two are usage errors. Creating the file
962also creates missing parent directories; exclusive creation preserves a file
963created concurrently by another invocation. No repository state is changed.
965### 6.2 Validation
967Loading fails (exit 3) if any of these hold:
9691. The file does not parse (§3).
9702. A signature without a definition names something the interpreter does not
971 implement; or a name has two signatures; or a signature is not immediately
972 followed by its definition when one exists.
9733. A name is defined twice, or a definition uses the name of a builtin the
974 interpreter implements (those names are reserved whether or not declared).
9754. A `typedecl` name is declared twice.
9765. An `Id` literal fails to resolve (§4.10).
9776. `user`, `immutable`, `tree`, or `labelled` is absent; or `user` is not a
978 record with non-empty `name` and `email` texts; or `immutable`, `tree`, or
979 `labelled` is not a function.
981Loading does **not** check types statically. Signatures are enforced at
982each call, one level deep (§4.13). The *presence* of a signature with no
983definition is what brings a builtin into scope; an implemented builtin that is
984not declared is simply unbound, and using it is a runtime crash.
986Definitions may reference each other in any order.
988Before authoring commits (`init`, `clone`, or an expression that persists a
989change), the effective identity must also have nonblank name/email and must
990not retain the shipped `Your Name` or `you@example.com` placeholders. Such
991identity failures are configuration errors (exit 3) and do not persist the
992edit. Inspection and unchanged expressions remain usable with placeholder
993identity, so users can inspect and repair existing repositories.
995### 6.3 Definitions the interpreter reads
997Four names in `config.j` are read by the interpreter itself, not only by
998expressions:
1000- `user`, a record `{ name, email }`: the identity that authors commits
1001 (§7.9).
1002- `immutable`, a `Revset` that persistence evaluates to decide what may not be
1003 rewritten (§7.5).
1004- `tree`, used by display to render a `Repo` (§5.1).
1005- `labelled`, which a label literal `%name` desugars to (§4.11).
1007All four are ordinary definitions; the reference `config.j` provides them and
1008a user edits or redefines them.
1010---
1012## 7. Repositories
1014`j` operates on jj repositories through jj-lib. It creates jj commits,
1015operations, and working-copy state that `jj` itself can read, and vice versa,
1016but nothing here requires the `jj` binary to be installed.
1018### 7.1 Locating the repository
1020Walk up from the current directory to the first directory containing `.jj`.
1021Only the default workspace is supported; if the working directory belongs to
1022another workspace, exit 2.
1023The working copy must also include the whole repository: sparse patterns
1024must contain the root path. Otherwise exit 2 without changing the patterns,
1025files, or operations, with instructions to run
1026`jj sparse set --clear --add .` before using `j`.
1028### 7.2 Building the `Repo` value
1030The history of the repository is loaded at the current operation and mapped to
1031a value as follows.
1033- **Commits.** Every visible commit (an ancestor of a visible head), including
1034 jj's root commit, becomes a `Commit` record: `files` from its tree (§7.3),
1035 `message` from its description, `labels` from the remote bookmarks of
1036 `origin` pointing at it (§7.6), `id` from its change id.
1037- **Tree.** The root commit is the top of the tree. Each commit's parent is
1038 its **first** jj parent. A commit with two or more parents (a merge) is
1039 therefore placed under its first parent and its other parents are not
1040 represented; such a commit is *read-only* (§7.5). If two visible commits
1041 share a change id, exit 2 with
1042 `j: change <id> has two visible commits; j cannot operate on this repository`.
1043- **Child order.** A commit's children are ordered by committer timestamp
1044 ascending, ties broken by change-id text ascending. Within a program,
1045 `attach` appends. The order is presentation only: no command and no law
1046 depends on which child is first, and the language has no way to select a
1047 child by position.
1048- **Focus.** The zipper is focused on the default workspace's working-copy
1049 commit, after snapshotting (§7.4). `context` is computed from the path to the
1050 root. If that commit is in the immutable set (§7.5) — typically because a
1051 `fetch` found the remote's `main` pointing at it — the snapshot cannot go
1052 into it; the focus is instead a new empty child of it holding the snapshot,
1053 as `abandon` would leave it, and persisting records that child. Nothing
1054 else is written by loading. The value as loaded (§1.2 step 8) has the same
1055 child holding the commit's own files, so `j id` records the child exactly
1056 when the working directory differs from that commit.
1058The record is the *semantics*. An implementation may back `files`, `children`,
1059and `context` with lazily materialised structures, provided every observation
1060an expression can make agrees with the eager value. If materialising one of
1061them, or a file's content, fails (an object missing from the store), every
1062later use of it fails the same way: a crash caught by `or` (§4.7) never leaves
1063some other value in its place.
1065### 7.3 Files, blobs, and `replay`
1067- A commit's `files` has one `Entry` per tracked path in its tree. `path` is
1068 the list of path components; components must be valid UTF-8, and a
1069 repository with a path that is not exits 2. `content` is a `Blob` carrying the file's
1070 content and type (regular, executable, symlink) and, for conflicted paths,
1071 jj's conflict value for that path, less each pair of sides that cancel (a
1072 side added and one removed that are the same), as jj drops them to write
1073 a file's conflict out. jj keeps such pairs in the conflicts of the trees
1074 it merges; dropped here, a conflict a commit inherits unchanged reads as
1075 its parent's. A conflict whose sides left would all be directories keeps
1076 every side, as jj keeps it as one conflict at the path rather than one
1077 between directories. The entries' order carries no meaning,
1078 as a tree has none: persistence (§1.2 step 8, §7.5), the laws of §8 and
1079 the tree's empty mark compare snapshots path by path, though `==` compares
1080 them as lists (§4.5).
1081- A path that is deleted and resolved has no entry. A path that is in a
1082 deletion conflict has an entry whose blob is unresolved. Each side of a
1083 conflict is either absent or content with its own file type, so a side
1084 that deleted the path is not an empty file. In a conflict between a file
1085 and a directory, which jj keeps as one path, a directory side reads as
1086 empty content but is kept whole, and is written back as that directory.
1087- `replay onto { from, to }` is jj's tree merge: for each path present in
1088 any of the three snapshots, the three-way merge of that path's values with
1089 `from` as the common ancestor, replaying the change from `from` to `to` on
1090 top of `onto`. Conflicts are kept as unresolved blobs, and resolved where
1091 jj's merge would resolve them (identical changes, changes from the current
1092 content, non-overlapping line-level hunks). A path unresolved in any of the
1093 three takes part with all its sides, as when jj rebases a conflicted commit,
1094 so sides that cancel drop out and a replay can resolve a conflict as well
1095 as keep one. A conflict it keeps has no pair of sides that cancel
1096 (above), so in a stack replayed commit by commit, a conflict each commit
1097 inherits is its parent's, whatever conflicts the commits below added. It
1098 never crashes on content, except where a file meets a
1099 directory (below). It crashes if any of the three is not a well-formed
1100 snapshot (a list of `Entry` records with unique paths, none of them the
1101 root `./`, and none both a file and a directory as `./a` beside `./a/b`
1102 would be).
1103- A path that is a file in one of the three snapshots and a directory in
1104 another is merged as one value, as jj does, the directory with everything
1105 below it. When at most one of `onto` and `to` changed it from `from`, that
1106 value is taken whole. When both did and none of the three holds a
1107 conflict at or below the path, the result is their value taken whole if
1108 they made the same change, and otherwise a conflict at the path, its
1109 directory sides kept whole. A conflict one of the three holds there takes
1110 part with all its sides, as above, so the result is a conflict at the path
1111 unless sides cancel, even where both made the same change: a child that
1112 resolves a conflict at `./a` into `./a/b`, replayed with `from` that
1113 conflict onto the same resolution, keeps a conflict at `./a`. `replay`
1114 crashes, naming the path, when its result would be a conflict at the path
1115 with a file on one side and on another a directory that `onto` or `to`
1116 holds, as replaying the addition of `./a/b` onto a file `./a` would: one
1117 entry cannot list the directory's entries. It does not crash where one of
1118 the three already holds a conflict at that path (an unresolved blob there,
1119 not one below it): the sides came in with that conflict and are carried
1120 like any others, so a child that resolves such a conflict can be squashed
1121 into it. The in-memory backend of §10 merges such a path file by file,
1122 like any other, keeps no directory as a side, and crashes when its result
1123 would hold both `./a` and `./a/b`. So here, as where jj merges lines, the
1124 two backends may differ: it resolves some merges that jj keeps as a
1125 conflict or refuses (a change from a file `./a` to `./a/b` replayed onto a
1126 snapshot without `./a` gives `./a/b`, and so does one from a conflict at
1127 `./a` to `./a/b` replayed onto `./a/b`; the deletion of `./a/z` replayed
1128 onto a snapshot where `./a` is a file gives that file), and it may crash
1129 where jj carries a conflict that one of the three held at `./a`.
1130- `unresolved`, `blob`, `blobHex`, and `text` are as in §4.9. `blob` produces
1131 a regular file from text. `blobHex` constructs a regular file, executable,
1132 or symlink from its kind and hexadecimal bytes, so `show` can preserve both
1133 content and file type. `text` of a symlink is its target; `text` of a
1134 non-UTF-8 blob crashes. Persisting a symlink with a non-UTF-8 target crashes.
1136### 7.4 Working-directory invariant
1138At every program boundary the files of the focused commit equal the working
1139directory.
1141- **Before evaluation**, the working directory is snapshotted into the
1142 working-copy commit, and that is the `files` of the focus in the `Repo`
1143 value. The snapshot tracks every file not matched by `.gitignore` files,
1144 and each file it tracked before that a `.gitignore` has come to match
1145 (deleted once it is gone, even where a file has replaced a directory
1146 above it), with no size limit, symlinks as symlinks, and nothing inside a
1147 nested repository (a directory below the root holding `.git` or `.jj`);
1148 these rules are fixed, since `j` reads no jj configuration. If the snapshot
1149 changed the commit, that change is part of the operation persisted
1150 afterwards, or discarded with the rest if nothing is persisted; a change
1151 that leaves the commit with its parent's files, as where the directory
1152 reverts what the commit changed, gives it the parent's tree, as step 4
1153 of §7.5 writes such a commit, so that jj takes it for empty. A crashed
1154 or printing program leaves the working copy and the repository exactly as
1155 before (but see §7.5 step 7); `j id` is the way to record the working
1156 directory and nothing else (§1.2).
1157- **A stale working copy.** The working copy is stale when the files last
1158 checked out are not the working-copy commit's: jj changed the commit
1159 without updating the working directory (a command run with
1160 `--ignore-working-copy`, or one in another workspace that rewrites this
1161 workspace's commit), `fetch` rebased it (§7.6), or a checkout failed or
1162 was cut short after its operation was recorded (§7.5 step 7). The
1163 working copy's record of the files last checked out names the operation
1164 it was saved at, and one saved at the head operation is current whatever
1165 files it records, as jj takes it: where the record was lost, and jj made
1166 it again recording no file, the snapshot records the directory as it
1167 is. Over a stale working copy, the directory started from the files last
1168 checked out, and what has changed in it since is a change to those,
1169 which the snapshot replays onto the commit: a three-way merge with the
1170 files last checked out as the base, in which a path that the directory
1171 and the commit both changed, differently, is a conflict (an edit to a
1172 file the commit deletes, say), and one where the directory holds what
1173 the commit does is the commit's (what a checkout cut short had written).
1174 A path that both changed where that conflict would set a directory
1175 against a file, a symlink or nothing (a file the commit changes that the
1176 user replaced by a directory, say), which `replay` refuses as one entry
1177 cannot list the directory's entries (§7.3), takes what the working
1178 directory holds there instead, as over a working copy that is not stale:
1179 the commit's change there is left in the operation before. A conflict of
1180 that kind that the commit itself has (one made by a `fetch` that rebased
1181 it, say) stays where the directory has not changed the path, which is
1182 the commit's like any other. Either way, where the record does not hold
1183 one of the commit's conflicts, a file holding what a checkout writes for
1184 it is read back as that conflict: exactly its markers, or a description
1185 of the same sides, whatever their labels and less any side it both
1186 removes and adds. With no change there is nothing to snapshot, and a
1187 program that persists writes the focus over the files last checked out
1188 as usual. A stale working copy refuses no program.
1189- **After persistence**, the focus of the result is checked out: its files are
1190 written to the working directory, unresolved blobs materialised with jj's
1191 conflict markers, and the workspace's working-copy commit set to the focus.
1192 A checkout writes nothing over what stands where the focus has a file (or
1193 a symlink, or a conflict) and the directory has no tracked one. It first
1194 removes each tree of empty directories there, which no snapshot sees (a
1195 tool may leave one, and a failed checkout does, for a path it did not
1196 reach), and moves an untracked file holding just what it writes there
1197 (as a checkout cut short leaves at an ignored path) aside into `.jj`,
1198 which no snapshot reads, looking through no symlink, so nothing outside
1199 the working directory is touched. Once the checkout returns, each file
1200 moved aside is put back where nothing stands, as where a failed checkout
1201 did not get to write, and, where the checkout failed (a full disk), over
1202 a file holding a start of it, less than all of it (an empty file, for a
1203 symlink), as a write cut short leaves, completing the write; the rest
1204 are removed, each holding just what the focus has there, which the
1205 repository keeps, and what stands there, what the checkout wrote or
1206 something put there since, stays. What a run killed meanwhile leaves in
1207 `.jj`, the next run puts back as after a failed checkout, before it
1208 looks at the working directory. A file that cannot be moved stays, and the
1209 checkout, which skips its path, fails, naming it and why (§7.5 step 7).
1210 Anything else untracked there, or in place of a directory above the path
1211 (an ignored file, a symlink, a directory holding one), crashes the program
1212 before its operation is recorded, as git refuses to write over an
1213 untracked file, naming each such thing (the first ten, and how many more
1214 there are), a directory by its own path and an untracked file in it:
1215 each is to be moved aside.
1216 A later snapshot reads such a file back as the conflict its markers
1217 describe, edits included, while they parse at the length they were written
1218 with (longer than 7 when a side holds a marker-like line); once they do
1219 not, the file is resolved to its text. A conflict with a side that is no
1220 file (a directory, a symlink) has no markers: it is written as jj's
1221 description of its sides, and read back as that conflict while the file
1222 is left as written (the working copy records each file's size and
1223 modification time) or describes the same sides, whatever their labels
1224 and less any side it both removes and adds (a snapshot may drop such a
1225 pair from the conflict without writing the file again); a file written
1226 with anything else is resolved to its text.
1228Reserved commands never snapshot.
1230The `unrecorded : Repo -> [Path]` builtin compares the invocation's loaded
1231focus files with its snapshotted focus files, using the same path/content
1232comparison as `changed`. The result describes the original working-copy
1233edits, independently of changes an expression makes to its `Repo` argument.
1234It returns `[]` when either snapshot context is absent, including reserved
1235push evaluation. Read-only status and preview calls do not record these paths;
1236`save = id` persists their snapshot through the normal expression path.
1238### 7.5 Persistence
1240Given the loaded value `old` and the result `new`, one jj operation is
1241recorded, described by the expression text (truncated to 200 characters).
1242Within it:
12441. **Validate shape.** `new` has the shape of a `Repo`; every `id` occurs
1245 exactly once; every commit's `message` is a `Text`; every snapshot entry
1246 has a `path` list of texts and a `content` that is a `Blob`; every snapshot
1247 has unique paths, none of them the root `./` and none both a file and a
1248 directory (§7.3); every path
1249 component of the focus, of every other commit that is not in `old`, and
1250 of every path any other commit holds that it did not hold in `old`
1251 (§7.3), is a name a checkout can create: not empty, `.`, `..`, `.git` or
1252 `.jj`, without `/`
1253 or NUL, and a name the workspace's filesystem can hold. A name the working
1254 directory holds (§7.4) is one. A name longer than 255 bytes, the limit of
1255 ext4, is tried on the filesystem, since exFAT, NTFS and APFS count 255
1256 UTF-16 units or characters instead; where a filesystem's limit is lower,
1257 or a whole path outgrows the system's limit, the checkout of step 7
1258 refuses it instead. Where the working directory's filesystem folds case
1259 (`.JJ` names its `.jj`), `.git` and `.jj` are refused in any letter case.
1260 (Any other path is neither checked out nor written with a name jj has not
1261 already stored, and a fetched branch can hold any name git can, even one
1262 above the focus that a snapshot rebases.) Violations crash with a message
1263 naming the rule. Files as loaded from a stored tree (§7.2) are such a
1264 snapshot already, as a jj tree holds each name once and each path as a
1265 file or as a directory, and are not checked again.
12662. **Validate labels.** The set of `(id, label)` pairs in `new` equals the set
1267 in `old`. Labels are the remote's names (§7.6); a script cannot add, move,
1268 or remove one. In particular a commit carrying a label cannot be abandoned.
12693. **Validate immutability.** The *immutable set* is the config's `immutable`
1270 revset evaluated against `old`, together with every merge commit (§7.2)
1271 and all of its ancestors. Every id in it must be present in `new` with the
1272 same parent id, files, and message. Violations crash naming the commit.
1273 (Ancestors of merges are included because rewriting an ancestor rewrites
1274 the merge, whose second parent the model cannot represent.) They are the
1275 merge's jj ancestors through every parent, not only the first, so a
1276 commit reached only through a second parent is immutable too.
12774. **Walk `new` top-down.** For each commit `c` (root first):
1278 - If `c.id` is the root commit's change id, it must be the top of the tree
1279 and must be unchanged; otherwise crash.
1280 - If `c.id` is not in `old`: create a jj commit with parent = the jj commit
1281 written for `c`'s parent in this walk, tree from `c.files`, description
1282 `c.message`, author and committer from `user` (§7.9) and the current
1283 time, change id `c.id`.
1284 - Otherwise, if `c`'s parent's *written* commit hash, or `c.files`, or
1285 `c.message` differs from the stored commit: rewrite it (new commit hash,
1286 same change id, stored as a successor so jj records predecessors),
1287 keeping the author and author date, with committer `user` and the
1288 current time.
1289 - Otherwise keep the stored commit.
12905. **Abandon** every change id in `old` that is not in `new`.
12916. **Focus.** The focus must be mutable: if `new.root.id` is the root commit
1292 or in the immutable set, crash with
1293 `the focus must be a mutable commit; compose with new`. Otherwise set the
1294 default workspace's working-copy commit to the commit carrying
1295 `new.root.id`. (`abandon` and `squash` end with `new` for this reason, so
1296 they are safe on a commit directly above `main`; navigation onto `main`
1297 is written `new . goto trunk`.)
12987. Record the operation, then perform the checkout of §7.4, as jj does. A
1299 signal to stop that comes meanwhile waits until the checkout and its
1300 record are saved (§1.3). An operation that cannot be recorded, a
1301 checkout that would write over something untracked (§7.4), and one that
1302 would write over a change made to the working directory while the
1303 program ran (a file saved, created or removed after the run's snapshot,
1304 at a path where the focus differs from what that snapshot read), which
1305 it names, crash before the checkout, so nothing is recorded or written.
1306 A checkout that fails (a path the filesystem cannot hold, a full disk)
1307 crashes with the operation recorded and the working directory partly
1308 updated, and says so; so does one that completes but whose record of
1309 what it wrote cannot be saved. Nothing it wrote is taken back: the
1310 working copy is left stale (§7.4), recording the files the directory
1311 held when the checkout began, so the next run takes what the checkout
1312 wrote for the focus's own and what else has changed since for a change
1313 to the focus, the next program that persists writes the rest of the
1314 focus, and `j undo` goes back. A file saved meanwhile at a path after
1315 the checkout wrote there, or at a path the focus adds before the
1316 checkout got there, and a file a full disk cut short where no file was
1317 moved aside for it, are conflicts with the focus's content there, so
1318 neither is lost (at an ignored path, a file a full disk cut short is not
1319 read: the next checkout names it as in its way, and `j undo` leaves it);
1320 a file the focus changes or removes, saved while the checkout runs but
1321 before it reaches that path, is written over, as in jj. The checkout
1322 reads no file into the repository and removes none it does not replace:
1323 a file it moved aside to write again (§7.4) is put back where it did not
1324 get to, and over the start of it that it wrote where it was cut short,
1325 and where anything else stands is removed, holding just the focus's
1326 content there; an ignored file saved meanwhile where the focus adds one,
1327 before the checkout reached it, stays, holding what it held, and the
1328 checkout fails, naming it, so that no run reads it; anything inside a
1329 nested repository stays too. No uncommitted edit present at the run's
1330 snapshot is lost where the checkout writes over it, as the operation
1331 holds that snapshot (§7.4). This is the one crash that records anything.
1333Labels are not written by persistence at all; they are derived from remote
1334refs, which only `fetch` and `push` change. The interpreter may run any part
1335of the walk through jj-lib's rebase machinery provided the stored result
1336equals what the steps above produce. As in §1.2 step 8, steps 3 and 4 may
1337compare tree hashes rather than values: files still as loaded from a stored
1338tree are that tree's. Step 4 writes a commit whose files are still as
1339loaded from a stored tree, its own or another's (`new` gives the child its
1340parent's), with that tree as jj stored it, pairs of sides that cancel and
1341conflict labels included (§7.3), as jj's own `new` and `describe` keep a
1342tree: one built from the files could be another tree for the same files.
1343For the same reason a commit step 4 writes whose files are its parent's is
1344written with the parent's tree, labels included, whatever tree its files
1345were loaded from, as jj's own `squash` or `rebase` leaves a commit it
1346empties: jj takes a commit for empty only where its tree is its parent's.
1347`squash`, `rebase` or `abandon` can leave such a commit by building its
1348files anew, or by moving it, its files unchanged, onto another tree for
1349the same files: an empty child of a commit squashed into its parent, or
1350an empty commit rebased onto one holding its parent's files. A persisting
1351run then reads the files of the focus, of the commits it writes with
1352other files, and of those whose files it compares with a tree they were
1353not loaded from, but not those of the rest of the history.
1355### 7.6 Labels and the remote
1357A label is the name of a bookmark on the remote `origin`, as of the last
1358`fetch` or `push`. There is one namespace. Labels are read-only in the
1359language: `fetch` and `push` are the only things that change them.
1361- **`fetch`** fetches from `origin` over git and imports refs. Afterwards
1362 each remote bookmark `name` is the label `name` on the commit it points at;
1363 labels for bookmarks that no longer exist on the remote are removed; commits
1364 reachable from remote bookmarks become visible. Fetching never moves the
1365 focus or touches the working directory. It records one operation. When
1366 the import rewrites or abandons the focus or a commit below it, the focus
1367 is rebased as jj rebases descendants, and the working copy is then stale
1368 (§7.4): the next run records what has changed in the directory onto the
1369 rebased focus, and the next program that persists writes its files.
1370- **`push EXPR`** evaluates `EXPR` (§1.1); a function result is applied to
1371 the recorded repository. The value must be a list whose elements are records
1372 of two shapes:
1373 - `{ id : Id, name : Text }` — set bookmark `name` to the commit `id`,
1374 creating it if absent;
1375 - `{ delete : Text }` — delete the bookmark of that name.
1377 Before sending a valid push, inspect the working directory without saving
1378 a snapshot or scan state. If it has unrecorded edits, print a warning to
1379 stderr (also when piped or colors are disabled) explaining that push sends
1380 recorded content only, and that `j id` followed by another push includes
1381 those edits. The warning does not change the requested push's targets or
1382 prevent deliberate publication of recorded commits.
1384 Duplicates are merged; two records with the same `name` and different
1385 effects are a crash. It is refused (exit 1, nothing pushed) if:
1386 - a `name` is not a valid git branch name, an `id` is not a visible commit
1387 or names the synthetic root (which has no Git commit), or a delete names
1388 a bookmark the remote does not have;
1389 - any commit that would be sent has an unresolved file or an empty
1390 description (the commits that would be sent are the records' `id`s and
1391 their ancestors that no bookmark on `origin` reaches as of the last
1392 `fetch` or `push`; a delete sends none);
1393 - the bookmark's current target is in the immutable set (§7.5) and the
1394 record would move it to a commit that does not descend from it, or delete
1395 it while no bookmark left on `origin` after the push reaches that target
1396 (those left are the bookmarks no record names, where they are as of the
1397 last `fetch` or `push`, and the records' new targets);
1398 - the deletes would wait (below) and a bookmark it sets and one it deletes
1399 are a name and a name under it, such as `master` and `master/legacy`
1400 (not `master2`): git cannot hold both, so the first git push could not
1401 succeed.
1403 Targets and descent are commits as the remote has them: a target rewritten
1404 here since the last `fetch` or `push` is hidden, and not in the immutable
1405 set although the visible rewrite carries its change id and its label.
1406 Moving a bookmark whose current target is not immutable to an unrelated
1407 commit is allowed; that is how a rewritten stack is re-pushed. Deleting a
1408 bookmark on an immutable commit that another bookmark still reaches is how
1409 a merged feature's name is removed. It loses no history as long as that
1410 other bookmark is still where the last `fetch` or `push` left it: `push`
1411 does not ask the remote, so it does not notice a bookmark moved or deleted
1412 there since. The remote applies each update of a git push on its own, so
1413 when only records' new targets reach the commit, as when
1414 `rename "master" "main"` renames trunk's only bookmark, the deletes wait:
1415 the other updates are sent first, and the deletes in a second git push
1416 only once the remote has accepted every one of them. To rename trunk's
1417 only bookmark to a name under it, push a temporary label on its commit
1418 first, `push (label "tmp" (labelled "master"))`: with it on `origin`
1419 nothing waits, and `rename "master" "master/legacy"` goes as one git
1420 push; then `push (unlabel "tmp")`. The refusal gives these steps with the
1421 first of `tmp`, `tmp-1`, `tmp-2`, … that no bookmark, on `origin` or in
1422 the repository, and no record names, and that is not a name under one of
1423 those or one they are under: following them moves none of the user's
1424 bookmarks, and the refused push does not touch the label. After a
1425 successful push the labels reflect the new positions. It records one
1426 operation, even when it sends two git pushes. An empty list sends nothing
1427 to the remote, records no operation, and always reports that no updates
1428 were selected, with guidance for selecting a first bookmark. A nonempty
1429 successful push reports published, deleted, and unchanged bookmark counts
1430 on an interactive terminal, including an entirely unchanged selection.
1431 If the remote accepts some of the updates and rejects others, that
1432 operation records the accepted ones, whose labels move, and `push` exits 1
1433 naming the rejected bookmarks and any deletes it did not send.
1435Only the remote named `origin` is supported in this version; `fetch` and
1436nonempty `push` exit 1 with `j: no remote origin` when it is not configured.
1437Authentication is git's: the ssh agent for ssh URLs, git credential helpers
1438for https, as jj-lib's git backend provides them; `j` adds no prompting.
1439Bringing work up to date is a separate expression, e.g. `rebase trunk`.
1441### 7.7 Operations, undo, redo, and the lock
1443Every persisting `j` program, each `fetch`, and each nonempty `push` records
1444exactly one jj operation, described by the expression or command text. A push's
1445description includes its `push ` prefix, so an expression named `init` or
1446`clone` cannot be mistaken for the operation that created the repository.
1447Crashes record nothing, except as §7.5 step 7 says.
1449**Kinds.** An operation is *normal*, *undo*, or *redo*, determined by its
1450description. New undo and redo records use jj's current markers,
1451`undo: restore to operation <id>` and `redo: restore to operation <id>`.
1452The id names the exact operation whose view was restored, retaining the
1453navigation point for later undo and redo commands.
1454Older `j` markers (`undo: <id>` naming the discarded operation and
1455`redo: <id>` naming the reversed undo) and jj's legacy `undo operation <id>` /
1456`redo operation <id>` markers remain readable with their original meanings.
1457An operation without a recognized marker is normal, so mixed use degrades
1458to "undo the newest operation" where no marker is present.
1460For current markers, start at the head and follow restored-operation links
1461while their kind matches the command: undo links for `undo`, redo links for
1462`redo`. The command then selects that operation's parent. Follow links of
1463the same kind at the selected target too, and record the final target's id
1464and view. Reversing direction therefore restores the opposite marker's
1465parent, and either CLI can continue the other's undo/redo chain.
1467**`undo`** restores the state before the operation reached by that walk.
1468If no parent exists, or the operation reached is the `init` or `clone`
1469operation (§7.8), before which there was no repository, exit 1 with
1470`j: nothing to undo`.
1472**`redo`** requires the operation reached through redo links to be an undo;
1473it restores the state that undo discarded. Otherwise exit 1 with
1474`j: nothing to redo`.
1476For older `j` markers, undo follows an undo's discarded operation to its
1477parent, or a redo's reversed undo to the operation it discarded. Redo
1478follows a redo's reversed undo to its parent until it reaches an undo,
1479then restores that undo's parent. This preserves pending redos when a
1480history crosses from older markers into current ones.
1482Both refuse, before doing anything, if the working directory holds a change
1483the focused commit does not, as a snapshot would find it (§7.4; a stale
1484working copy holds none where the directory holds what was last checked out
1485or what the commit has). The refusal explains that `j id` preserves those
1486edits in a new operation, and the next undo reverses that recording before
1487reaching the earlier operation; users should inspect `j ops` and can recover
1488the recording with redo. Both record their operation and then check
1489out the restored focus, as persistence does (§7.5 step 7): a checkout that
1490fails leaves the operation recorded, and `redo` or `undo` goes back.
1491Undoing a `push` restores the recorded labels and leaves the remote untouched.
1493**`ops`** prints the operation log, newest first, one line each: relative
1494time, the operation's description (a `j` expression, a command, or another
1495tool's description), and `undo`/`redo` where applicable; the current
1496operation is marked. Rendered in the binary like `tree`.
1498**Lock.** A run that may persist (any expression evaluation, `fetch`, `push`,
1499`undo`, `redo`) takes an exclusive lock, the file `.jj/j.lock`, for its
1500duration.
1501A second `j` exits 2 with `j: another j is running in this repository`.
1502Display-only runs are not distinguishable in advance, so they take the lock
1503too; reserved commands that need no repository (`help`, `commands`, `init`,
1504`clone`) do not.
1505The lock prevents `j` from ever producing two commits with one change id.
1506Other tools operating concurrently are outside `j`'s control; if they produce
1507that state, §7.2 applies.
1509### 7.8 Creating and connecting repositories
1511- **`init`** creates a colocated repository (both `.jj` and `.git`) in the
1512 current directory. If `.git` already exists and `.jj` does not, jj is
1513 initialised on top of the existing git repository and its history is
1514 imported (subject to §7.2). Either way a working-copy commit is created as a
1515 child of the current head (or of the root commit for an empty repository)
1516 and checked out; the current head is git's `HEAD`, also when it is
1517 detached. Over an existing git repository the checkout writes no file: the
1518 working directory is taken as it is, and what it holds beyond the head
1519 becomes the working-copy commit's change. A checkout that fails leaves the
1520 operation recorded, as §7.5 step 7 says. It exits 2 if the directory is
1521 already inside a jj repository, or if `.git` exists but is not a directory
1522 (a git worktree or submodule). It requires `user` (§7.9).
1523- **`clone URL [DIR]`** creates `DIR` and its missing parents (exit 2 if
1524 `DIR` exists and is non-empty, or cannot be created, which includes a `DIR`
1525 such as `new/..` that names an existing directory once its parents exist),
1526 clones `URL` into it as a colocated repository, sets `origin` to `URL`,
1527 fetches, and creates a working-copy commit as a child of the remote's
1528 default bookmark target (or of the root commit if the remote has none),
1529 holding that target's files (see below), and checks it out. The default
1530 bookmark is the branch the remote's `HEAD` names. A clone that fails, its
1531 checkout included, or that is interrupted while it fetches (§1.3), records
1532 nothing and removes the `DIR` it created and each parent it created that is
1533 then empty, or empties the `DIR` it found empty, and nothing else. It
1534 removes or empties each only while its path still leads to that directory,
1535 so a symlink put in its place, or in place of a directory above it, is not
1536 followed: a path that leads elsewhere is left, and the error names it.
1537 Without `DIR`, it is the repository's name in `URL`, as `git clone` names
1538 it: the last component of `URL`'s path, a final `.git` component skipped,
1539 minus `.git` (`repo` for `/srv/repo/.git`, `host:repo.git` and
1540 `https://host/team/repo`); a `URL` that leaves no name, such as `/` or
1541 `..`, is a usage error asking for `DIR`. It requires `user`. Interactive
1542 confirmation includes a shell-quoted command to enter the clone directory
1543 and run `j status`; cloning cannot change the caller's working directory.
1544- **`remote URL`** sets the URL of `origin`, creating the remote if it does not
1545 exist. It does not fetch.
1547`clone` and `remote` store a `URL` that is a local path (one with no scheme
1548and no `host:` before its first `/`) as the absolute path it names from the
1549current directory, symlinks resolved, as `jj git clone` does (`git clone`
1550stores it absolute too), so that `fetch` and `push` reach it from wherever
1551they run. A local path that begins with `~` (`~/x.git`, `~user/x.git`) is
1552stored as given, since git expands it to that home directory on every
1553`fetch` and `push`; `./~/x.git` names a directory called `~`. Any other
1554`URL` is stored unresolved. A `URL` that cannot be parsed, or a path that
1555cannot be resolved or whose absolute path is not UTF-8, is a usage error
1556(exit 2) that changes nothing. `fetch` and `push` run git from the top of
1557the workspace, as git runs from the top of its working tree, so a relative
1558local path stored some other way (by `git remote add`, say) is resolved
1559from there, whichever directory they run in.
1561Besides jj's own record of the new workspace, `init` and `clone` each record
1562at most one operation, described `init` and `clone URL` (`URL` as given, a
1563local path as stored), holding what they imported and the working-copy
1564commit; `undo` never undoes it (§7.7). That commit holds its parent's files
1565less any at a path a checkout cannot create (§7.5 step 1), such as a
1566committed `.jj` directory: their removal is its change.
1568### 7.9 Identity
1570Commits are authored and committed as `user.name <user.email>` from
1571`config.j` (§6.3). `j` reads no other configuration; jj-lib's settings object
1572is constructed by `j` from `user` and fixed defaults. `init`, `clone`, and
1573persistence exit 3 if `user` is missing or malformed, since that is a
1574configuration error. Authoring also refuses blank fields or the shipped
1575`Your Name` / `you@example.com` placeholders (§6.2), with instructions to
1576edit the actual config file. Read-only expressions and unchanged results
1577remain available with placeholder identity. Successful interactive setup
1578reports the configured identity; terminal control characters are escaped
1579in confirmations without modifying the identity stored in commits.
1580`validate` checks the author identity when its argument differs from the
1581loaded repository, so validated previews report the same identity refusal
1582before saving. That refusal is a catchable crash, like other `validate`
1583failures. An unchanged `validate` and previews without `validate` remain usable.
1585### 7.10 External diff rendering
1587`difft p a b` runs difftastic. It is the only builtin that executes another
1588program.
15901. Write the content of `a` and `b` to files in separate `old` and `new`
1591 subdirectories of a fresh temporary directory. Each file keeps the last
1592 component of `p` unchanged, so valid names stay within the filesystem's
1593 length limit and difftastic sees the real filename. A last component
1594 that is not a filename is a crash; an empty path uses `file`.
15952. Run `difft OLD NEW` with the process's stdin closed and its environment
1596 inherited unchanged, except: if `DFT_COLOR` is unset and `j`'s stdout is a
1597 terminal, set `DFT_COLOR=always`; if `DFT_WIDTH` is unset and `j`'s stdout
1598 is a terminal, set it to the terminal width.
15993. Capture stdout; the program's stderr is `j`'s own, so what it says there
1600 reaches the user. Delete the temporary directory.
16014. Return stdout as `Text`. A non-zero exit status is not an error (difftastic
1602 uses it to signal "differences found" under some options), so what a
1603 `difft` that fails printed, even nothing, is the result; a failure to
1604 execute the program because it is absent uses the fallback below. Other
1605 launch failures are crashes naming the tool and the OS error.
1607If the executable is absent (`NotFound`), return a unified diff with three
1608lines of context and `--- a/PATH` / `+++ b/PATH` headers using the complete
1609path `p`. Paths containing whitespace or control characters are quoted.
1610Content that is not UTF-8 or contains NUL receives a binary-difference summary.
1611Equal bytes produce empty output. This fallback is usable without installing
1612another program or changing configuration.
1614All rendering options are difftastic's own, set through its `DFT_*`
1615environment variables. `j` adds no options of its own. `diff` remains
1616available as a dependency-free unified diff without path headers; the
1617reference `config.j` uses `difft` for display and receives the automatic
1618fallback when difftastic is absent.
1620Packaging: difftastic is an optional runtime enhancement; on Nix, wrap `j`
1621with `difft` on its `PATH`.
1623### 7.11 Tree rendering
1625`treeWith options r` renders the history as text. It is implemented in the
1626binary because it is presentation, not semantics. It reads the `Repo` value,
1627the immutable set (§7.5), `diff` sizes, and (for the margin, ages, and the
1628sibling order) jj's commit metadata by id.
1630#### Options
1632```
1633{ detail : Int -- 0, 1, or 2; see below
1634, margin : Bool -- age and author column
1635, elide : Bool -- fold uninteresting runs
1636, icons : Bool -- pictographic glyph set
1637, color : Text } -- "auto", "always", "never"
1638```
1640Commits with no stored counterpart — minted in this program, as in a dry
1641run — have no metadata: their margin cells are blank, their size bar is
1642computed from the value, and they sort last among their siblings. The same
1643holds for a `Commit` block in display (§5.1).
1645Missing fields crash. `color = "auto"` means colour iff stdout is a terminal
1646and `TERM` is not `dumb`.
1647If the environment variable `NO_COLOR` is set and non-empty, colour is never
1648used regardless of `color`. `config.j` fixes the defaults by defining `tree`.
1650#### Layout
1652Root at top, one line per commit, plus optional detail lines under the focus.
1654```
1655 ⌂ zzzz
1656 ╎ 14
1657 ◆ kpqx ▅ add parser main 3d mo
1658 ├─ ○ mnrv ▂ fix lexer 1d mo
1659 ▶ ├─ ⊗ wqzt ▃ wip feature 2h mo
1660 │ ✖ src/lexer.rs ~ src/parser.rs + tests/lexer.rs
1661 │ └─ ○ yxsk ▃ 1h mo
1662 └─ ◌ ptlm docs ⋯ 3 5d ak
1663```
1665(That is `detail = 2, margin = true`. With `detail = 1, margin = false`, the
1666size bars, the margin, and the detail line are absent.)
1668Columns, left to right:
16701. **Gutter**, two characters: `▶` on the focus line, blank otherwise.
16712. **Rails**: `│ ├─ └─`, two columns per depth; `╎ n` for an elided run
1672 (§Elision).
16733. **Node glyph**: what kind of commit.
16744. **Id**: shortest prefix unique among visible commits, minimum 4.
16755. **Size bar** (`detail ≥ 1`, focus and its parent and children only; all
1676 commits at `detail = 2`): one of `▁ ▂ ▃ ▅ ▇`, lines added plus removed
1677 by a shortest line diff against the parent, thresholds 1, 10, 50, 200,
1678 1000. Absent for empty commits. A changed path with no line added or
1679 removed (an empty file, a new file type) counts as one line.
16806. **Message**: first line; nothing if empty.
16817. **Labels**: right-aligned column, present only if any rendered commit has
1682 a label; names separated by two spaces.
16838. **Margin** (`margin = true`): age and author initials, right-aligned.
1684 Age is the committer time, rendered `Ns`, `Nm`, `Nh`, `Nd`, `Nw`, `Ny`.
1685 Initials are the first letters of the author name's words, at most two.
16869. **Collapse marker** `⋯ n` after the message of a collapsed subtree's top.
1688**Detail line** (`detail = 2`, focus only): indented under the focus, the
1689changed paths with a mark each: `+` added, `~` modified, `−` deleted,
1690`✖` unresolved. Renames are not detected; they appear as `−` and `+`.
1692#### Glyphs
1694| glyph | meaning | `icons = true` |
1695|---|---|---|
1696| `◉` | focus | `🌸` |
1697| `●` | ancestor of the focus | `🌿` |
1698| `○` | other commit | `🍃` |
1699| `◆` | in the immutable set (§7.5) | `🪨` |
1700| `◌` | empty: no change against its parent | `🫙` |
1701| `⊗` | has unresolved files | `🔥` |
1702| `⌂` | root | `🌱` |
1704Precedence when several apply: `⌂`, then `⊗`, then `◌`, then `◆`, then the
1705position glyphs; position is then carried by colour (and, for the focus, by
1706`▶`).
1708#### Elision (`elide = true`)
1710A commit is *interesting* if it is the focus, an ancestor of the focus, a
1711child of an ancestor of the focus, labelled, conflicted, a leaf, or has more
1712than one child. Runs of consecutive uninteresting commits on a single line of
1713descent are folded into `╎ n`. Subtrees whose top commit is not the focus, an
1714ancestor of it, or a child of an ancestor are rendered as their top commit
1715followed by `⋯ n` (omitted when `n = 0`), where `n` counts hidden descendants.
1716With `elide = false` everything is shown.
1718#### Colour
1720Applied only when colour is on. Glyphs always carry the meaning; colour only
1721adds emphasis, so a colourless rendering loses nothing.
1723| element | treatment |
1724|---|---|
1725| focus line | bold, faint background |
1726| ancestors of the focus | normal |
1727| all other lines | dim |
1728| rails on the path from the top to the focus | cyan |
1729| other rails, `╎ n`, `⋯ n` | dim |
1730| id of a conflicted commit | red |
1731| id of an immutable commit | blue |
1732| message of an empty commit | dim italic |
1733| labels | green |
1734| size bar | one accent colour, brighter with size |
1735| detail marks `+` `−` `~` `✖` | green, red, yellow, red |
1736| age | grey scale: brighter when more recent |
1737| author initials | a hue chosen per author, stable across runs (hash of the name) |
1739Messages are never coloured except dim (cousins) and dim italic (empty).
1741---
1743## 8. Laws
1745These hold for the reference `config.j` and should be property-tested against
1746an in-memory implementation of the builtins (§10). `=` means the results are
1747equal, with snapshots compared path by path (§7.3), or both crash.
1749```
1750by r.root.id r = r
1751prev (next r) = r (when r has exactly one child)
1752next (prev r) = r (when r is an only child)
1753top (top r) = top r
1754tip (tip r) = tip r
1755(abandon . new) r = r (up to the minted id of the new focus)
1756(abandon . contract m . split m) r = r (up to minted ids)
1757rebase parents r = r
1758goto here r = r
1759into i r = by i r (when i is a child of the focus)
1760at rs id r = r
1761(e or id) r = r (when e r crashes)
1762ancestors r = r.root.id :: ancestors (up r) (when up r exists)
1763forEach (const []) e r = r
1764eachChild id r = r
1765replayOnto (up r).root r = r
1766rewrite id r = r
1767replay b { from = b, to = x } = x
1768replay x { from = b, to = b } = x
1769invert (invert ch) = ch
1770touched (invert ch) = touched ch
1771from here f = f
1772concat [xs] = xs
1773concat (xs ++ ys) = concat xs ++ concat ys (both non-empty)
1774e or x = e (when e does not crash)
1775crash m or x = x
1776```
1778---
1780## 9. Reference `config.j`
1782This file is the complete definition of the language's vocabulary. It ships
1783with the binary and is the version installed to `~/.config/j/config.j`.
1785```haskell
1786-- config.j — everything j knows.
1788-- j reads this file on every run. An expression can use a name only if this
1789-- file declares it (a builtin, implemented by j) or defines it (written here,
1790-- in the language). Nothing else exists.
1792-- Conventions in this file:
1793-- Name = … a shape: a record layout, matched by its field names
1794-- name : Type a signature. Alone, it declares a builtin implemented
1795-- by j. Before a definition, it documents that definition.
1796-- Either way j checks arguments and results against it at
1797-- each call, one level deep: kind, list-ness, field names.
1798-- name = expr a definition. Functions are lambdas: name = \x -> …
1800-- Edits. Most definitions are Edits: functions from a Repo to a Repo. On the
1801-- command line a function result is applied to the current repository; a Repo
1802-- result is persisted. Anything else is printed. `e2 . e1` runs e1 then e2;
1803-- `e or id` runs e and leaves things alone if it crashes.
1805-- Four definitions here are read by j itself: `user` (who commits), `tree`
1806-- (how a Repo is printed), `immutable` (which commits may never be
1807-- rewritten), and `labelled` (what a %name literal means).
1810------------------------------------------------------------------------------
1811-- You
1812------------------------------------------------------------------------------
1814user : { name : Text, email : Text }
1815user = { name = "Your Name", email = "you@example.com" }
1818------------------------------------------------------------------------------
1819-- Shapes
1820------------------------------------------------------------------------------
1822Path = [Text] -- a file path as its components; written ./a/b
1823Label = Text -- a bookmark name on the remote
1825Entry = { path : Path, content : Blob }
1826Snapshot = [Entry] -- the files of one commit; paths unique;
1827 -- a deleted, resolved path has no entry
1828Change = { from : Snapshot, to : Snapshot } -- the files before and after
1830Commit = { files : Snapshot
1831 , message : Text
1832 , labels : [Label] -- the remote's names for this commit;
1833 -- read-only: only fetch and push change them
1834 , id : Id } -- each id is on exactly one commit
1836Subtree = { root : Commit, children : [Subtree] }
1838-- A Repo is the whole history, seen from one commit: the focused subtree plus
1839-- the path back to the top. Each Frame is one ancestor with a hole where the
1840-- focused subtree was; left and right are the siblings on either side. Sibling
1841-- order is presentation only.
1842Frame = { parent : Commit, left : [Subtree], right : [Subtree] }
1843Repo = { root : Commit, children : [Subtree], context : [Frame] }
1844 -- context = [] at the top of history
1846Detached = { subtree : Subtree, rest : Repo }
1847Rebase = { from : Snapshot, onto : Snapshot } -- the base a subtree was written on, and the new one
1848Meta = { hash : Text, author : Text, email : Text, time : Int }
1849 -- what jj records about a commit beyond the model
1851Edit = Repo -> Repo -- a command; may crash
1852Fileset = Path -> Bool -- which paths a command applies to
1853Revset = Repo -> [Id] -- a set of commits, computed from a repo
1855Push = { id : Id, name : Label } -- set the remote's bookmark `name` to `id`
1856Drop = { delete : Label } -- delete the remote's bookmark
1859------------------------------------------------------------------------------
1860-- Builtins: functions and control
1861------------------------------------------------------------------------------
1863(.) : (b -> c) -> (a -> b) -> a -> c -- composition, right to left
1864-- Return a value unchanged. As a repository command, `j id` records the
1865-- snapshotted working-copy edits in the focused commit. `j save` is the
1866-- descriptive alias in this reference config; inspections such as `j status`
1867-- and `j tree` do not record those edits.
1868id : a -> a
1869const : a -> b -> a
1870crash : Text -> a -- abort the program with a message
1872-- `a or b` is a keyword, not a builtin: the value of a; or, if evaluating a
1873-- crashed, the value of b. When a is a function and b is one too, the result
1874-- is pointwise, (f or g) x = f x or g x, so `edit or id` tries an edit and
1875-- keeps the repository if it fails. Edits compose with `.`: `tree . squash`
1876-- squashes, then renders.
1878------------------------------------------------------------------------------
1879-- Builtins: comparison, booleans, integers
1880------------------------------------------------------------------------------
1882(==) : a -> a -> Bool -- structural; functions crash
1883(/=) : a -> a -> Bool
1884(&&) : Bool -> Bool -> Bool -- short-circuit
1885(||) : Bool -> Bool -> Bool -- short-circuit
1886not : Bool -> Bool
1887(+) : Int -> Int -> Int
1888(-) : Int -> Int -> Int
1889(*) : Int -> Int -> Int
1890(<) : Int -> Int -> Bool
1891(<=) : Int -> Int -> Bool
1892(>) : Int -> Int -> Bool
1893(>=) : Int -> Int -> Bool
1894show : a -> Text -- any value, in this language's syntax
1896------------------------------------------------------------------------------
1897-- Builtins: lists and text
1898------------------------------------------------------------------------------
1900(::) : a -> [a] -> [a] -- cons
1901map : (a -> b) -> [a] -> [b]
1902filter : (a -> Bool) -> [a] -> [a]
1903length : [a] -> Int
1904null : [a] -> Bool
1905head : [a] -> a -- crash on []
1906tail : [a] -> [a] -- crash on []
1907last : [a] -> a -- crash on []
1908nth : Int -> [a] -> a -- 0-based; crash out of range
1909take : Int -> [a] -> [a]
1910drop : Int -> [a] -> [a]
1911member : a -> [a] -> Bool
1912range : Int -> Int -> [Int] -- range a b = [a (a+1) … (b-1)]
1913foldl : (b -> a -> b) -> b -> [a] -> b -- foldl f z [x y] = f (f z x) y
1915-- ++ and concat work on lists and on text. concat [] crashes: supply a
1916-- default with or, e.g. concat xs or []
1917(++) : m -> m -> m
1918concat : [m] -> m
1920startsWith : Text -> Text -> Bool
1921endsWith : Text -> Text -> Bool
1922splitOn : Text -> Text -> [Text] -- splitOn "/" "a/b" = ["a" "b"]
1924------------------------------------------------------------------------------
1925-- Builtins: the repository
1926------------------------------------------------------------------------------
1928-- Replay a change onto a snapshot: "onto, with the change from `from` to `to`
1929-- applied." Where the change collides with what is already there, the path's
1930-- blob is unresolved rather than an error, except that a collision making a
1931-- path a file on one side and a directory on another, as adding ./a/b onto a
1932-- file ./a would, crashes, naming the path (§7.3).
1933replay : Snapshot -> Change -> Snapshot
1934unresolved : Blob -> Bool
1936-- Paths edited in the working copy since the last recorded repository state.
1937-- `j status` includes this list; `j save` records it in the focused commit.
1938-- This measures the working copy, even when composed after an in-memory edit.
1939unrecorded : Repo -> [Path]
1940touchedPaths : Change -> [Path] -- paths whose content differs, one pass;
1941 -- blobs compared by content id, bytes never read
1942blob : Text -> Blob -- a resolved regular file
1943blobHex : Text -> Text -> Blob -- kind (regular/executable/symlink), hex bytes
1944text : Blob -> Text -- its content (markers if unresolved)
1945by : Id -> Repo -> Repo -- focus the commit with this id; crash if absent
1946lookupCommit : Id -> Repo -> Commit -- indexed commit lookup without moving the focus
1947lookupContent : Path -> Snapshot -> Blob -- indexed file content; an empty blob if absent
1948subtreeCommits : a -> [Commit] -- every commit of a tree in preorder, in one
1949 -- pass: what `commits` (below) is
1950meta : Id -> Meta -- git hash, author, email, committer time;
1951 -- crash for a commit not yet persisted
1952validate : Repo -> Repo -- the repo unchanged, or the crash persisting
1953 -- it would produce (shape, root, labels, immutability,
1954 -- focus). `tree . validate . rebase trunk` is an
1955 -- honest dry run.
1956diff : Blob -> Blob -> Text -- unified diff from the first to the second
1957difft : Path -> Blob -> Blob -> Text -- difftastic when difft is on PATH; otherwise
1958 -- unified diff with path headers and 3 context lines,
1959 -- or a binary-files summary. DFT_* configures difft.
1960treeWith : { detail : Int, margin : Bool, elide : Bool, icons : Bool, color : Text
1961 , lanes : Int, author : Bool, date : Bool, files : Bool }
1962 -> Repo -> Text -- the history as a tree; see the spec
1964-- Every subvalue of a given shape, however deeply nested. A shape is a type
1965-- name used as a value: extract Commit x, extract Id x, extract Push ys.
1966extract : Shape -> a -> [b]
1968-- Ids: an existing commit is written @kpqx (any unique prefix; checked before
1969-- the program runs). A bare @ is a new id, distinct each time it is evaluated.
1970-- A label is written %main and is a Revset: the commit the remote calls "main".
1973------------------------------------------------------------------------------
1974-- Zipper. A Repo is focused on one commit; these move or detach the focus.
1975-- Commands never select a commit by position: use ids, labels, or predicates.
1976------------------------------------------------------------------------------
1978-- To the parent. Crashes at the top.
1979up : Edit
1980up = \repo ->
1981 let f = head repo.context
1982 in { root = f.parent
1983 , children = f.left ++ [{ root = repo.root, children = repo.children }] ++ f.right
1984 , context = tail repo.context }
1986-- Detach the focused subtree; the focus moves to the parent. Crashes at the top.
1987detach : Repo -> Detached
1988detach = \repo ->
1989 let f = head repo.context
1990 in { subtree = { root = repo.root, children = repo.children }
1991 , rest = { root = f.parent, children = f.left ++ f.right, context = tail repo.context } }
1993-- To the top of history.
1994top : Edit
1995top = \repo -> top (up repo) or repo
1997-- Every commit of a subtree (or of the focused subtree of a Repo), in preorder.
1998-- Takes anything with `root` and `children`, so the signature is left open.
1999-- The builtin is \t -> t.root :: (concat (map commits t.children) or [])
2000-- in one pass; written that way it copies the list below every commit, and
2001-- so takes time quadratic in the length of the history.
2002commits : a -> [Commit]
2003commits = subtreeCommits
2006------------------------------------------------------------------------------
2007-- Structure. Editing at the focus.
2008------------------------------------------------------------------------------
2010mapRoot : (Commit -> Commit) -> Edit
2011mapRoot = \f repo -> repo { root = f repo.root }
2013mapChildren : ([Subtree] -> [Subtree]) -> Edit
2014mapChildren = \f repo -> repo { children = f repo.children }
2016-- Attach a subtree as a new child of the focus; the focus does not move.
2017attach : Subtree -> Edit
2018attach = \t -> mapChildren (++ [t])
2020-- Remove the focused commit; its children join the parent. Focus to the parent.
2021remove : Edit
2022remove = \repo -> let x = detach repo
2023 in x.rest { children = x.rest.children ++ x.subtree.children }
2025-- Attach a commit as a new child of the focus, and move to it.
2026addChild : Commit -> Edit
2027addChild = \c repo -> by c.id (attach ({ root = c, children = [] }) repo)
2029-- A new commit with these files, no message, no labels, and a new id.
2030newCommit : Snapshot -> Commit
2031newCommit = \files -> { files = files, message = "", labels = [], id = @ }
2034------------------------------------------------------------------------------
2035-- Snapshots, changes, and filesets
2036------------------------------------------------------------------------------
2038-- A path is written ./src/lexer.rs, which is ["src" "lexer.rs"]; ./ alone is
2039-- the root, []. For names the literal cannot spell, splitOn "/" "…" builds one.
2041restrict : Fileset -> Snapshot -> Snapshot -- entries matching m
2042restrict = \m -> filter (\e -> m e.path)
2044select : Fileset -> Snapshot -> Snapshot -> Snapshot -- m from a, the rest from b
2045select = \m a b -> restrict m a ++ restrict (neg m) b
2047-- Unresolved paths in a snapshot. For the focus, inspect `j status` or
2048-- `j conflicted . files`, edit the listed files to remove conflict markers,
2049-- then run `j save` and inspect `j status` again. See `j help conflicts`.
2050conflicted : Snapshot -> [Path]
2051conflicted = \s -> map (.path) (filter (\e -> unresolved e.content) s)
2053-- What the focus changes: its parent's files, and its own.
2054changeOf : Repo -> Change
2055changeOf = \repo -> { from = (up repo).root.files or [], to = repo.root.files }
2057-- The same change, backwards.
2058invert : Change -> Change
2059invert = \ch -> { from = ch.to, to = ch.from }
2061everything : Fileset
2062everything = const true
2064neg : Fileset -> Fileset
2065neg = \m -> not . m
2067both : Fileset -> Fileset -> Fileset
2068both = \m n p -> m p && n p
2070either : Fileset -> Fileset -> Fileset
2071either = \m n p -> m p || n p
2073under : Path -> Fileset -- inside directory d
2074under = \d p -> take (length d) p == d
2076ext : Text -> Fileset -- file extension e
2077ext = \e p -> endsWith ("." ++ e) (last p)
2080------------------------------------------------------------------------------
2081-- Revsets. A revset is a function from a Repo to a list of ids, so it can be
2082-- relative to the focus (parents, kids) or absolute (all, %main).
2083------------------------------------------------------------------------------
2085here : Revset
2086here = \repo -> [repo.root.id]
2088parents : Revset
2089parents = \repo -> [(up repo).root.id] or []
2091kids : Revset
2092kids = \repo -> map (\t -> t.root.id) repo.children
2094descendants : Revset -- includes the focus
2095descendants = \repo -> map (.id) (commits repo)
2097ancestors : Revset -- includes the focus
2098ancestors = \repo -> repo.root.id :: map (\f -> f.parent.id) repo.context
2100siblings : Revset
2101siblings = \repo -> filter (\i -> i /= repo.root.id) (kids (up repo)) or []
2103all : Revset
2104all = \repo -> descendants (top repo)
2106stack : Revset -- the line through the focus
2107stack = union ancestors descendants
2109labelled : Label -> Revset -- %main is labelled "main"
2110labelled = \n repo -> map (.id) (filter (\c -> member n c.labels) (commits (top repo)))
2112-- Evaluate f starting from each commit of rs, and collect.
2113from : Revset -> Revset -> Revset
2114from = \rs f repo -> concat (map (\i -> f (by i repo)) (rs repo)) or []
2116descendantsOf : Revset -> Revset
2117descendantsOf = \rs -> from rs descendants
2119ancestorsOf : Revset -> Revset
2120ancestorsOf = \rs -> from rs ancestors
2122union : Revset -> Revset -> Revset
2123union = \a b repo -> let xs = a repo in xs ++ filter (\i -> not (member i xs)) (b repo)
2125intersect : Revset -> Revset -> Revset
2126intersect = \a b repo -> let ys = b repo in filter (\i -> member i ys) (a repo)
2128minus : Revset -> Revset -> Revset
2129minus = \a b repo -> let ys = b repo in filter (\i -> not (member i ys)) (a repo)
2131matching : (Commit -> Bool) -> Revset -> Revset
2132matching = \p rs repo -> filter (\i -> p (commitAt i repo)) (rs repo)
2134-- Find every commit with unresolved files. `j conflicts` lists candidates;
2135-- use `j by @ID` to focus a mutable one, then `j status` to find its paths.
2136-- Edit each conflicted file, remove the conflict markers, and run `j save`.
2137-- Check `j status` again; `j clean` means the focus has no unresolved files,
2138-- not that the working copy has no unrecorded edits. `j review` shows the diff.
2139conflicts : Revset
2140conflicts = matching (\c -> not (null (conflicted c.files))) all
2142-- The first of several revsets that is non-empty.
2143firstOf : [Revset] -> Revset
2144firstOf = \rss repo -> foldl (\acc rs -> if null acc then rs repo else acc) [] rss
2146-- The main line: whichever of these names the remote has, first one wins.
2147-- Empty when no fetched remote label is named main, master, or trunk;
2148-- nothing is then immutable. Configure `j remote URL`, run `j fetch`, and
2149-- inspect `j tree` to see remote labels. A remote with another default label
2150-- needs this definition adjusted. Start work with j 'new . goto trunk'.
2151trunk : Revset
2152trunk = firstOf [%main %master %trunk]
2154-- Commits that may never be rewritten, abandoned, or focused. j evaluates this
2155-- before persisting anything and refuses to change what it names. Merge
2156-- commits and their ancestors are immutable regardless. The focus must always
2157-- be mutable, so it is `new . goto trunk`, never `goto trunk` alone.
2158immutable : Revset
2159immutable = ancestorsOf trunk
2162------------------------------------------------------------------------------
2163-- Focusing. `goto` is the only place a revset must have exactly one member.
2164------------------------------------------------------------------------------
2166-- Move to the single commit selected by a revset.
2167-- Example: j 'goto %feature'; use j 'new . goto trunk' to start on the main line.
2168goto : Revset -> Edit
2169goto = \rs repo ->
2170 let is = rs repo
2171 candidate = \i ->
2172 let c = commitAt i repo
2173 message = head (splitOn "\n" c.message)
2174 in " " ++ show i ++ " " ++ (if message == "" then "(no description)" else message) ++ "\n"
2175 in if length is == 1
2176 then by (head is) repo
2177 else if null is
2178 then crash "expected one revision, got 0; no matching revision. Run `j tree` to inspect available revisions. For a missing remote label such as %main or trunk, configure `j remote URL`, run `j fetch`, and check the label names in `j tree`."
2179 else crash ("expected one revision, got " ++ show (length is) ++ "\nCandidates:\n" ++ concat (map candidate (take 8 is)) ++ (if length is > 8 then " More candidates: run `j tree`.\n" else "") ++ "Choose a mutable commit with `j by @ID`, or start a child with `j 'new . by @ID'`; replace @ID with a candidate above.")
2181commitAt : Id -> Repo -> Commit
2182commitAt = lookupCommit
2184prev : Edit -- the parent
2185prev = goto parents
2187-- Move to the only child. At a tip, `j new` starts a child; when there are
2188-- several children, choose one of the candidates with `j by @ID`.
2189next : Edit
2190next = \repo -> if null (kids repo)
2191 then crash "next: this commit has no children; run `j new` to start a new child, or `j tree` to inspect the history"
2192 else goto kids repo
2194tip : Edit -- end of the line of only-children
2195tip = \repo -> tip (next repo) or repo
2197into : Id -> Edit -- a child, by id
2198into = \i repo -> if member i (kids repo) then by i repo
2199 else crash "into: not a child of the focus"
2201child : (Commit -> Bool) -> Edit -- the one child satisfying p
2202child = \p -> goto (matching p kids)
2204-- Run an edit somewhere else, then come back (by id, so the edit may move things).
2205at : Revset -> Edit -> Edit
2206at = \rs e repo -> let me = repo.root.id in by me (e (goto rs repo))
2208-- Run an edit at every commit of a revset, returning to the focus.
2209forEach : Revset -> Edit -> Edit
2210forEach = \rs e repo -> foldl (\acc i -> at (const [i]) e acc) repo (rs repo)
2212eachChild : Edit -> Edit
2213eachChild = forEach kids
2215guard : (Repo -> Bool) -> Edit -- crash unless p holds
2216guard = \p repo -> if p repo then repo else crash "guard"
2218-- Whether the focused commit has no unresolved files. This says nothing
2219-- about unrecorded working-copy edits; inspect those with `j unrecorded`.
2220clean : Repo -> Bool
2221clean = \repo -> null (conflicted repo.root.files)
2224------------------------------------------------------------------------------
2225-- Rebasing
2226------------------------------------------------------------------------------
2228-- Rewrite a subtree as if it had been written on `onto` instead of `from`.
2229-- Each commit's change is replayed onto the new base; its children are then
2230-- replayed from its old files onto its new ones.
2231replayTree : Rebase -> Subtree -> Subtree
2232replayTree = \rb t ->
2233 let c = t.root
2234 c' = c { files = replay rb.onto ({ from = rb.from, to = c.files }) }
2235 in { root = c', children = map (replayTree ({ from = c.files, onto = c'.files })) t.children }
2237-- Replay the focused subtree onto the commit newP, in place. The subtree stays
2238-- attached where it is; only its files change. Move it afterwards with detach
2239-- and attach. Crashes at the top.
2240replayOnto : Commit -> Edit
2241replayOnto = \newP repo ->
2242 let t = replayTree ({ from = (up repo).root.files, onto = newP.files })
2243 ({ root = repo.root, children = repo.children })
2244 in repo { root = t.root, children = t.children }
2246-- Replace the focused commit with f applied to it, replaying its children.
2247rewrite : (Commit -> Commit) -> Edit
2248rewrite = \f repo ->
2249 let c = repo.root
2250 c' = f c
2251 in (eachChild (replayOnto c') repo) { root = c' }
2254------------------------------------------------------------------------------
2255-- Commands
2256------------------------------------------------------------------------------
2258-- Record the current working-copy edits in the focused commit.
2259-- Example: j save; use j status first to inspect unrecorded paths.
2260-- This is id restricted to a Repo: the final Repo result triggers recording.
2261-- It does not publish anything. `j new` starts a child; `j id` records too.
2262save : Edit
2263save = id
2265-- Preview an edit and validate that its result could be recorded, then show
2266-- the resulting tree. This returns Text, so it records nothing.
2267-- Examples: j 'preview squash'; j 'preview (rebase trunk)'.
2268-- This helper is in the reference config. Existing custom configs are not
2269-- upgraded automatically; add it there or use `tree . validate . EDIT`.
2270preview : Edit -> Repo -> Text
2271preview = \edit -> tree . validate . edit
2273-- Set the message of the focused commit.
2274-- Example: j 'describe "fix login"'
2275describe : Text -> Edit
2276describe = \m -> mapRoot (\c -> c { message = m })
2278-- Start an empty child of the focus and move to it.
2279-- Examples: j new; j 'describe "next change" . new'
2280new : Edit
2281new = \repo -> addChild (newCommit repo.root.files) repo
2283-- Remove the focused commit. Its children are rebased onto its parent, and a
2284-- new empty commit on that parent becomes the focus (the parent may be
2285-- immutable, and the focus never is). Refused for a commit the remote has a
2286-- name for: push something else under that name first, or forget the name.
2287-- Example: j abandon; validate a preview first with j 'preview abandon'.
2288abandon : Edit
2289abandon = \repo ->
2290 let c = repo.root
2291 p = (up repo).root
2292 in if not (null c.labels)
2293 then crash ("abandon: the remote names this commit " ++ show c.labels)
2294 else new (remove (eachChild (replayOnto p) repo))
2296-- Push the files matching m from the focus down into its parent.
2297-- Example: j 'contract (ext "rs")'
2298contract : Fileset -> Edit
2299contract = \m repo -> let a = repo.root
2300 in at parents (rewrite (\q -> q { files = select m a.files q.files })) repo
2302-- Fold the focus entirely into its parent; a new empty commit becomes the focus.
2303-- Example: j squash; preview first with j 'preview squash'.
2304squash : Edit
2305squash = abandon . contract everything
2307-- Push the files matching m from the focus up into a new child, which becomes
2308-- the focus and inherits the old focus's children. Labels stay with the
2309-- original commit, since they are the remote's.
2310-- Example: j 'split (ext "rs")'; use (under ./src) to select a directory.
2311split : Fileset -> Edit
2312split = \m repo ->
2313 let a = repo.root
2314 p = (up repo).root
2315 a' = a { files = select m p.files a.files }
2316 x = newCommit a.files
2317 in by x.id (repo { root = a', children = [{ root = x, children = repo.children }] })
2319-- Move the focused subtree onto another commit. Returns to the moved commit.
2320-- Example: j 'rebase trunk'; preview with j 'preview (rebase trunk)'.
2321rebase : Revset -> Edit
2322rebase = \rs repo ->
2323 let d = (goto rs repo).root
2324 in if member d.id (descendants repo)
2325 then crash "rebase: the destination is inside the subtree being moved"
2326 else let me = repo.root.id
2327 x = detach (replayOnto d repo)
2328 in by me (attach x.subtree (by d.id x.rest))
2330-- Apply the focused commit's change onto another commit, as a new child there.
2331-- Example: j 'pick %main'
2332pick : Revset -> Edit
2333pick = \rs repo ->
2334 let ch = changeOf repo
2335 t = (goto rs repo).root
2336 in at rs (addChild (newCommit (replay t.files ch))) repo
2338-- A new child of the focus that undoes the change of the given commit.
2339-- Example: j 'backout %feature'
2340backout : Revset -> Edit
2341backout = \rs repo ->
2342 let ch = changeOf (goto rs repo)
2343 in addChild (newCommit (replay repo.root.files (invert ch))) repo
2346------------------------------------------------------------------------------
2347-- Pushing. `j push EXPR` evaluates EXPR to a list of Push and Drop records.
2348------------------------------------------------------------------------------
2350-- Label every commit of a revset. `j 'push (label "feature" here)'` labels @.
2351label : Label -> Revset -> Repo -> [Push]
2352label = \n rs repo -> map (\i -> { id = i, name = n }) (rs repo)
2354-- Remove a label on the remote. `j 'push (unlabel "feature")'` after the merge.
2355unlabel : Label -> [Drop]
2356unlabel = \n -> [{ delete = n }]
2358-- Move a label: `j 'push (rename "old" "new")'`.
2359rename : Label -> Label -> Repo -> [b]
2360rename = \old new repo -> label new (labelled old) repo ++ unlabel old
2362-- Every label the remote already has, at its current local commit.
2363-- `j push relabel` after rewriting a stack moves the remote's bookmarks along.
2364relabel : Repo -> [Push]
2365relabel = \repo -> concat (map (\c -> map (\n -> { id = c.id, name = n }) c.labels)
2366 (extract Commit repo)) or []
2369------------------------------------------------------------------------------
2370-- Inspection. These return printable values rather than a Repo.
2371------------------------------------------------------------------------------
2373focus : Repo -> Commit -- the focused commit
2374focus = \repo -> repo.root
2376files : Repo -> Snapshot -- its files
2377files = \repo -> repo.root.files
2379-- The entry at path p in snapshot s, as a list: [] if absent.
2380entryAt : Path -> Snapshot -> [Entry]
2381entryAt = \p s -> filter (\e -> e.path == p) s
2383-- The content at path p, or an empty file if absent.
2384contentAt : Path -> Snapshot -> Blob
2385contentAt = lookupContent
2387-- The paths a change touches.
2388touched : Change -> [Path]
2389touched = touchedPaths
2391-- Paths changed by the focused commit compared with its parent, including
2392-- the working-copy snapshot. These can remain nonempty after `j save`;
2393-- `j unrecorded` shows only working-copy edits not yet recorded.
2394-- Example: j changed
2395changed : Repo -> [Path]
2396changed = \repo -> touched (changeOf repo)
2398-- What the focus changes, one record per changed path. Uses difftastic when
2399-- installed; a missing difft falls back to a unified diff with path headers
2400-- and 3 context lines, or a binary-files summary.
2401diffs : Repo -> [{ path : Path, diff : Text }]
2402diffs = \repo ->
2403 let ch = changeOf repo
2404 in map (\p -> { path = p, diff = difft p (contentAt p ch.from) (contentAt p ch.to) }) (touched ch)
2406-- The same, as one page of text. A Text result prints raw, so `j review` is
2407-- readable in the terminal. A focus that changes nothing reads "no changes";
2408-- missing difft uses the built-in unified diff (path headers, 3 context lines)
2409-- or a binary-files summary. Other execution errors remain visible; an
2410-- installed difft's output, even nothing, is the page.
2411-- Example: j review; difftastic is optional.
2412review : Repo -> Text
2413review = \repo ->
2414 let ds = diffs repo
2415 in if null ds then "no changes\n" else concat (map (\d -> d.diff) ds)
2417-- A summary of the focus. `changed` lists changes in the commit compared
2418-- with its parent; `unrecorded` lists working-copy edits not yet recorded.
2419-- Inspection does not record anything. Run `j save` to record those edits.
2420-- Example: j status
2421status : Repo -> { id : Id, message : Text, labels : [Label], changed : [Path], conflicts : [Path], unrecorded : [Path] }
2422status = \repo ->
2423 { id = repo.root.id
2424 , message = repo.root.message
2425 , labels = repo.root.labels
2426 , changed = changed repo
2427 , conflicts = conflicted repo.root.files
2428 , unrecorded = unrecorded repo }
2430-- A summary of every commit, top first, in preorder.
2431-- Example: j log
2432log : Repo -> [{ id : Id, message : Text, labels : [Label], focus : Bool }]
2433log = \repo ->
2434 map (\c -> { id = c.id
2435 , message = c.message
2436 , labels = c.labels
2437 , focus = c.id == repo.root.id })
2438 (commits (top repo))
2440-- The history as a tree. Edit these records to change what `j tree` shows.
2441-- (The parentheses are required: `f { … }` would be a record update of f.)
2442-- The default `tree` shows every commit, sorted by time (parents always above
2443-- their children); `treeCompact` folds uninteresting runs and far subtrees.
2444-- Examples: j tree; j 'tree . squash' previews an edit without saving it.
2445tree : Repo -> Text
2446tree = treeWith ({ detail = 1, margin = false, elide = false, icons = false, color = "auto", lanes = 4, author = false, date = false, files = false })
2448treeCompact : Repo -> Text
2449treeCompact = treeWith ({ detail = 1, margin = false, elide = true, icons = false, color = "auto", lanes = 4, author = false, date = false, files = false })
2451treeFull : Repo -> Text
2452treeFull = treeWith ({ detail = 2, margin = true, elide = false, icons = false, color = "auto", lanes = 4, author = false, date = false, files = false })
2454-- The full tree plus the extra data columns: date, files changed, author.
2455treeData : Repo -> Text
2456treeData = treeWith ({ detail = 2, margin = true, elide = false, icons = false, color = "auto", lanes = 4, author = true, date = true, files = true })
2457```
2459---
2461## 10. Testing
2463The interpreter must be testable without a jj repository. Provide an in-memory
2464implementation of the domain builtins (`replay`, `unresolved`, `blob`, `blobHex`,
2465`text`, `by`, `extract`, `meta`, `difft` as a stub, and the minting
2466of `@`) in which a resolved blob carries bytes and a file kind, a
2467conflict is a record of the three sides, and `replay` resolves a path exactly
2468when at most one side changed it or both made the same change, path by path
2469even where a file meets a directory, which jj merges as one value (§7.3).
2470Property-test the laws of §8 over randomly generated `Repo` values (bounded
2471depth and width, random labels, random file edits) using the reference
2472`config.j` unmodified.
2474The builtin `by` must agree, on every generated repo, with this in-language
2475reference definition, which uses positional moves the public base does not
2476expose:
2478```haskell
2479down = \i repo ->
2480 let k = nth i repo.children
2481 in { root = k.root, children = k.children
2482 , context = { parent = repo.root, left = take i repo.children, right = drop (i + 1) repo.children }
2483 :: repo.context }
2484locs = \l -> l :: (concat (map (\i -> locs (down i l)) (range 0 (length l.children))) or [])
2485by = \i repo -> head (filter (\l -> l.root.id == i) (locs (top repo))) or crash "by: no such commit"
2486```
2488Golden tests: parse the reference `config.j`; `show` round-trips through the
2489parser for generated values of every kind except closures; every example in
2490§11 produces the stated result.
2492---
2494## 11. The development flow, end to end
2496Each step of ordinary development, and what covers it. Anything not listed
2497here is out of scope (§12). Nothing here uses the `jj` binary.
2499**Getting a repository**
2501```
2502j setup 'Your actual name' you@your-domain.example -- create the full config once
2503j init -- new repository here, or adopt an existing .git
2504j clone git@host:org/repo.git project -- or clone an existing one
2505cd project -- after clone, enter its directory
2506j remote git@host:org/repo.git -- attach a remote to an init'd repo
2507```
2509**Looking**
2511```
2512j tree -- the history as a tree, focus marked
2513j treeFull -- the same with sizes, ages, authors, changed paths
2514j status -- focus, in-commit changes, unrecorded edits, conflicts
2515j log -- every commit as a record
2516j review -- difftastic or unified diff of @ against its parent
2517j review . by @kpq -- the same for another commit, without moving
2518j diffs -- the same, one record per path
2519j here -- @'s id
2520j kids -- @'s children, as a commit table
2521j conflicts -- every conflicted commit
2522j 'map (.path) . files' -- paths tracked in @
2523j 'text . contentAt ./README.md . files'
2524j focus -- the focused commit
2525j 'meta . (.id) . focus' -- its git hash, author, time
2526```
2528**Working**
2530```
2531j 'describe "fix login"'
2532j new -- start the next commit
2533j prev -- to the parent
2534j next -- to the only child
2535j new . goto trunk -- start on the main line; the focus must be a mutable commit
2536j by @kpq -- any unique id prefix
2537j into @kpq -- a child, by id
2538j 'child (\c -> startsWith "fix" c.message)'
2539j 'split (ext "rs")' -- *.rs changes into a new child
2540j 'contract (under ./docs)' -- docs/ changes down into the parent
2541j squash
2542j abandon
2543j rebase trunk
2544j guard clean . rebase trunk or id -- only if it comes out clean
2545j pick @kpq
2546j 'forEach (descendantsOf here) (describe "wip")'
2547j save -- record the working directory, change nothing else
2548j 'preview squash' -- validate and show the result without saving
2549j tree . squash -- dry run: show the result, persist nothing
2550j tree . validate . squash -- the same, refusing what persistence would refuse
2551j squash && j tree -- do, then look
2552```
2554**Sharing**
2556```
2557j 'push (label "feature" here)' -- name @ on the remote
2558j push relabel -- move the remote's existing names to the rewritten stack
2559j 'push (unlabel "feature")' -- delete a name on the remote
2560j 'push (rename "old" "new")' -- move a name
2561j fetch -- refresh the remote's names and commits
2562j rebase trunk -- bring the stack up to date
2563```
2565**Conflicts**
2567A rebase or fetch that conflicts leaves unresolved files in the affected
2568commits. `j conflicts` lists them; `j by @…` moves there, which checks the
2569files out with conflict markers; editing the files and running any persisting
2570expression (`j save` or `j id` at minimum) records the resolution. Run
2571`j status` to verify `No conflicts` and `All edits recorded` in the focus,
2572and `j conflicts` to check the rest of the history. No continue command is
2573needed.
2575**Mistakes**
2577```
2578j ops -- what happened, newest first
2579j undo -- reverts one j expression
2580j redo
2581```
2583**Own commands**
2585Any definition added to `config.j` whose value is an `Edit` is a command:
2587```haskell
2588pr = \n -> describe n . prev . squash
2589```
2591```
2592j 'pr "fix login"' && j 'push (label "fix-login" here)'
2593```
2595---
2597## 12. Out of scope for this version
2599Second parents of merge commits (merges are placed under their first parent
2600and are read-only); hunk-level `split`; conflict resolution inside the
2601language (blobs are opaque); workspaces other than the default; sparse working
2602copies (refused; §7.1); remotes other than `origin`; tags; submodules and LFS;
2603ignore rules beyond `.gitignore`; repairing a repository in which one change
2604id has two visible commits (refused; §7.2); general command flags beyond the
2605`--help` and `-h` discovery arguments; static typing. None of
2606these are precluded by the design.