just playing with tangled
at docs-prerelease 411 lines 19 kB view raw view rendered
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