I don't layer my utensils for example, because a spoon is fit for purpose and reliable.
But if I needed to eat multiple different bowls at once maybe I would need to.
For my personal use case, git is fit for purpose and reliable, even for complex refactoring. I don't find myself in any circumstances where I think, gosh, if only I could have many layers of this going on at once.
Honestly, if you don't find it appealing you don't need to use it. I think a lot of folks don't find vim appealing and stick to vscode and that's okay too.
The jj lovers can go build their massive beautiful branches off in a corner, I'll be over here building an SDLC that doesn't require that.
Old man yells at cloud moment is over
Programs to manage “stacks of patches” go back decades. That might be hundreds that have accumulated over years which are all rebased on the upstream repository. The upstream repository might be someone you barely know, or someone you haven’t managed to get a response from. But you have your changes in your fork and you need to maintain it yourself until upstream accepts it (if they ever call back).
I’m pretty sure that the Git For Windows project is managed as patches on top of Git. And I’ve seen the maintainer post patches to the Git mailing list saying something like, okay we’ve been using this for months now and I think it’s time that it is incorporated in Git.[1]
I’ve seen patches posted to the Git mailing list where they talk about how this new thing (like a command) was originally developed by someone on GitHub (say) but now someone on GitLab (say) took it over and wants to upstream it. Maybe years after it was started.
Almost all changes to the Git project need to incubate for a week in an integration branch called `next` before it is merged to `master`.[1] Beyond slow testing for Git project itself, this means that downstream projects can use `next` in their automated testing to catch regressions before they hit `master`.
† 1: Which is kind of a like a “megamerge”
Yeah, and? Not everyone is in control of the culture of the organization they work in. I suspect most people are not. Is everyone on HN CEOs and CTOs?
Turns out these two differences combined with tracking change identity over multiple snapshots (git shas) allow for ergonomic workflows which were possible in git, just very cumbersome. The workflows that git makes easy jj also keeps easy. You can stop yelling at clouds and sleep soundly knowing that there is a tool to reach for when you need it and you’ll know when you need it.
That’s why it’s always the same confusing hype when it’s discussed, because it’s AI/LLM hype effectively
And better conflict resolution means it often becomes viable to just have mega merge add next release
This. Things like stacks and mega-merges are huge red flags, and seeing enthusiastic people praising how a tool is more convenient to do things that raise huge red flags is perplexing.
Let's entertain the idea of mega-merges, and assume a tool fixes all tool-related issues. What's the plan to review the changes? Because what makes mega merges hard is not the conflicts but ensuring the change makes sense.
What's the red flag about a stack?
I understand if people are enjoying it great, but the amount of praise and 'this is revolutionary' comments I see makes me really feel I'm missing a beat.
This doesn't seem to be entirely up-to-date: http://github.github.com/gh-stack
Won't get you much if you don't like to mutate commits in general, of course; at that point it's just a different committing workflow, which some may like and some dislike. (I for one am so extremely-happy with the history-rewriting capabilities that I've written some scripts for reinventing back a staging area as a commit, and am fine to struggle along with all the things I don't like about jj's auto-tracking)
As a fun note, git 2.54 released yesterday, adding `git history reword` and `git history split` in the style of jj (except less powerful because of git limitations) because a git dev discovered jj.
> Basically, in the megamerge workflow you are rarely working directly off the tips of your branches. Instead, you create an octopus merge commit (hereafter referred to as “the megamerge”) as the child of every working branch you care about. This means bugfixes, feature branches, branches you’re waiting on PRs for, other peoples’ branches you need your code to work with, local environment setup branches, even private commits that may not be or belong in any branch. Everything you care about goes in the megamerge. It’s important to remember that you don’t push the megamerge, only the branches it composes.
> You are always working on the combined sum of all of your work. This means that if your working copy compiles and runs without issue, you know that your work will all interact without issue.
You don't even push the megamerge to the origin. Or perhaps you don't even need to push it. You can just... work off it.
But why would I do that with git anyway ? My local branch is what I'm working of, if I'm not ready to push, why would I ? I can as you say just work off it..
And when I'm ready to push, I prep my commit, because I'm expecting it to be immutable and pulled by others 'as-is'. Again, I must be missing something. I think the tool is just not for me, yet at least.
And I hope you do. It is so much better than git in every way. It enables working with stacks and the aforementioned megamerges so easily, allowing me to continue working forward while smaller units of work are reviewed/merged.
When I first tried to use jj, I wasn't entirely committed and switched between jj and git. Finally I hit a breaking point being fed up with stacks/merges and tried jj _for real_.
I recommend to give it a serious try for a few solid days and use it exclusively to really understand it. You won't go back.
The jj Discord is a very helpful place. Thanks to everyone there. Great article Isaac!
Btw, the risk of trying out other modern version control systems is nearly as low: most of them are compatible with git and you can convert back and forth. That definitely includes mercurial etc.
People tried mercurial. They went back to git.
Though, I'd be remiss not to mention that this (and any other) jj workflow would be much easier with jjui. It's the best TUI around, not just for jj
I proposed incorporating some of this article into it. https://github.com/idursun/jjui/discussions/644
I imagine if I follow this workflow, I might accidentally split it off in a way that branch A is dependent on some code changes in branch B, and/or vice versa. Or I might accidentally split it off in a way that makes it uncompilable (or introduce a subtle bug) in one commit/branch because I accidentally forgot there was a dependency on some code that was split off somewhere else. Of course, the CI/CD pipeline/reviewers/self-testing can catch this, but this all seems to introduce a lot of extra work when I could have just been working on things one at a time.
I'm open to changing my mind, I'm sure there are lots of benefits to this approach, since it is popular. What am I missing here?
When I have discrete, separate units of work, but some may not merge soon (or ever), being able to use mega merges is so amazing.
For example, I have some branch that has an experimental mock-data-pipeline thingy. I have yet to devote the time to convince my colleagues to merge it. But I use it.
Meanwhile, I could be working on two distinct things that can merge separately, but I would like to use Thing A while also testing Thing B, but ALSO have my experimental things merged in.
Simply run `jj new A B C`. Now I have it all.
Because jj's conflict resolution is fundamentally better, and rebases are painless, this workflow is natural and simple to use as a tool
Your repo is small and/or your CI is fast. You’ll understand in a big repo or when CI has to run overnight to get you results.
because agents are slow.
I use SOTA model (latest opus/chatgpt) to first flesh out all the work. since a lot of agent harness use some black magic, i use this workflow
1. Collect all issues 2. Make a folder 3. Write each issue as a file with complete implementation plan to rectify the issue
After this, i change from SOTA to Mini model
Loop through each issue or run agents in parallel to implement 1 issue at a time.
I usually need to do 3 iteration runs to implement full functionality.
You’re right that I have to make sure that the backend changes don’t depend on the mobile changes, but I might have to be mindful of this anyway if the backend needs to stay compatible with old mobile app versions. Megamerge doesn’t seem to make it any harder.
In other words, I effectively was working on one thing, but at a quicker easier pace.
You've missed a crucial detail.
You've both been doing it, but only one of you was using a tool that needed rebases to pull it off.
I gather one scenario is: You do a megamerge and run all your tests to make sure new stuff in one branch isn't breaking new stuff in another branch. If it does fail, you do your debug and make your fix and then squash the fix to the appropriate branch.
My mind was a little blown when I read about the megamerge strategy in Steve Klabnik's tutorial.[1]
Yes, Jujutsu's approach of autorebasing changes is very nice. Now all I have to do is to try it myself.
† 1: https://steveklabnik.github.io/jujutsu-tutorial/advanced/sim...
If none exist, I think there's a great opportunity there, for anyone with the knowledge and motivation to make some absolute beginner guides. Already jj is infinitely more user-friendly, and as the tool matures, it isn't far fetched to think a new generation of programmers could go straight to jj without knowing their way around git first.
It's certainly very usable despite all that, and the changes are simple enough to adapt to, but it's a pretty new thing.
what's next, "oh! my gitess"? "chainsvn man"?
I have a PR up for jjk that does the full change as a review changes, and there's another user's PR that allows diffs over arbitrary ranges (i.e. when working out whether the commits that make up a PR are good as a whole rather than individually)
[1] https://docs.jj-vcs.dev/latest/cli-reference/#jj-parallelize [2] https://blog.chay.dev/parallelized-commits
It's ok to force-push a branch that only you have worked on (and even in the case of others working on the same branch it can be fine as long as you communicate with them)
https://www.jj-vcs.dev/latest/config/#set-of-immutable-commi...
You can force changes with a ‘—ignore-inmutable’ flag.
IUUC This is already implemented for git as an extension. https://github.com/tummychow/git-absorb
I think this is such a basic thing that should be part of any DVCS implementation.
If anyone is JJ-curious, I also can't recommend the Discord[1] enough. The community is very helpful and welcoming.
I'm hesitant to pick jj up in case it ends up losing to git like mercurial did. But it's very tempting.
Eventually I settled on a tree-like megamerge that's more practical: merge 2 branches at a time and merge the merged branch with the next branch. This way I only need to handle 2-way conflicts at a time which is more manageable.
Also you have to be very careful to decide the order when you (and your colleagues) are going to land the branches, or if you expect any new features other people are working on that's going to conflict with your branches. When using megamerger workflow, most of the problems come from coordinating with other colleagues.
When LLMs are driving development, source control stops being an active cognitive concern and becomes a passive implementation detail. The unit of work is no longer “branches” or “commits,” it’s intent. You describe what you want, the model generates, refactors, and reconciles changes across parallel streams automatically.
Parallel workstreams used to require careful coordination: rebasing, merging, conflict resolution, mental bookkeeping of state. That overhead existed because humans were the bottleneck. Once an LLM is managing the codebase, it can reason over the entire state space continuously and resolve those conflicts as part of generation, not as a separate step.
In that world, tools like jj are optimizing a layer that’s already being abstracted away. It’s similar to how no one optimizes around assembly anymore. It still exists, it still matters at a lower level, but it’s no longer where productivity is gained.
It better be, now and going forward for people who use LLMs..because they will need it when LLM messes up and have to figure out, manually, how to resolve.
You ll need all the help (not to mention luck) you need then..
You're bashing the old way, but you do not provide any concrete evidence for any of your points.
> The unit of work is no longer “branches” or “commits,” it’s intent.
Insert <astronaut meme "always has been">.
Branching is always about "I want to try to implement this thing, but I also want to quickly go back to the main task/canonical version". Committing is about I want to store this version in time with a description of the changes I made since the last commit. So both are an expression and a record of intent.
> Parallel workstreams used to require careful coordination: rebasing, merging, conflict resolution, mental bookkeeping of state.
Your choice of words is making me believe that you have a poor understanding of version control and only see it as storage of code.
Commits are notes that annotates changes, when you want to share your work, you share the changes since the last version everyone knows about alongside the notes that (should) explain those changes. But just like you take time to organize and edit your working notes for a final piece, rebasing is how you edit commits to have a cleaner history. Merging is when you want to keep the history of two branches.
Conflict resolution is a nice signal that the intent of a section of code may differ (eg. one wants blue, the other wants red). Having no conflict is not a guarantee that the code works (one reduces the size of the container, while the other increase the flow of the pipe, both wanted to speed up filling the container). So you have to inspect the code and run test afterwards.
Discard the above if you just don't care about the code that you're writing.
I'm still not as smooth at figuring out conflicts on mega-rebase.
There's some counterproductive stuff in there from my perspective but at its core you're keeping up a throwaway integration branch, which is helpful practice if you'll ever care about an integration. It's annoying with git because the interface for updating your throwaway integration branch is very clunky and easy to get wrong.
I just wish Jujutsu supported git tags rather than only supporting bookmarks as branches. And I also wish that Jujutsu supported preserving commit dates during rebases.
One of my absolute favorite things about Jujutsu is how easy it is to manipulate the commit graph remotely without having to manually checkout each commit first. I've been working on some pull requests to their built-in diff editor lately trying to improve the user experience enough that most conflicts will be fixable without having to use a text editor.
Also, the lack of a special staging area means you also never have to fucking stash your changes before you can do practically anything. Your changes always have a place, you can always go somewhere else and you can always come back.
There are commands for manipulating tags (jj tag set, jj tag delete), and recently [1] support for fetching / pushing
Probably my favourite thing that has really changed my workflow is being able to write empty commits in advance then just switch between them. It helps me remember what I’m doing and whats next whenever I get distracted or take a break.