on master help sign in
j/README.md
621 lines 22 kB history raw
1<p align="center">
2 <img src="logo.png" alt="j logo" width="200">
3</p>
5<p align="center"><em>Your repo is a function (not really)</em></p>
7**`j` is a functional-programming-centered command-line interface to Jujutsu
8(jj) repositories.** Instead of subcommands and flags, you write expressions in
9a small, pure functional language that transform the repository. The repository
10is a *value*, a command is a *function from repository to repository*, and
11everyday work is done by composing those functions.
13`j` is not a new version-control system. The storage, data model, and on-disk
14format are jj's (which is git-compatible — `j` works directly on a colocated
15`.jj`/`.git` repository, with no `jj` binary required). What `j` replaces is
16the *interface*.
18```
19j 'describe "wip"' -- set the focused commit's message
20j 'new' -- start a new commit on top
21j 'describe "wip" . new' -- compose: new commit, then describe it
22j squash -- fold the focus into its parent
23j 'tree' -- print the history tree
24```
26The whole vocabulary — `new`, `describe`, `squash`, `tree`, `rebase`, … — is
27written *in the language* in `config.j`, and you extend it by writing more
28functions.
30## Find a command
32```
33j help -- a quick start, grouped commands, and examples
34j commands -- common tasks and how to do them
35j commands all -- the full vocabulary in your config
36j commands rebase -- search names, signatures, and descriptions
37j help describe -- see a command's signature, documentation, and examples
38j help push -- learn a reserved command's usage
39j help config -- find your config and set your identity
40```
42`j --help` and `j -h` also open help. A separate trailing help argument, such
43as `j abandon --help`, opens that command's help without executing it.
44Help and command discovery work outside a repository and never change your
45files or configuration. The catalog includes
46your own definitions, even ones without a signature; when no config exists, it
47uses the embedded reference config. General help and help for reserved commands
48are available even if your config is broken.
50Set up with your own name and email, then choose one starting point:
52```sh
53j setup 'Ada Lovelace' ada@example.org
55# Start a new project
56mkdir project && cd project
57j init
58```
60```sh
61# Or join an existing project
62j clone URL project
63cd project
64```
66`init` and `clone` leave you on a working-copy commit: the commit you are
67editing now. Edit files, then run `j 'describe "first change"'` to save the
68files and their description. Use `j save` to save files without changing the
69description. Run `j new` **before** editing the next change. `j status` shows
70both changes in the commit and edits that still need saving; `j tree` shows
71where that commit sits in history. Compose commands right to left:
72`j 'describe "first change" . new'` creates a commit, then describes it.
73Preview an edit with `j 'preview squash'`. Search familiar tasks with
74`j commands commit`, `j commands checkout`, or `j commands branch`.
76---
78## Why `j`?
80| | |
81|---|---|
82| **No staging area** | Like jj, the working copy *is* a commit; there's no `git add` step. |
83| **Stable change ids** | A commit keeps its id (`@wqzt…`) across `describe`, `squash`, `rebase`. History editing is safe to talk about. |
84| **First-class undo** | Every operation is recorded. `j undo` / `j redo` / `j ops`, not a forensic reflog. |
85| **Composable commands** | A command is a function. `describe "wip" . new . (goto %main)` is one expression, not three commands. |
86| **Programmable** | The vocabulary is `config.j`, written in the language. Add your own edits, revsets, and inspections. |
87| **Total operations** | A conflicting `replay` produces an unresolved blob, not a halt. Resolve whenever you like. |
89---
91## Installation
93### With Nix (recommended)
95The repository provides a flake with one default binary, `j`. Difftastic is a
96runtime enhancement and is wired in automatically.
98```
99nix build # builds ./result/bin/j
100nix run # run j directly
101```
103The reference `config.j` is installed alongside the binary
104(`<prefix>/share/j/config.j`) and used if you have no user config.
106### From source
108```
109cargo build --release # produces target/release/j
110```
112Run `j setup` to create the reference `config.j` (see next section).
113[Difftastic](https://difftastic.wilfred.me.uk/) on your `PATH` improves
114`review`/`difft`; without it they use a unified diff.
116---
118## Configuration
120### Terminal colors and motion
122In an interactive terminal, `j` uses vivid branch colors, a blue focus band,
123colorful data and status messages, and animated progress indicators while
124repository operations or expressions run. Each indicator names the current
125operation and shows a spinner, a moving activity bar, and elapsed time. The
126bar shows activity, not a completion percentage; on narrow terminals it makes
127room for the operation's name. Colored trees and tables appear in a quick
128cascade. Progress starts only when an operation takes a moment; fast commands
129do not wait for a spinner.
131To keep the colors but turn off animation:
133```sh
134J_ANIMATIONS=never j tree
135```
137Set `NO_COLOR=1` for plain, motion-free output. Motion is also disabled when
138either output stream is redirected, `TERM=dumb`, or `CI` is nonempty. Automatic
139colors follow the terminal for each stream; piped output stays plain unless
140you explicitly request `treeWith`'s `color = "always"`. `NO_COLOR` takes
141precedence even over that setting.
143Interactive edits report `Saved changes` or `No changes`, followed by the
144focused commit's short id and description. `NO_COLOR=1` and `TERM=dumb` keep
145these confirmations in plain text. Success confirmations are suppressed when
146either output stream is redirected or CI is set; warnings and errors still
147appear.
149### User config
151`j setup 'Your actual name' you@your-domain.example` creates the full reference
152config with your identity. `j setup` without arguments creates an editable
153default and tells you where to set the identity. Neither form overwrites an
154existing file; use `j help config` to find and edit it.
156Expressions read `~/.config/j/config.j` (or `$XDG_CONFIG_HOME/j/config.j`).
157An expression can only use a name this file declares or defines. The reference
158[`config.j`](config.j) ships with the binary. Commands that execute against a
159repository create an editable copy there when it is missing; help and discovery
160use the embedded copy without writing it. Edit at least the identity:
162```
163user = { name = "Ada Lovelace", email = "ada@example.org" }
164```
166Use your own name and email. `j init`, `j clone`, and edits that save changes
167reject empty fields and the shipped `Your Name` / `you@example.com`
168placeholders. Interactive setup confirms the identity it used. `j help config`
169shows the actual config path and remains available when the file is broken.
171Existing configurations keep their own vocabulary. To adopt new helpers,
172copy the `save` and `preview` definitions, the `unrecorded` declaration, and
173the updated `status` definition from the [reference config](config.j), preserving your
174identity and custom definitions. `j setup` does not upgrade existing files.
176The reference config defines the entire base vocabulary (see
177[docs/base.md](docs/base.md)). Four definitions are read by `j` itself: `user`
178(who commits), `tree` (how a `Repo` prints), `immutable` (which commits may
179never be rewritten), and `labelled` (what a `%name` literal means).
181---
183## How it works
185Every expression run:
1871. Snapshots the working directory for evaluation.
1882. Builds a `Repo` value focused on the working-copy commit.
1893. Evaluates your expression.
1904. If the result is a function, applies it to the `Repo`.
1915. If the final value is a `Repo` that changed, persists it. An unchanged
192 `Repo` saves nothing; other values print without saving.
194So most of what you write is an **edit** — a function `Repo -> Repo`. A result
195that's plain data is printed and persists nothing (a dry run).
196`j status` sees current file edits but does not record them. Use `j save` to
197record those edits without changing anything else before pushing.
199```
200j 'length . commits . top' -- a number: how many commits? prints, persists nothing
201j squash -- an edit: persists the squash
202j 'tree . squash' -- a Text: shows what squash *would* do, persists nothing
203```
205The repository is applied **implicitly** — there's no `repo` variable; write a
206function and it receives the repository.
208---
210## Frequent examples
212Each of these is a complete command you can run. Edits persist; inspections
213print.
215### Start and describe work
217```
218j 'new'
219```
221Starts an empty child of the focused commit and moves to it. Edit files in
222your editor, then:
224```
225j 'describe "add the lexer"'
226```
228Sets the message of the focused commit. The two compose:
230```
231j 'describe "add the lexer" . new'
232```
234Opens a new commit *and* describes it, in one step.
236### See where you are
238```
239j 'status'
240```
242A summary of the focus: id, message, labels, changed paths, unrecorded edits,
243and conflicted paths. `in commit` (the `changed` field) compares the commit
244with its parent;
245`unrecorded` compares the current files with their last saved state. After
246`j save`, a commit can still have changed paths while all edits are recorded.
248```
249in commit No changes
250conflicts No conflicts
251id zrkmkkvrvtokumkuzrkmkkvrvtokumku
252labels No labels
253message add a library
254unrecorded All edits recorded
255```
257```
258j 'files'
259```
261The files of the focused commit, with sizes.
263```
264j 'changed'
265```
267The paths whose content differs between the focus and its parent.
269### See the history
271```
272j 'tree'
273```
275The history as a tree, focused commit marked:
277```
278 ⌂ zzzz
279 └─ ● rrtv ▂
280 └─ ● xqsr ▂ start the project
281▶ └─ ◌ zrkm add a library
282```
284```
285j 'treeFull'
286```
288The same tree with ages and authors in the margin.
290```
291j 'log'
292```
294A table of every commit, top first, with a `✓` on the focus, short ids, and
295label names. Tables fit the terminal width, switching to fields on separate
296lines on very narrow terminals. Redirected output preserves full cell text.
298```
299j 'review'
300```
302The focus's changes as one page of diffs, using difftastic when available
303and a unified diff otherwise.
305### Move around
307Navigation checks out the selected commit's files so you can edit them.
309```
310j 'prev' -- to the parent
311j 'next' -- to the only child
312j 'tip' -- to the tip of the current line
313j 'by @wqzt' -- to a specific commit, by id
314j 'new . goto trunk' -- start a change on top of the protected main line
315```
317Use `j 'tree . goto trunk'` to inspect main without moving the working copy.
318At a fork, use an id from `j tree` with `by`; `next` requires one child.
319Main must exist on the remote (`j fetch`) before `trunk` can select it.
321### Undo and history of actions
323```
324j undo -- revert the last j expression
325j redo -- reapply it
326j ops -- the operation log, newest first
327```
329Undo and redo require a working copy with no unrecorded edits. If you run
330`j id` to record edits first, that creates a new operation: the next `j undo`
331undoes the recording, and another undo reaches the preceding edit. A new
332recording also clears pending redos. Inspect `j ops` when deciding how far to
333go back. Interactive confirmations name the affected operation and restored
334focus.
336### A safe dry run
338`preview` validates an edit and returns its resulting tree without saving:
340```
341j 'preview squash'
342j 'preview (rebase trunk)'
343```
345This is shorthand for `tree . validate . EDIT`. `tree . EDIT` also previews,
346but does not check whether the result can be saved. `validate . EDIT` alone
347**saves** a changed repository; validation is not a dry-run mode.
349---
351## Editing history
353These are the everyday history edits. Each is an `Edit`.
355| command | what it does |
356|---|---|
357| `j 'describe "…"'` | set the focus's message |
358| `j new` | start an empty child of the focus |
359| `j squash` | fold the focus entirely into its parent |
360| `j abandon` | drop the focus; its children join the parent |
361| `j 'split <fileset>'` | push matching files up into a new child commit |
362| `j 'contract <fileset>'` | push matching files down into the parent |
363| `j 'rebase <revset>'` | move the focused subtree onto another commit |
364| `j 'pick <revset>'` | copy the focus's change onto another commit |
365| `j 'backout <revset>'` | a new commit undoing another commit's change |
367### `squash` — fold a commit into its parent
369```
370j squash
371```
373Given `base work` → `more work`, after `j squash` the `more work` commit is
374gone, its files folded into `base work`, and a fresh empty commit is the
375focus:
377```
378 ⌂ zzzz
379 └─ ● opwp ▂
380 └─ ● zqsq ▂ base work
381▶ └─ ◌ nttk
382```
384### `abandon` — drop a commit
386```
387j abandon
388```
390Removes the focus and rebases its children onto the parent. Refused for a
391commit the remote has a name for (push something else under that name first).
393### `split` / `contract` — move changes by fileset
395A **fileset** is a function `Path -> Bool`. `split` pushes the matching files
396up into a new child commit; `contract` pushes them down into the parent.
398```
399j 'split (ext "rs")'
400```
402Takes a commit touching `a.rs` and `b.j`, and splits it: the `.rs` change
403becomes a separate child commit (now the focus), the `.j` change stays behind.
405```
406j 'contract everything'
407```
409Pushes *all* of the focus's files into the parent (the inverse of `split`).
410`squash` is just `abandon . contract everything`.
412Filesets compose: `under ./src`, `ext "rs"`, `both`, `either`, `neg`,
413`everything`. So `split (both (under ./src) (ext "rs"))` splits off only the
414Rust files under `src/`.
416### `rebase` / `pick` / `backout`
418```
419j 'rebase %main' -- move the current stack onto main
420j 'pick @wqzt' -- copy @wqzt's change here as a new commit
421j 'backout @wqzt' -- a new commit undoing @wqzt's change
422```
424`rebase` moves the focused subtree (and crashes if the destination is inside
425it). `pick` copies a change without moving anything. `backout` replays a
426change's *inverse*.
428---
430## Labels and the remote
432A **label** is a bookmark name on the remote, shown on a commit's `labels`.
433Labels are read-only in the language — only `fetch` and `push` change them.
435```
436j 'remote URL' -- set origin's URL
437j fetch -- fetch from origin
438```
440`j push EXPR` evaluates `EXPR` to a list of push/drop records:
442```
443j 'push (label "feature" here)' -- point the "feature" bookmark at the focus
444j 'push (rename "old" "new")' -- rename a bookmark on the remote
445j 'push (unlabel "old-feature")' -- delete a bookmark
446j 'push relabel' -- after a rewrite, re-point the remote's bookmarks
447```
449Push sends recorded content. If files have changed since the last saved edit,
450it warns that those changes are omitted, then sends the recorded commits.
451Run `j save` and push again to include them; `j status` alone does not record
452changes.
454For the first publication, choose a bookmark name with
455`j 'push (label "feature" here)'`. `j push relabel` updates existing bookmarks;
456it does not create the first one. Push reports when no updates were selected,
457and gives counts of published, deleted, and unchanged bookmarks for a
458nonempty selection in an interactive terminal.
460### Resolve conflicts
462A history edit can succeed with conflicts. Run `j status` to find conflicted
463files, inspect them with `j review`, and edit the files to remove the conflict
464markers and keep the intended content. Run `j save`, then `j status` again
465to check for `No conflicts` and `All edits recorded`. There is no separate
466continue command. `j conflicts` lists conflicted commits across history;
467use `j 'by @id'` to work on another mutable commit when needed, and check
468`j conflicts` again after resolving it.
470---
472## Advanced examples
474These show the language doing things that take several commands (or aren't
475possible) in other tools.
477### Describe every commit in a stack at once
479```
480j 'forEach descendants (describe "wip")'
481```
483`forEach` is an ordinary function `Revset -> Edit -> Edit`: it runs an edit at
484every commit a revset names, returning to the focus. This one marks every
485commit below the focus `wip`.
487### Find commits by any predicate
489```
490j 'matching (\c -> c.message == "wip") all'
491```
493`matching p rs` keeps the commits of revset `rs` satisfying predicate `p`, as a
494revset — here, every commit whose message is `wip`. Since the result is a list
495of commits, it prints (and persists nothing).
497### Count things
499```
500j 'length . commits . top'
501```
503Composes three functions into `Repo -> Int`: the number of visible commits.
505### An honest dry run of a complex edit
507```
508j 'tree . validate . rebase %main'
509```
511Shows the tree as it would look after rebasing onto main, *without persisting
512anything*. And because `validate` crashes with the exact error persistence
513would raise, this is honest: if the rebase couldn't actually happen (say `%main`
514doesn't exist yet, or the destination is inside the moved subtree), you see
515that crash here instead of after a real attempt.
517```
518j 'tree . validate . squash'
519```
521The same idea for a simpler edit: renders the post-squash tree, and a following
522`j tree` confirms nothing changed.
524### Run an edit elsewhere, then come back
526```
527j 'at %main (describe "released")'
528```
530Describes `main`, then returns the focus to where it was. `at rs e` runs edit
531`e` at the commit revset `rs` names and comes back by id.
533### Combine edits into a single operation
535```
536j 'describe "hotfix" . new . (goto %main)'
537```
539Go to main, open a new commit, describe it — one expression, one recorded
540operation. With `or` you get a fallback:
542```
543j 'rebase %main or id'
544```
546Rebase if you can; leave the repository alone if it crashes.
548### Define your own command
550Anything added to `config.j` whose value is an `Edit` is a new command:
552```
553-- in config.j: squash into the parent and name the combined commit "release"
554release : Edit
555release = describe "release" . prev . squash
556```
558Then `j release` works like any built-in.
560---
562## Reserved commands
564A handful of commands are built in (not expressions): they provide help,
565create or connect repositories, move refs, and walk the operation log.
567| command | what it does |
568|---|---|
569| `j help [NAME]` | show a quick start or help for a reserved command or config name |
570| `j commands [QUERY]` | show common tasks, search by task/name, or use `all` for the full vocabulary |
571| `j setup [NAME EMAIL]` | create the full reference config, optionally with your identity; never overwrite an existing file |
572| `j init` | create a colocated `.jj`/`.git` repository here (adopting an existing `.git`) |
573| `j clone URL [DIR]` | clone `URL` into `DIR` (default: the repository's name, as `git clone` picks it) |
574| `j remote URL` | set `origin`'s URL |
575| `j fetch` | fetch from `origin` |
576| `j push EXPR` | evaluate `EXPR` to push/drop records and push them |
577| `j undo` / `j redo` | walk the operation log |
578| `j ops` | print the operation log |
580`--help` and `-h` open help as the first word or as a separate argument after
581the command: `j --help describe`, `j describe --help`, and `j describe -h`
582all open help for `describe`. Inside a single expression argument or stdin,
583language comments still apply: `j 'new --help'` executes `new`. There are no
584other general command flags. Everything else is an expression in the language.
586Quote literal reserved-command arguments separately to keep spaces intact:
587`j clone URL 'my project'` and `j remote '/path/to/shared repo.git'`. A whole
588reserved command supplied as one string or on stdin is split on whitespace.
590---
592## Documentation
594| document | contents |
595|---|---|
596| **[docs/tutorial.md](docs/tutorial.md)** | A guided first hour: the mental model (implicit repo application, edits, revsets, filesets), dry runs, `or`, history editing, batch operations, and writing your own commands. The best place to start learning. |
597| **[docs/language.md](docs/language.md)** | The `j` language in detail: values, syntax, semantics, builtins, contracts, `show`, the `Repo` zipper, and many examples. Start here to learn the language. |
598| **[docs/base.md](docs/base.md)** | The complete base vocabulary: every builtin and every `config.j` type and function, grouped logically, each with a description and examples, plus an alphabetical index. |
599| **[docs/comparison.md](docs/comparison.md)** | A structured three-way comparison of git, jj, and `j`: concept mappings, side-by-side command tables, and a full workflow in each. |
600| **[specs/main.md](specs/main.md)** | The normative specification of the language, the CLI, and repository semantics. |
601| **[config.j](config.j)** | The reference configuration: the entire base vocabulary, written in the language. |
603---
605## Project layout
607```
608config.j the reference base vocabulary
609src/ the j implementation (Rust, on jj-lib)
610tests/ unit, property, and CLI end-to-end tests
611docs/ language.md, base.md, comparison.md
612specs/ the language, CLI, repository, and tree specifications
613flake.nix Nix package: one binary, j, with difftastic as a runtime dep
614```
616### Development
618```
619cargo build # build
620cargo test # run the test suite
621```