This content originally appeared on DEV Community and was authored by Altariarite
jj is a shiny new version control system. I’ve been using it for a week now and it revolutionised my workflow with GitHub. It’s simpler and more intuitive than git, but the official tutorial and the default UI can be a little daunting.
This guide will start with a simpler jj
interface and walk you through common development workflows. We start from making a single change and go all the way to managing a stack of tiny pull requests.
I hope I can show you why jj
feels amazing by the end! We’ll use a simple Python project as our example.
Setup
First, let’s customise jj
. Then we will set up our project and initialise it with jj
.
0. Customise jj
The default jj log
shows a lot of stuff. That can be quite confusing for someone new to jj
. When starting out I preferred to use a simpler interface. You can do that by writing to ~/.config/jj/config.toml
"$schema" = "https://jj-vcs.github.io/jj/latest/config-schema.json"
[user]
email = "someone@example.com"
name = "Some One"
[ui]
default-command = ["log", "-T", "builtin_log_oneline"]
# replace with your editor
editor = "nvim"
[template-aliases]
# Username part of the email address
'format_short_signature(signature)' = 'signature.email().local()'
# Relative timestamp rendered as "x days/hours/seconds ago"
'format_timestamp(timestamp)' = 'timestamp.ago()'
# Hide git commit id
'format_short_commit_id(id)' = '""'
[templates]
log = "builtin_log_comfortable"
1. Create your project:
mkdir jj-hello-world
cd jj-hello-world
2. Initialise jj
and git:
jj
works on top of a git repository, which allows it to integrate with platforms like GitHub.
jj git init
1. Your First Change & PR
Now our journey starts! We start by running jj log
.
Wow, what are all those things? A minute ago we just had an empty folder!
Turns out, every new jj
repository starts with two “commits”:
The line starting with
◆
is the root commit. It’s the special, empty starting point of your project’s entire history, identified by all Zs (zzzzzzzz
). Think of it as the foundation upon which all your future work will be built.The line starting with
@
is your current working-copy commit. The@
symbol means this is your active workspace where any new file changes will be automatically tracked. In a brand new repository, this commit is also(empty)
and has no description yet, ready for you to start coding.
Let’s make a simple change.
1. Write a change:
Modify the main.py
file and save.
print("hello world!")
jj
automatically captures this change in your working copy. If we run jj log
again, you will see that the (empty)
tag is gone. jj
knows that we have changed something.
We can see the change with jj diff
2. Commit your change:
jj commit -m "Add hello world"
Your jj log
will now show three commits: the root commit, the feature you committed just now, and a new empty working-copy commit you’re now on.
Note:
Your feature commit has the idxvuxvpsx
. That’s exactly the same as the id of the previous working copy. The new working copy has a new id that starts withm
3. Sync and first push:
Let’s push your feature. Create a new, empty repository on GitHub. Then, add it as a remote.
# Replace <your-github-url> with your repository's URL
git remote add origin <your-github-url>
We want to give our commit a “bookmark”. Since GitHub is organised around named branches, this bookmark tells jj
which of your local commits should become a specific branch on the remote. We want to bookmark our feature commit as main.
jj bookmark create main -r x
Note:
-r
stands for “revision”, which is a synonym for “commit”. Andx
is the shortest unique id for our local commit.
Push to remote.
jj git push --allow-new
Now your feature is on GitHub! \o/
Next up, we will look at creating and fixing PRs (pull requests), which happens all the time when you collaborate with someone on GitHub, or sometimes even when you work alone. Stay tuned!
This content originally appeared on DEV Community and was authored by Altariarite