just playing with tangled
1# Frequently asked questions
2
3### Why does my bookmark not move to the new commit after `jj new/commit`?
4
5If you're familiar with Git, you might expect the current bookmark to move forward
6when you commit. However, Jujutsu does not have a concept of a "current bookmark".
7
8To move bookmarks, use `jj bookmark move`.
9
10### I made a commit and `jj git push --all` says "Nothing changed" instead of pushing it. What do I do?
11
12`jj git push --all` pushes all _bookmarks_, not all revisions. You have two
13options:
14
15* Using `jj git push --change` will automatically create a bookmark and push it.
16* Using `jj bookmark` commands to create or move a bookmark to either the commit
17 you want to push or a descendant on it. Unlike Git, Jujutsu doesn't do this
18 automatically (see previous question).
19
20### Where is my commit, why is it not visible in `jj log`?
21
22Is your commit visible with `jj log -r 'all()'`?
23
24If yes, you should be aware that `jj log` only shows the revisions matching
25`revsets.log` by default. You can change it as described in [config] to show
26more revisions.
27
28If not, the revision may have been abandoned (e.g. because you
29used `jj abandon`, or because it's an obsolete version that's been rewritten
30with `jj rebase`, `jj describe`, etc). In that case, `jj log -r commit_id`
31should show the revision as "hidden". `jj new commit_id` should make the
32revision visible again.
33
34See [revsets] and [templates] for further guidance.
35
36### What are elided revisions in the output of `jj log`? How can I display them?
37
38"Elided revisions" appears in the log when one revision descends from another,
39both are in the revset, but the revisions connecting them are _not_ in the
40revset.
41
42For example, suppose you log the revset `tyl|mus` which contains exactly two
43revisions:
44
45```sh
46$ jj log -r 'tyl|mus'
47○ musnqzvt me@example.com 1 minute ago 9a09f8a5
48│ Revision C
49~ (elided revisions)
50○ tylynnzk me@example.com 1 minute ago f26967c8
51│ Revision A
52```
53
54Only the two revisions in the revset are displayed. The text "(elided
55revisions)" is shown to indicate that `musnqzvt` descends from `tylynnzk`, but
56the nodes connecting them are not in the revset.
57
58To view the elided revisions, change the [revset expression](revsets.md) so it
59includes the connecting revisions. The `connected()` revset function does
60exactly this:
61
62```sh
63$ jj log -r 'connected(tyl|mus)'
64○ musnqzvt me@example.com 43 seconds ago 9a09f8a5
65│ Revision C
66○ rsvnrznr me@example.com 43 seconds ago 5b490f30
67│ Revision B
68○ tylynnzk me@example.com 43 seconds ago f26967c8
69│ Revision A
70```
71
72### How can I get `jj log` to show me what `git log` would show me?
73
74Use `jj log -r ..`. The `..` [operator] lists all visible commits in the repo, excluding the root (which is never interesting and is shared by all repos).
75
76### Can I monitor how `jj log` evolves?
77
78The simplest way to monitor how the history as shown by `jj log` evolves is by using the [watch(1)](https://man7.org/linux/man-pages/man1/watch.1.html) command (or [hwatch](https://github.com/blacknon/hwatch?tab=readme-ov-file#configuration) or [viddy](https://github.com/sachaos/viddy)).
79For example:
80
81```sh
82watch --color jj --ignore-working-copy log --color=always
83```
84
85This will continuously update the (colored) log output in the terminal.
86The `--ignore-working-copy` option avoids conflicts with manual operations during the creation of snapshots.
87Martin used watch in a [tmux](https://github.com/tmux/tmux/wiki) pane during his presentation [Jujutsu - A Git-compatible VCS](https://www.youtube.com/watch?v=LV0JzI8IcCY).
88
89Alternatively, you can use [jj-fzf](https://github.com/tim-janik/jj-fzf), where the central piece is the `jj log` view and common operations can be carried out via key bindings while the log view updates.
90
91The wiki lists additional TUIs and GUIs beyond the terminal: [GUI-and-TUI](https://github.com/jj-vcs/jj/wiki/GUI-and-TUI)
92
93### Should I co-locate my repository?
94
95Co-locating a Jujutsu repository allows you to use both Jujutsu and Git in the
96same working copy. The benefits of doing so are:
97
98- You can use Git commands when you're not sure how to do something with
99 Jujutsu, Jujutsu hasn't yet implemented a feature (e.g., bisection), or you
100 simply prefer Git in some situations.
101
102- Tooling that expects a Git repository still works (IDEs, build tooling, etc.)
103
104The [co-location documentation describes the
105drawbacks](git-compatibility.md#co-located-jujutsugit-repos) but the most
106important ones are:
107
108- Interleaving `git` and `jj` commands may create confusing bookmark conflicts
109 or divergent changes.
110
111- If the working copy commit or its parent contain any conflicted files, tools
112 expecting a Git repo may interpret the commit contents or its diff in a wrong
113 and confusing way. You should avoid doing mutating operations with Git tools
114 and ignore the confusing information such tools present for conflicted commits
115 (unless you are curious about [the details of how `jj` stores
116 conflicts](technical/conflicts.md)). See
117 [\#3979](https://github.com/jj-vcs/jj/issues/3979) for plans to improve
118 this situation.
119
120- Jujutsu commands may be a little slower in very large repositories due to
121 importing and exporting changes to Git. Most repositories are not noticeably
122 affected by this.
123
124If you primarily use Jujutsu to modify the repository, the drawbacks are
125unlikely to affect you. Try co-locating while you learn Jujutsu, then switch if
126you find a specific reason not to co-locate.
127
128### `jj` is said to record the working copy after `jj log` and every other command. Where can I see these automatic "saves"?
129
130Indeed, every `jj` command updates the current "working-copy" revision, marked
131with `@` in `jj log`. You can notice this by how the [commit ID] of the
132working copy revision changes when it's updated. Note that, unless you move to
133another revision (with `jj new` or `jj edit`, for example), the [change ID] will
134not change.
135
136If you expected to see a historical view of your working copy changes in the
137parent-child relationships between commits you can see in `jj log`, this is
138simply not what they mean. What you can see in `jj log` is that after the
139working copy commit gets amended (after any edit), the commit ID changes.
140
141You can see the actual history of working copy changes using `jj evolog`. This
142will show the history of the commits that were previously the "working-copy
143commit", since the last time the change id of the working copy commit changed.
144The obsolete changes will be marked as "hidden". They are still accessible with
145any `jj` command (`jj diff`, for example), but you will need to use the commit
146id to refer to hidden commits.
147
148You can also use `jj evolog -r` on revisions that were previously the
149working-copy revisions (or on any other revisions). Use `jj evolog -p` as an
150easy way to see the evolution of the commit's contents.
151
152### Can I prevent Jujutsu from recording my unfinished work? I'm not ready to commit it.
153
154Jujutsu automatically records new files in the current working-copy commit and
155doesn't provide a way to prevent that.
156
157However, you can easily record intermediate drafts of your work. If you think
158you might want to go back to the current state of the working-copy commit,
159simply use `jj new`. There's no need for the commit to be "finished" or even
160have a description.
161
162Then future edits will go into a new working-copy commit on top of the now
163former working-copy commit. Whenever you are happy with another set of edits,
164use `jj squash` to amend the previous commit.
165
166If you have changes you _never_ want to put in a public commit, see: [How can I
167keep my scratch files in the repository without committing
168them?](#how-can-i-keep-my-scratch-files-in-the-repository-without-committing-them)
169
170For more options see the next question.
171
172### Can I interactively create a new commit from only some of the changes in the working copy, like `git add -p && git commit` or `hg commit -i`?
173
174Since the changes are already in the working-copy commit, the equivalent to
175`git add -p && git commit`/`git commit -p`/`hg commit -i` is to split the
176working-copy commit with `jj split -i` (or the practically identical
177`jj commit -i`).
178
179For the equivalent of `git commit --amend -p`/`hg amend -i`, use `jj squash -i`.
180
181### Is there something like `git rebase --interactive` or `hg histedit`?
182
183Not yet, you can check [this issue] for updates.
184
185To reorder commits, it is for now recommended to rebase commits individually,
186which may require multiple invocations of `jj rebase -r` or `jj rebase -s`.
187
188To squash or split commits, use `jj squash` and `jj split`.
189
190### How can I keep my scratch files in the repository without committing them?
191
192You can set `snapshot.auto-track` to only start tracking new files matching the
193configured pattern (e.g. `"none()"`). Changes to already tracked files will
194still be snapshotted by every command.
195
196You can keep your notes and other scratch files in the repository, if you add
197a wildcard pattern to either the repo's `gitignore` or your global `gitignore`.
198Something like `*.scratch` or `*.scratchpad` should do, after that rename the
199files you want to keep around to match the pattern.
200
201If you keep your scratch files in their own directory with no tracked files, you
202can create a `.gitignore` file in that directory containing only `*`. This will
203ignore everything in the directory including the `.gitignore` file itself.
204
205If `$EDITOR` integration is important, something like `scratchpad.*` may be more
206helpful, as you can keep the filename extension intact (it
207matches `scratchpad.md`, `scratchpad.rs` and more). Another option is to add a
208directory to the global `.gitignore` which then stores all your temporary files
209and notes. For example, you could add `scratch/` to `~/.git/ignore` and then
210store arbitrary files in `<your-git-repo>/scratch/`.
211
212You can find more details on `gitignore` files [here][gitignore].
213
214### How can I avoid committing my local-only changes to tracked files?
215
216Suppose your repository tracks a file like `secret_config.json`, and you make
217some changes to that file to work locally. Since Jujutsu automatically commits
218the working copy, there's no way to prevent Jujutsu from committing changes to
219the file. But, you never want to push those changes to the remote repository.
220
221One solution is to keep these changes in a separate commit branched from the
222trunk. To use those changes in your working copy, _merge_ the private commit
223into your branch.
224
225Suppose you have a commit "Add new feature":
226
227```shell
228$ jj log
229@ xxxxxxxx me@example.com 2024-08-21 11:13:21 ef612875
230│ Add new feature
231◉ yyyyyyyy me@example.com 2024-08-21 11:13:09 main b624cf12
232│ Existing work
233~
234```
235
236First, create a new commit branched from main and add your private changes:
237
238```shell
239$ jj new main -m "private: my credentials"
240Working copy now at: wwwwwwww 861de9eb (empty) private: my credentials
241Parent commit : yyyyyyyy b624cf12 main | Existing work
242Added 0 files, modified 1 files, removed 0 files
243
244$ echo '{ "password": "p@ssw0rd1" }' > secret_config.json
245```
246
247Now create a merge commit with the branch you're working on and the private
248commit:
249
250```shell
251$ jj new xxxxxxxx wwwwwwww
252Working copy now at: vvvvvvvv ac4d9fbe (empty) (no description set)
253Parent commit : xxxxxxxx ef612875 Add new feature
254Parent commit : wwwwwwww 2106921e private: my credentials
255Added 0 files, modified 1 files, removed 0 files
256
257$ jj log
258@ vvvvvvvv me@example.com 2024-08-22 08:57:40 ac4d9fbe
259├─╮ (empty) (no description set)
260│ ◉ wwwwwwww me@example.com 2024-08-22 08:57:40 2106921e
261│ │ private: my credentials
262◉ │ xxxxxxxx me@example.com 2024-08-21 11:13:21 ef612875
263├─╯ Add new feature
264◉ yyyyyyyy me@example.com 2024-08-21 11:13:09 main b624cf12
265│ Existing work
266~
267```
268
269Now you're ready to work:
270
271- Your work in progress _xxxxxxxx_ is the first parent of the merge commit.
272- The private commit _wwwwwwww_ is the second parent of the merge commit.
273- The working copy (_vvvvvvvv_) contains changes from both.
274
275As you work, squash your changes using `jj squash --into xxxxxxxx`.
276
277If you need a new empty commit on top of `xxxxxxxx` you can use the
278`--insert-after` and `--insert-before` options (`-A` and `-B` for short):
279
280```shell
281# Insert a new commit after xxxxxxxx
282$ jj new --no-edit -A xxxxxxxx -m "Another feature"
283Working copy now at: uuuuuuuu 1c3cff09 (empty) Another feature
284Parent commit : xxxxxxxx ef612875 Add new feature
285
286# Insert a new commit between yyyyyyyy and vvvvvvvv
287$ jj new --no-edit -A yyyyyyyy -B vvvvvvvv -m "Yet another feature"
288Working copy now at: tttttttt 938ab831 (empty) Yet another feature
289Parent commit : yyyyyyyy b624cf12 Existing work
290```
291
292To avoid pushing change _wwwwwwww_ by mistake, use the configuration
293[git.private-commits](config.md#set-of-private-commits):
294
295```shell
296jj config set --user git.private-commits 'description(glob:"private:*")'
297```
298
299### I accidentally changed files in the wrong commit, how do I move the recent changes into another commit?
300
301Use `jj evolog -p` to see how your working-copy commit has evolved. Find the
302commit you want to restore the contents to. Let's say the current commit (with
303the changes intended for a new commit) are in commit X and the state you wanted
304is in commit Y. Note the commit id (normally in blue at the end of the line in
305the log output) of each of them. Now use `jj new` to create a new working-copy
306commit, then run `jj restore --from Y --into @-` to restore the parent commit
307to the old state, and `jj restore --from X` to restore the new working-copy
308commit to the new state.
309
310### How do I resume working on an existing change?
311
312There are two ways to resume working on an earlier change: `jj new` then `jj squash`,
313and `jj edit`. The first is generally recommended, but `jj edit` can be useful. When
314you use `jj edit`, the revision is directly amended with your new changes, making it
315difficult to tell what exactly you change. You should avoid using `jj edit` when the
316revision has a conflict, as you may accidentally break the plain-text annotations on
317your state without realising.
318
319To start, use `jj new <rev>` to create a change based on that earlier revision. Make
320your edits, then use `jj squash` to update the earlier revision with those edits.
321For when you would use git stashing, use `jj edit <rev>` for expected behaviour.
322Other workflows may prefer `jj edit` as well.
323
324### Why are most merge commits marked as "(empty)"?
325
326Jujutsu, like Git, is a snapshot-based VCS. That means that each commit
327logically records the state of all current files in the repo. The changes in a
328commit are not recorded but are instead calculated when needed by comparing the
329commit's state to the parent commit's state. Jujutsu defines the changes in a
330commit to be relative to the auto-merged parents (if there's only one parent,
331then that merge is trivial - it's the parent commit's state). As a result, a
332merge commit that was a clean merge (no conflict resolution, no additional
333changes) is considered empty. Conversely, if the merge commit contains conflict
334resolutions or additional changes, then it will be considered non-empty.
335
336This definition of the changes in a commit is used throughout Jujutsu. It's
337used by `jj diff -r` and `jj log -p` to show the changes in a commit. It's used
338by `jj rebase` to rebase the changes in a commit. It's used in `jj log` to
339indicate which commits are empty. It's used in the `files()` revset function
340(and by `jj log <path>`) to find commits that modify a certain path. And so on.
341
342### How do I deal with divergent changes ('??' after the [change ID])?
343
344A [divergent change][glossary_divergent_change] represents a change that has two
345or more visible commits associated with it. To refer to such commits, you must
346use their [commit ID]. Most commonly, the way to resolve
347this is to abandon the unneeded commits (using `jj abandon <commit ID>`). If you
348would like to keep both commits with this change ID, you can `jj duplicate` one
349of them before abandoning it.
350
351### How do I deal with conflicted bookmarks ('??' after bookmark name)?
352
353A [conflicted bookmark][bookmarks_conflicts] is a bookmark that refers to multiple
354different commits because jj couldn't fully resolve its desired position.
355Resolving conflicted bookmarks is usually done by setting the bookmark to the
356correct commit using `jj bookmark move <name> --to <commit ID>`.
357
358Usually, the different commits associated with the conflicted bookmark should all
359appear in the log, but if they don't you can use `jj bookmark list`to show all the
360commits associated with it.
361
362### How do I integrate Jujutsu with Gerrit?
363
364At the moment you'll need a script, which adds the required fields for Gerrit
365like the `Change-Id` footer. Then `jj` can invoke it via an `$EDITOR` override
366in an aliased command. Here's an [example][gerrit-integration] from an
367contributor (look for the `jj signoff` alias).
368
369After you have attached the `Change-Id:` footer to the commit series, you'll
370have to manually invoke `git push` of `HEAD` on the underlying git repository
371into the remote Gerrit bookmark `refs/for/$BRANCH`, where `$BRANCH` is the base
372bookmark you want your changes to go to (e.g., `git push origin
373HEAD:refs/for/main`). Using a [co-located][co-located] repo
374will make the underlying git repo directly accessible from the working
375directory.
376
377We hope to integrate with Gerrit natively in the future.
378
379### I want to write a tool which integrates with Jujutsu. Should I use the library or parse the CLI?
380
381There are some trade-offs and there is no definitive answer yet.
382
383* Using `jj-lib` avoids parsing command output and makes error handling easier.
384* `jj-lib` is not a stable API, so you may have to make changes to your tool
385when the API changes.
386* The CLI is not stable either, so you may need to make your tool detect the
387different versions and call the right command.
388* Using the CLI means that your tool will work with custom-built `jj` binaries,
389like the one at Google (if you're using the library, you will not be able to
390detect custom backends and more).
391
392
393[bookmarks_conflicts]: bookmarks.md#conflicts
394
395[change ID]: glossary.md#change-id
396[co-located]: glossary.md#co-located-repos
397[commit ID]: glossary.md#commit-id
398[config]: config.md
399
400[gerrit-integration]: https://gist.github.com/thoughtpolice/8f2fd36ae17cd11b8e7bd93a70e31ad6
401[gitignore]: https://git-scm.com/docs/gitignore
402
403[glossary_divergent_change]: glossary.md#divergent-change
404
405[operator]: revsets.md#operators
406
407[revsets]: revsets.md
408
409[templates]: templates.md
410
411[this issue]: https://github.com/jj-vcs/jj/issues/1531