| ▲ | coldtea 8 hours ago | |||||||||||||
All of these features sound like the recipe for a confusing nightmare! "You can switch branches halfway through resolving conflicts and then come back later and pick up where you left off. You can also just ignore the conflicts and continue editing files on the conflicted branch and then resolve the conflicts later." "Similar to stashes, but each "stash" is just a normal branch that can have multiple commits. If I want to test something but I have current changes, I just `jj new`. And if I want to go back, I just make a new commit off of the previous one. And all these commits stick around, so I can go back to something I tried before." | ||||||||||||||
| ▲ | nickisnoble 8 hours ago | parent | next [-] | |||||||||||||
I thought the same until I started using it. Turns out, git sorta trains you to be very, very afraid of breaking something. jj answers this in a few ways: 1. everything is easily reversible, across multiple axes. 2. yes, everything is basically a stash, and it's a live stash — as in, I don't have to think about it because if it's in my editor, it's already safely stored as the current change. I can switch to a different one, create a new one, have an agent work on another one, etc, all without really caring about "what if I forgot to commit or stash something". Sounds like insanity from a git POV but it really is freeing. 3. Because of 2, you can just leave conflicts alone and go work on something else (because they are, like you said, essentially stashed). It's fine and actually very convenient. The thing the article doesn't mention, that makes this all safe, is that trunk / "main" is strictly immutable. All this flexibility is *just* for unmerged WIP. (There are escape hatches though, naturally!) | ||||||||||||||
| ▲ | steveklabnik 8 hours ago | parent | prev | next [-] | |||||||||||||
The "you don't need to worry about resolving conflicts" thing is confusing when you hear it with words, so let me show you what it looks like in practice. Let's say I have two branches off of trunk. They each have one commit. That looks like this (it looks so much nicer with color, I'm going to cut some information out of the default log so that it's easier to read without the color):
So both `foo` and `bar` are on top of trunk, and I'm also working on a third branch on top of trunk (@). Those vvxv and such are the change ids, and you can also see the named trunk there as well.Now, I fetch from my remote, and want to rebase my work on top of them: a `jj git fetch`, and then let's rebase `foo` first: that's `jj rebase uu -o trunk` (you only need uu instead of uuowqquz because it's a non-ambiguous prefix, just like git). Uh oh! a conflict!
Note that jj did not put us into a "hey there's a conflict, you need to resolve it" state. It just did what you asked: it rebased it, there's a conflict, it lets you know.So why is this better? Well, for a few reasons, but I think the simplest is that we now have choice: with git, I would be forced to deal with this conflict right now. But maybe I don't want to deal with this conflict right now: I'm trying to update my branches in general. Is this conflict going to be something easy to resolve? In this case, it's one commit. But what if each of these branches had ten commits, with five of them conflicted and five not? It might be a lot of work to fix this conflict. So the cool thing is: we don't actually have to. We could continue our "let's rebase all the branches" task and rebase bar as well. Maybe it doesn't have a conflict, and we'd rather go work on bar before we come back and deal with foo. Heck, sometimes, I've had a conflicted branch, and then a newer version of trunk makes the conflict go away! I only have to choose to address the conflict at the moment I want to return to work on foo. There's broader implications here, but in practice, it's just that it's simply nicer to have choice. | ||||||||||||||
| ▲ | ersatz-matty 8 hours ago | parent | prev | next [-] | |||||||||||||
In practice, it isn't. What you're identifying as potentially nightmarish - and no doubt quite tedious in git - are things that JJ enables you to do with a small subset of commands that work exactly how you expect them to work _in every workflow context_ in which they are needed. Thinking specifically about conflicts: being able to defer conflicts until you're ready to deal with them is actually great. I might not be done with what I am actually working on and might want to finish that first. being forced into a possibly complicated conflict resolution when I'm in the middle of something is what I'd actually consider nightmarish. When you want to solve the conflict: `jj new <rev>`, solve the conflict, then `jj squash`, your conflict resolution is automatically propagated to the chain of child commits from the conflict. | ||||||||||||||
| ▲ | BeetleB 3 hours ago | parent | prev | next [-] | |||||||||||||
Remember when you used SVN or whatever before git, and you loved git because of how easy it is to make branches? With branches, jj is to git what git was to SVN. It's an order of magnitude less friction to do branching in jj than git. Not long ago, I pulled from main and rebased my branch onto it - merge conflicts. But I wanted to work on some other feature at the moment. Why should I have to fix this merge conflict to work on a feature on a totally different branch? With jj, I don't. I just switch to the other branch (that has no conflict), and code my new feature. Whenever I need to work on the conflicted branch, I'll go there and fix the conflict. Once I started using jj, I realized how silly it was for git to have separate concepts for stash and index. And it's annoying that stash/index is not version controlled in git. Or is it? I have no idea. In jj, a stash is simply yet another unnamed branch. Do whatever you want there. Add more commits. Then apply it to any branch(es) that you would like to. Or not. Why does git need a separate concept of a stash? And wouldn't you like a version controlled stash in git? Have you ever made a ton of changes, done a "git add", accidentally deleted some of the changes in one file, done a "git add", and thought "Oh crap!" I suppose that information can be recovered from the reflog. But wouldn't you wish "git add" was version controlled in the same way everything else is? That's the appeal of jj. You get a better stash. You get a better index. And all with fewer concepts. You just need to understand what a branch (or graph) is, and you get all of it. Why give it a name like "stash" or "index"? Why does git insist on giving branches names? Once you get used to unnamed branches, the git way just doesn't make sense. In jj you'll still give names wherever you need to. | ||||||||||||||
| ▲ | ncphillips 8 hours ago | parent | prev [-] | |||||||||||||
Yeah I legit do not understand the appeal. I’m willing to be wrong but it’s not clicking with me at all | ||||||||||||||
| ||||||||||||||