4 ms·
jj makes it super easy to "fix up" your commit tree to what you want it to look like. "Oh I forgot to make a change in this commit and I'm 4 commits in..." ->
by rtpg 2y ago
jj makes it super easy to "fix up" your commit tree to what you want it to look like.
"Oh I forgot to make a change in this commit and I'm 4 commits in..." -> "I can go change that commit and everything else magically rebases on it".
It treats changes as this conceptual thing, and the whole immutable commit thing as a backing store but not how _you_ are looking at a problem. Or at least not how I look at it.
I added a test, put in a new feature, updated the readme. Those changes are not about all the metadata around the change, they're the change. Of course you still have the immutable commit graph when you want to _really specifically_ talk about a certain commit, but for most intents and purposes it's the changes that matter.
jj gives you similar workflows to git in the easy case. In the hard cases, jj makes it easier to do the work than git. So it's nicer!
- gpm 2y ago> jj makes it super easy to "fix up" your commit tree to what you want it to look like. I hit this today in a fun way. I was working along as one does, and needed to write a parser for a simple s-expression based language. So I did that fairly quickly, added a few tests which appeared to pass, and kept on working. A few commits later I reached a point where I needed to manually test my code. And promptly hit a stack overflow in the parser. A few minutes of debugging I understood the issue (I'd used the wrong function and failed to require brackets around a nested s-expression) - except I could have sworn my tests should catch it. So I ran my tests manually, and lo and behold they did catch it. Turns out that there was a bug in the tool I was using to run my tests [1] that was masking the test failure. I had completely broken my tests for the last few commits (all of them since I wrote the parser). Anyways, I went and fixed the tool, but by now on my main repo I had fixes for the last few commits all mixed together with a fairly large WIP commit. Thankfully instead of making this the frustrating game of rebasing with git, jj makes it just take a few jj split (select changes you want to split off, sort like git add -p); jj squash (merging changes into the existing commit) commands. Could I have fixed up the previous commits with git? Of course. But it would have made a frustrating hour even more frustrating. [1] https://github.com/Canop/bacon/issues/326 https://github.com/Canop/bacon/issues/326
- Izkata 2y agoIf I'm understanding right, that would also be 2 commands in git and you even mentioned one of them: "git add -p" to create a new commit with the fix, separating it from the rest of the WIP, then "git rebase -i <old commit>" and use the file it opens to tell git which commits to combine. Save and quit, and git does the rest for you. There's other functionality in there too, including just straight editing old commits without having to deal with the child commits yourself.
- gpm 2y agoYou're... not wrong. You're also missing the point, which is on me. It's `git rebase -i`, and edit a file to tell it what to do, and work in a limited rebase-state of git. Versus `jj squash --into <commit>` and if doesn't merge nicely, or it causes conflicts, you stay in the normal state with the normal tools. It's a difference in quality of life, of reducing friction, not the power of the tools. Even the `git add -p`s interface is also just less nice than `jj split`'s interface. Where `git add -p` feeds you changes one at a time and makes you select them, `jj split` gives you a interactive selection gui that lets you scroll through changes, collapse and uncollapse files, select and unselect whole files, single diff sections, or even indivudal lines. It's nicer. > including just straight editing old commits without having to deal with the child commits yourself. This is sort of an example. Git needs a special mode, invoked via this file-based interface in `rebase -i` (though I imagine there's a more direct command that no one knows as well). While in that mode you can't do things like just switch to another branch and work on something else. It's "strange". In jj this is just `jj edit <commit>`. It's within the set of operations that are "normal" in jj's model. You can do everything you can normally do. If something like a merge conflict happens git says "and how you need to deal with this right away". jj says "these commits have merge conflicts in them, fix them if/when you like". Every small piece of my interaction feels slightly better than the same small piece of the interaction with git, and it's remarkable because it really does feel like it's every piece of the interaction with jj that is better. I don't feel like I'm being very eloquent - but hopefully the difference I'm trying to describe is coming across at least to some degree.