JJ
Updated: 23 December 2025
jj is a Git-compatible version control system. Another useful reference is Steve’s JJ tutorial or JJ for Everyone
Installation and Setup
jj supports Nushell, so naturally the configuration and installation is in (the jj installation docs)[https://jj-vcs.github.io/jj/v0.23.0/install-and-setup/#nushell] - this will give some really nice autocomplete for Nushell which is great
Initializing
To init jj in a repo that’s currently using git, use:
1jj git init --colocateStatus
All changes in jj are located in a working copy, these changes can be seen with:
1> jj status2
3Working copy changes:4A jj.txt5Working copy (@) : kwvkkoxy 53889ed8 (no description set)6Parent commit (@-): nlmkywks 2c0668f0 main | Add content for special notesAdditionally, the change history can also be seen with jj log and looks something like this:
1> jj log2
3@ kwvkkoxy nabeel@email.com 2025-10-27 13:04:27 53889ed84│ (no description set)5○ nlmkywks nabeel@email.com 2025-10-27 13:02:08 main git_head() 2c0668f06│ Add content for special notes7○ mvvunzxz nabeel@email.com 2025-10-27 13:02:08 03f621ee8│ add initial notes9○ mwmtqrmv nabeel@email.com 2025-10-27 13:02:08 754fba4810│ (empty) initial commit11│ ○ yotxkrrt nabeel@email.com 2025-10-27 13:03:26 example-feature-2 8cf8df5c12│ │ file 213│ ○ xwylmzso nabeel@email.com 2025-10-27 13:03:26 b626e37814│ │ Add content for special notes15│ ○ qzwwoopw nabeel@email.com 2025-10-27 13:03:26 30bc460f16│ │ add initial notes17│ ○ lvzvxwuo nabeel@email.com 2025-10-27 13:03:26 e265e2f218├─╯ (empty) initial commit19│ ○ nzyvlzlt nabeel@email.com 2025-10-27 13:03:16 example-feature d6e7e08720│ │ some content21│ ○ ruvknzzw nabeel@email.com 2025-10-27 13:03:16 b959bbdb22│ │ Add content for special notes23│ ○ lylxkkts nabeel@email.com 2025-10-27 13:03:16 da0f7c9824│ │ add initial notes25│ ○ nxlklokt nabeel@email.com 2025-10-27 13:03:16 01643ac626├─╯ (empty) initial commit27◆ zzzzzzzz root() 00000000Diff
You can also view the diff for changes relative to your current HEAD by using:
1> jj diffDiffs can also be done relative to other refs, for example relative to main like so:
1> jj diff --from main@originThere are, of course, other flags that are supported to enable additional functionality
Descriptions
We can add a decription to our working copy with jj describe
1> jj describe -m "Some notes on JJ"2> jj status3
4Working copy changes:5A jj.txt6Working copy (@) : kwvkkoxy 6dcc5582 Some notes on JJ7Parent commit (@-): nlmkywks 2c0668f0 main | Add content for special notesThe Working Copy
jj changes are done in a working copy. We can also have multiple simultaneous working copies in JJ. JJ allow us to create a working copy with a description like so:
1> jj new -m "Working copy description"A working copy can also be created after or before a specific commit using -a or -b respectively
The working copy can be moved around using jj edit and referencing a commit we’d like to move this on top of:
1> jj editRebasing and Moving the Working Copy
Moving the Working Copy
Rebasing can be done using jj rebase which allows you to move commits around. The simplest usecase for this is to move your working copy to a different bookmark, for example - moving the working copy to main can be done like so:
1> jj rebase -r @ -d mainThis moves
@(the working copy) to-d(destination) themainbookmark, effectively letting you “checkout” the main branch
Generally using jj rebase, jj new, or jj edit are how you would “checkout” a bookmark, depending on the current state of your working copy and your intended change
Moving a Branch
You can also rebase a branch using:
1jj rebase -b my/feature/branch -d mainA “branch” in the context of
jjrefers to a set of revisions that are not also part of the destination
Working from Another Revision
jj lets us create a working copy on top of another revision/bookmark, this can be done using jj new. Often we’d like to start working relative to some main bookmark, this looks like so:
1> jj new mainThis now moves our working copy to be on top of the main bookmark. Creating new bookmarks can then be done from this point
Commits
With
jjyou probably want to use bookmarks instead of commits
Commits can be created based on the current working copy and can be done with:
1> jj commitThis will simply create a commit with all the files in the current working copy. If you’d like to partially include files you can use jj commit -i which allows for an interactive commit
Bookmarks
Creating Bookmarks
jj uses the idea of bookmarks instead of branches. A bookmark is like a commit on a branch.
A bookmark can be created with:
1> jj bookmark create <bookmark/branch name>Tracking Bookmarks
jj can track remote branches by using:
1> jj bookmark track <bookmark-name>@<remote-name>Updating Bookmarks
Take a look at Steve’s tutorial on this for more details
Updating a bookmark is jj’s way of adding a commit to a branch. This is kinda weird but basically updates a commit to be the next branch
When working relative to a bookmark, you can make changes. After comitting those changes, you can update the current commit to be the new bookmark for that change like so:
1> jj bookmark set <bookmark-name>We can set the bookmark to a specific revision using the -r flag. We can set the current working copy with @ or the previous commit with @-
1> jj bookmark set <bookmark-name> -r @-Pushing Changes
jj allows for multiple different backends. Pushing to a git backend is done using:
1> jj git pushWhat this does under the hood is moves the bookmarks to around to maintain and push to git branches appropraiately
This command also allows you to specify which bookmarks or commits you’d like to push using -b or -c respectively
Restore a file
Restoring a file will reset the changes made to that file and can be done with:
1> jj restore path/to/file.txtConflict Resolution
jj has conflict resolution tooling builtin which can be accessed using jj resolve in the case of conflicts. Changes can be resolved using the resolution tool like so:
1> jj resolve path/to/file.txtWhich will open a similar tool to the once used for interactive commits
Basic Workflow
The bookmark concept can be a little tricky when working with git, basically here’s a worflow that I find seems to work:
- Just start doing some work
- Branching is done with either:
- Use
jj bookmark create <bookmark>to label your working area as a new branch (this is from your current location in the tree) - Use
jj edit <bookmark/commit>to select a commit to start working from, this is like branching from somewhere else
- Use
- Use
jj describeto set a description for your working area - this will become the commit message - Use
jj committo make a commit - You can then move the bookmark to it’s new location with
jj bookmark set <bookmark> -r @-(the@-refers to the parent commit/revision) - Use
jj git push -b <bookmark>to push the bookmark - Go back to 1.
Getting Commit Details
The jj show command can be used to get details about a commit or revision. It’s also possible to refer to the working area using @, which means that information about the current working area can be fetched with:
1> jj show @Additionally, the -T param can be used with some commands, including the jj show command, to structure the output