8 ms·
For a lot of people, making small and tightly-focused branches that are easy to review and merge is very important. This is where jj excels. Especially if you
by stouset 1y ago
For a lot of people, making small and tightly-focused branches that are easy to review and merge is very important.
This is where jj excels. Especially if you find yourself often doing large chunks of work between convenient checkpoints, but you still want to create commits as if this work was all done in tiny and discrete chunks. It's also very helpful if you're the kind of developer who makes lots of unrelated changes in a single coding session, and wants all those changes to be in parallel branches that can be reviewed and merged independently. I greatly prefer working with (and being) the kind of developer that puts out a large number of very tiny and easy to review PRs, eve. jj makes doing that a breeze.
There are lots of people for whom these things aren't important. I will be slightly judgmental and say I don't really enjoy working with them. They tend to write very large PRs that are difficult and time-consuming to review. And it's a frequent source of frustration for everyone when 95% of the work is uncontroversial but a merge is being held up because of legitimate concerns with an unrelated 5%. This is even worse when there's later work that builds upon it that can't happen until a merge (or that needs to be constantly rebased as the PR is improved).
This is not to say if you do this you’re a bad developer. There are plenty of great developers who don’t care about these things and still do great work. This is also not to say you can’t follow my preferred approach with git. I did it with git for a decade and a half.
- beng-nl 1y agoWow, that does sound like a big improvement. My git commits are, when not forced to be otherwise, very sloppy, even though I’d prefer them to be neatly self contained. But as you imply, there is friction to making these in git, while making lots of unrelated changes in a single coding session. As an example of another ‘unnecessary’ switch, Pip with venvs was also completely solving all my Python dependency problems. I just needed to copy paste a few lines from my README to create and populate the venv, and remember to run pip and Python from that venv. And run pip freeze after package installs or upgrades. No problem. But switching to uv was a huge life improvement. No more copy pasting (‘uv sync’ does everything and even that isn’t needed) nor remembering extra steps and everything is fast so I’m never waiting and forgetting what I was going to do. I could’ve been GP talking about pip but still I would be missing out. I still see people clinging to cvs because it works for them (netbsd why?), which I respect but don’t understand/believe. Fish don’t know what water is. So.. I’m gonna give jj a go and trust life will be better again.
- stavros 1y agoI'm fairly confident you're going to love it. I'd read a few tutorials, but what finally clicked for me was just asking Claude what commands to use, and then explaining why. Jujutsu finally made me understand git, after ten years of git use. It removes enough of the magic that I now know exactly what the commands do, and how the data model works.
- nchmy 1y agoYou'll love jj, as you've already been able to see the the light with new tooling like uv. Jj is to git what uv is to other python tooling. Check out jjui as well, which makes jj even better. https://github.com/idursun/jjui https://github.com/idursun/jjui https://mise.jdx.dev https://mise.jdx.dev is equally as revelatory as jj and uv
- exographicskip 1y agomise is awesome. Put it off far too long after a bad first experience. Now I'll never go back to asdf
- stouset 1y agoMise really is awesome. We are coming into a new golden era of tooling and I want everyone to experience these things. IMO this is all being driven by Rust. jj, mise, ripgrep, fd, bat, eza, delta… all of the best of breed tools these days seem to be coming out of that ecosystem.
- paradox460 1y agoMise just grew support for GitHub, gitlab, and arbitrary http as sources for tools. The ubi integration previously covered much of this, but had blind spots for things that were "bigger" than just a single binary
- palata 1y agoI tend to `git add -p` and create different commits that I put on different branches if they are unrelated. Doesn't feel painful in git, but I'd like to see an example doing that with jj. Maybe I'll try.
- sethammons 1y agoNice commits can really tell a development story that makes reviews easier. That said, I want all teams to squash merge their feature into master after tests pass. One commit at the end, and one commit to remove in case of an issue affecting customers related to the release. A very, very large problem at five out of six companies I have worked at is casual code improvement and refactoring. Devs would say, "we will address that minor and unrelated thing in a separate PR" - one that never comes. At one company, a single PR could address unrelated fixes and it was encouraged to "take out the trash" on the code. Unrelated metrics added, logging improvement, or code simplified, or test robustness improved, etc. That company had vastly better code. Easier to read. Easier to maintain. Easier to observe. And easier to test.
- normie3000 1y ago> That company had vastly better code. It's very frustrating that what IMO is the inferior approach was producing better results in those teams!
- RUnconcerned 1y agoIt's because what you see as the inferior approach involves less effort and friction for the developers. When you are told to separate general code improvements to another PR, or worse, to not do them, and create a Jira task for them so they can be adequately prioritized, it just saps your will to do so. You just won't do any improvements that fall outside the scope of the feature, because even just thinking about the hoops you have to jump through to get work done is mentally draining.
- jon-wood 1y agoI don't know how but we need to get developers out of thinking of PRs as the smallest possible change unit. This is literally what commits are for, you do a chunk of work, and you have a commit which describes that chunk of work. If you've got cleanly isolated commits then when you come to reviewing the PR (or changeset as I'd much rather see them called) and someone questions the wisdom of including that particular change you can either modify the commit to satisfy the questions, or just pull it out of the changeset into it's own for later review without blocking merge of the wider feature. Coincidentally jj makes this process much easier than it would be with git, it will very happily let you shift commits around between different branches, edit commits in place and cleanly rebase those edits onto subsequent commits, or split a messy commit into two commits that makes sense.
- normie3000 1y ago> ...making small and tightly-focused branches that are easy to review and merge is very important. > This is where jj excels. Especially if you find yourself often doing large chunks of work between convenient checkpoints, but you still want to create commits as if this work was all done in tiny and discrete chunks. This is exactly how I like to use git. Sounds like I should be recommending jj to colleagues who struggle with this approach.
- seivan 1y agoThe way I understand it, its for those who can't help but to fix B while working on A and want to make sure that they are two different PRs? The way I do it is after B is done, I just create a new branch and point B to A in the PR. A is pointing to dev/master/upstream. Does JJ make this workflow more convenient?
- nchmy 1y agoYou'd probably like reading about the megamerge workflow. I and others have linked some articles in a few comments here already.
- stouset 1y agoYep! And it makes it convenient even when you need to make changes or add new commits onto A. B is constantly stitched up to remain a child of A and incorporate its fixes. It also makes it simple and easy to split B and A apart such that both their parents are `main` if they’re unrelated. You can also go hog-wild. I was working on a big refactor recently. I made independent changes A, B, C, and D (each one to three commits). I then wanted to work on code that assumed all of these commits were available, so I made a merge commit E that combined them. I then made changes F that depended on that refactor, so was a child of E. Managing this was simple. If I needed to make updates or tweaks to A-D, E and F were updated to incorporate them automatically. `jj absorb` even meant that doing these types of changes was almost zero work: I could make a bunch of changes and the tool would know in which parent commit they belonged. None of this was merged in yet. When I was ready, PRs went out for A-D. When they each merged into `main`, E became a no-op and was discarded. F became its own PR. This is something I never would have done in git because having multiple threads of unmerged code is a colossal hassle.
- stavros 1y agoCan you go into some detail on how you do this? I use jj but it sounds like you make a change and then split it up into more changes after the fact, which I'm not familiar with yet.
- nchmy 1y agoI have a bad habit, even still, of just working in one monster commit. It took me a few months to realize that I could use jj split to move specific files to a different commit. And then I'd sometimes squash them into related commits, rebase to move them around etc... But I just discovered interactive split, which lets you move specific lines and sections from different files in a commit to a different commit. So I've been using that a lot more recently to organize the changes more thematically. Ultimately I should try to become more diligent with adding a new commit any time I start doing something different - it's dead simple to do and even less friction to organize later - but I suppose that I'm not that inclined because the interactive split makes it so easy to do it all later that I just stay in the flow of my monster commits. Everything is possible with jj. just started making much more use of jj split to move split
- stavros 1y agoInteractive split?! Very interesting, I'll look into that, thanks! EDIT: I love it.
- nchmy 1y agoHaha, fantastic. Also, if you didn't discover yet, you can use the arrow keys to unfold the different files and sections. Then select what you need, split the rest to new commit. As you know, even when just using the most basic functionality (new changes, merges, rebases) of jj, it's amazing. But then you just keep discovering other features and workflows - none of which require any incantations - that make it that much better. And I'm sure I'm still only scratching the surface of its possibilities. And, as I keep saying everywhere, jjui just takes the whole experience to another level.
- gdbsjjdn 1y agoI follow this methodology but I just ... use git? The hard part of making multiple small PRs is usually wrangling someone to actually review them, or following whatever process management has decided is necessary.
- endtime 1y agoThe hard part I always found without jj (and Fig before it, when I was at Google) was managing a DAG of small changes. What's your git workflow for a change that depends on two other in flight changes? (More generally, of course, this can occur in an arbitrary part of one's change graph - which is usually not too deep, but at least in my experience, occasionally is.) Having good tooling for this unlocked workflows I didn't know I was missing, and switching back to git when leaving Google felt like losing a limb.
- sesm 1y ago> It's also very helpful if you're the kind of developer who makes lots of unrelated changes in a single coding session, and wants all those changes to be in parallel branches that can be reviewed and merged independently. Git has worktrees for that. If a parallel change is done in a separate worktree, it can be built and tested independently, which, I guess, is important for kernel developers, who are the initial target audience for git.
- mpyne 1y agoI think `git add -p` and its friends are another thing I'd point to for this. I've never really struggled too hard to get git commits into different branches for review, but if you've put unrelated changes into the same working dir, you'll want `git add -p` to sort them out into multiple commits. Note there are corresponding `-p` flags for things like git-restore and git-reset as well.
- steveklabnik 1y agojj tends to use -i for 'interactive' to do what you do with -p in most git commands. It is in fact a great tool, jj makes doing this even easier.
- mpyne 1y agoI'm sure it's great but I don't have the problems with git that others apparently do, so as to make it worth switching to a whole new mental mode of source code management. At least uv solved real problems I was having with Python package management, but for my own personal usage git is 99% aligned with what I need.
- steveklabnik 1y agoI didn’t have problems with git either. jj just makes all of the stuff I liked to do with git easier and faster, and lets me do some things you can’t do with git. But you should use the tools you want to use.
- 1y ago
- therealpygon 1y agoTo be clear, I haven’t used jj so please correct any misundersrandings. I hear you and agree that smaller PRs are definitely easier to understand. On the flip side, it sounds like jj just trades large PRs for lots and lots of smaller, independent PRs that are seemingly unrelated despite all belonging to the same change? I wouldn’t see that as better because, on face, it would sound like far more opportunity for changes to leak out of an actual change-set. Or is the suggestion that the advantage is that each one of those discrete changes carries a comment? Because if developers are lazy, which clearly it is laziness to not use stash for unrelated changes, why wouldn’t I expect every comment to eventually be “{feature}” for everything? So now we need to put more policies in place about how devs should spend more time commenting every one-line code change they make that became an individual PR? And I’m sure jj is going to provide me with a handy feature for then re-grouping all these changes together…back into the original big PR that would have existed in the first place? That seems like a circuitous route to arrive at the same place, but with added risk of unintentional, or worse, missing integration of parts of features that appeared to be independent changes? Ive never found it difficult when I make an unrelated change to just stash that change and add it to its own branch related to a bug ticket at the end of my day. Jj wouldn’t replace 90% of those processes so it sounds like a new way to avoid typing a few commands, by typing more commands more frequently and shifting the workload from a single large relevant change to many, many small changes, all of which were still part of the same set of changes. None of that sounds like a positive to me, so I’d rather appreciate some evangelism to enlighten me and correct my misjudgments/misunderstandings which I fully admit are likely. :-)
- martinvonz 1y agoI don't know why you think jj makes you produce many little commits. Are you thinking about the automatic snapshotting of the working copy? That amends (replaces) your previous commit, so you won't end up with a long chain of commits. It's probably easiest to understand by just trying it. It can be used with regular Git repos.