I started dabbling with jj (git alternative) recently by going through Steve Klabnik’s jujutsu tutorial ↗. This is a great place to start (along with many other jj resources here ↗).
Then today as I’m wrapping up a migration script for my Kit.com account ↗, I decide it is worth putting up on GitHub. I then further decide that I should try my hand at using jj to go from zero (no repo) to pushing it all up to GitHub.
I’m not that far through Steve’s tutorial, so there are a lot of gaps in my knowledge. The whole process was not as straightforward as I thought it would be, so I figured it would help me and others to document…
I started dabbling with jj (git alternative) recently by going through Steve Klabnik’s jujutsu tutorial ↗. This is a great place to start (along with many other jj resources here ↗).
Then today as I’m wrapping up a migration script for my Kit.com account ↗, I decide it is worth putting up on GitHub. I then further decide that I should try my hand at using jj to go from zero (no repo) to pushing it all up to GitHub.
I’m not that far through Steve’s tutorial, so there are a lot of gaps in my knowledge. The whole process was not as straightforward as I thought it would be, so I figured it would help me and others to document the steps and missteps that I took to get the job done.
Since I ultimately want a git-backed repo that I can push up to GitHub, I need to start with:
This creates both .jj and .git directories.
quick note: I use the word “commit” in a lot of places throughout this post and most of those should probably be “change” in jj-parlance. Hard habit to break.
Now I’ll take a look at my starting status where I can see I have a couple files in the working copy on top of the root empty commit.
I could start with a jj describe and jj new to finalize a commit with message. However I want to take a more granular start by separating these files into a couple different commits.
I’m already at the edge of my jj knowledge here. My git brain wants to stage only the .gitignore file, but my understanding of jj is that all the files in the working copy are essentially staged.
To split them out, I need the jj split command. This splits out a separate commit from the working copy with the specified files.
This opens my editor (nvim), prompting me to describe the commit being split out from the working copy. I type a message, save, and check the status.
Great. I still have an undescribed working copy with the three remaining files on top of the newly described commit that includes my .gitignore file.
I now want to split out another commit from the working copy that includes both migrate.rb and kit_client.rb.
I’ll check the status again to see that one file remains.
To commit the remaining file, I’ll do a jj describe and then a jj new.
I can now look at all of my progress so far with the jj log command.
Now I’d like to put all of this up on GitHub. I create my new repo on GitHub ↗ and grab the URL of the origin so that I can tell jj (which I imagine is primarily telling git under the hood) what the remote is.
I had to look up that command which led me to figuring out how to list the remotes that I have configured.
Now I figured I could go ahead and push directly to GitHub at this point. But it doesn’t work and jj does its best to tell me why.
I remember reading that jj bookmarks roughly correspond to git branches ↗, so this error made sense. I guess I need to create a main bookmark.
Looking at the jj log, I can see main appear on that top empty working copy commit. This struck me as a bit odd that main is pointing to an empty, no-description commit, but I didn’t think too much of it. I quickly found that this wasn’t quite going to work.
Ok, so my main bookmark needs to be pointed at the previous commit, not this new, empty working copy. A bit more digging and I find that I can set a bookmark to point at a reference relative to the “head” (@) – in this case to one commit back with -r @-.
jj continues to be helpful letting me know that I need the --allow-backwards flag for this to work.
Checking jj log I can see the main bookmark showing up in the correct place.
Let’s try that push again, specifying the --bookmark as well:
And there I have it. I went from no repo to having a series of commits with specific files in each commit pushed up to GitHub. Along the way I learned about jj split, jj git remote, jj bookmark, moving a bookmark, and jj git push along with various flags.
I’m still selling myself on jj. It seems like it is going to require thinking a bit differently about things than I’ve learned with git. Many developers that I trust continue to advocate for it, so I trust that it will be worth effort.