Hacker News new | past | comments | ask | show | jobs | submit login

jj is truly its own VCS, so to deeply understand it, it's more than short. But it does map to git, and so you can sorta explain it in git terms. It's really kind of like "what if you tried to build hg on top of git?"

jj is kind of hard to really explain because a bunch of the design decisions have subtle but important impacts on other decisions, so your first impression of a feature may be slightly wrong because you don't get the implications yet.

jj is sort of the same as git: you have a DAG of snapshots of your project. The differences are in how you interact with those things. To try and put it in git terms:

1. Commits are mutable, not immutable (but we'll talk about is more later)

2. You're always working in the context of some commit

3. When you modify a file, it becomes part of that commit (we'll talk about the index in a minute)

4. You don't need to care about branches at all, the "detached head" state is the nrom.

5. commits are immutable in the "immutable data structures" sense, in that whenever you modify them, it's almost like you're adding a commit to them. this is why jj calls its "commits" "changes", change IDs stay stable as you edit them, and they produce new git commits for every edit.

6. Because of how this all fits together, you don't need an explicit index; if you want one, you can just `jj new` twice to get two changes on top of each other, and then edit your files. When you have what you want, `jj squash` will move the diff into the parent commit, and now it's "part of that feature" or whatever. If you want `git add -p`, that's `jj squash -i`.

That is kind of it on some level, but in reality, it's kind of hard to convey how a few, smaller, more orthogonal primitives let you do everything you can do in git, but easier. (I tried to actively think of cases last night and only came up with two or three that were easier in git than jj, and jj will have fixes for most of those soonish.)

stashing is another great example of a feature of git that's just a workflow pattern in jj.

There's just... it's a lot. It's hard to know what the best thing really is. Other than `jj undo` :)

(I've got this on the brain since I am literally working on my tutorial right now)




This is a pretty good summary of my experience and a small set of steps to understand to see why it's different – the idea that features of git are workflows/patterns in JJ is a nice one.

> it's kind of hard to convey how a few, smaller, more orthogonal primitives let you do everything you can do in git, but easier

Some of this didn't really click for me until I experienced it (and I'm still very much learning). The one that sticks out is how you're always in a commit. Where in git you work in "modes" – editing in the index, rebasing, committing, etc. In jj you're always "stable" and can do anything from that point.

The way this is sold is things like "mutable commits" or "first class conflicts", but for me the real power was just realising that I can always move to another commit/change without having to pre-plan how to do that, always being able to edit my commit message right now without having to finish up something else first. Now going back to git feels like the tool is slowing me down and not keeping up with the pace and style I want to work in. I was surprised that this was the thing I most enjoy, because it's a little hard to motivate.


I remember at an old job where the feedback loop was quite slow, so you always ended up with multiple branches or PRs in play at a time. I ended up using git worktree to basically have each branch as its own separate workspace (rip my hard drive) because the process of stashing and switching, pulling, and untangling wip commits got old fast.

I still juggle a few plates now (for better or worse) and especially with VisualJJ that experience is much nicer. I can just switch between bookmarks and do what I need to, and `absorb` makes that super nice in terms of addressing PR feedback.


jj also has workspaces, which are the same as a git worktree, if you want that workflow.


My biggest concern with moving to `jj` is how it handles new files. I don't always want files I create in my repository to end up on a remote and I have been under the impression `jj` assumes everything it hasn't been told to ignore is part of the repository.


You can set `snapshot.auto-track` config to "none()" (which is a fileset, so you could actually have something like src/* there).

That way, only files that were already present in the wc commit are amended, and new files are kept untracked until you explicitly `jj file track` them. And jj status finally fully shows them in the main branch too (it's broken in the v0.26 release sadly)


I guess it depends on your workflow. If you stage each file carefully in git, it's effectively opt-in as you suggest. If you `git add .` though, as many people do out of habit, then it's not going to help much. The same is true really for jj, if you don't edit your commits then yeah, it'll be included by default, but if you craft your commits then you'll spot it.

Also jj doesn't push until you push your changes when backing on to git. This is pluggable though, the backend I work with is not git, and does happen to upload all commits off my machine immediately (although still effectively in a private fork).




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: