Last time I tried jj, branches were an extremely laborious process to keep up to date. I don't see how people that aren't working alone can work with that. I have numerous branches in flight at any given time, and my colleagues do as well. The idea of manually keeping them pointed at the right commit is just nuts.
Maybe they've fixed that astonishing choice since then, and I'd give things another go if they did. But branches and worktrees are how I operate.
Regarding the article, I have no idea what is going on as I'm red-green color deficient.
There are just multiple different ways of working. Some ways fit some people's mental models better.
You're not going to get a definitive "jujutsu is better than git" or vice versa. You should accept that some people have no problems with what you've described using jujutsu, and likewise jujutsu users should understand that not everyone can handle jj as well as they can.
Imagine a different thread where jj users take your exact scenario, and complain about solving the problem with git. You wouldn't understand their pain, because it's not painful for you. This thread is the same, just with jj and git reversed.
Personally, I don't see the pain you have. Back when I used git a lot, if I left a branch for a few weeks, I'd forget the name of the branch and would have to list all the branches (and set an alias to sort by and list the last commit dates of each) to discover the appropriate branch name. It's really not all that different from looking at all (recent) heads. Once you get used to this, you stop naming branches - other than to share with others. And when you do share with them, you cannot push (newer) changes because only bookmarked nodes and their parents can be pushed - so just prior to pushing, you advance the bookmark. With the shells I use, it's a few keystrokes before autocomplete/fzf produces the command for me - no mental effort at all.
You definitely wouldn't advance the bookmark with each commit. Only when you need to push.
And oh man, it's so nice not to have to manage all the branches. With git, I'd routinely go and delete old branches to declutter. With jj, there's simply no need to. The same with stashes. It's really nice not having to do that labor, and simultaneously not dealing with long lists.
If this doesn't appeal to you - that's fine. You're not deficient. But understand, nor are those for whom your workflow sucks.
If it is like you say and different people are just inherently more or less suited to different paradigms, then not everyone can be happy.
This whole thread is about working with git coworkers while using jujutsu, and it was in that context that I wrote my comment: Namely that most who prefer jujutsu happily work with their colleagues who use git in precisely the scenario the OP mentions and don't see why the OP finds it painful. The OP and others should accept that reality.
> If it is like you say and different people are just inherently more or less suited to different paradigms, then not everyone can be happy.
If you force everyone to use git, of course not everyone will be happy.
If you force everyone to use jj, of course not everyone will be happy.
Thankfully, the whole point is git and jj users can interoperate without needing to care what the other is using. So yes, not only can everyone be happy, but everyone is happy! This isn't a hypothetical - it's a reality. It's the reason so many use jujutsu at work.
Bookmarks aren’t that bad either IMO, especially with the recent addition of `jj bookmark advance`. Curious if you can say more about the particular difficulties you found keeping them up to date?
I often work on something and then switch away to something else. it might be a week before i get back to it, and the name of the branch is a clue as to what the heck I was doing.
Other people often need to check out a branch I'm working on to help. How does anonymous branching help anyone except a solo developer?
I think I misread you, because you were talking about git vs svn in a way that made it sound like jj was a step backward from git as regards branching, and I got confused.
> I often work on something and then switch away to something else. it might be a week before i get back to it, and the name of the branch is a clue as to what the heck I was doing.
Right, but you can still name your branches with bookmarks, you’re just not required to. Personally, I tend to use commit descriptions more than bookmarks to keep track of what I’m working on, but this is a personal choice.
> Other people often need to check out a branch I'm working on to help. How does anonymous branching help anyone except a solo developer?
It’s just nicer as a local workflow, to me at least? I can create throwaway branches without having to come up with a name for them. I end up creating many, many more branches than I did in git as a result, which helps me keep my work better organized and my changes more focused when I submit them for others to review (which at least on GitHub, requires a bookmark of course). This is ultimately psychological because obviously I could just make up a name for the git branch, right? But it makes a big difference for me!
Ah, this is what the description (what git would call the commit message) is for. You can set the description even before you've made any changes.
Is it easy?
Some later googling revealed `git rebase --onto origin/main theirbranch main` was probably what they needed. Which I’m sure would have come to me quicker if I hadn’t dropped the git cli for jj 2+ years ago.
Personally I’m a huge fan of this approach. If you aren’t, it’s literally just a one-liner (that is trivially made into an alias) to advance a branch name to the most recent revision. And now there’s a feature to do auto-advancing if you want it.
Why is it this way? Because jj is designed around revisions being constantly mutated.
In git, when I make a commit, I am typically signaling that that a chunk of work is complete. Not always, but usually. In most jj workflows, revisions are mutated constantly during development. A revision being made on the tip of a branch is rarely a signal that that unit of work is finished. It’s even incredibly common to have multiple revisions in a row that are works in progress. Hell, the article we’re all commenting on discusses just such a workflow. If I make five revisions on top of some branch, there is no reason to assume that any of them are ready to be shared, much less all of them.
Because of that difference, it makes sense to have an explicit act to move a branch name forward.
I dislike this as well. I find it easier to keep track of branches with bookmarks, but my workflow still makes things cumbersome. I am usually working with the "megamerge" branches, and I usually want to add commits to my current branch instead of squashing my edits. However, adding commits means I have to add my commit, move my bookmark up to the branch tip (jj tug?), and then rebase the megamerge branch, versus doing nothing for squashing. I also find that when I mess up, I don't really love using `jj op log` to fix it. I want to not be in an environment where it's this easy to destroy history (I feel like git was on the other end of it).
That’s why I always use jj’s automatic commit identifiers. They are short and I don’t waste brain cycles naming things that are ephemeral. When I push, I let jj automatically creates, updates, and deletes remote git branches (`jj git push -c` for creation, plain `jj git push` for updates, `jj git push --deleted` for deletions). I do not ever have to think about branch names and it is great!
Restricted and summarized is good - easier to find/remember, less fluff in a list. And easier to recognize a short identifier from a list of the 2-3 most recent branches, than scanning through 50 commits, when trying to remember where some work last was, and which is the proper end-point instead of some failed attempt or unrelated change.
Unnamed branches are quite neat - I certainly have a lot more of such than named ones in jj - but as such named branches are, if anything, more important as a result, for separating sequences of changes striving towards a goal, from the sea of smaller experiments.
Wrong. With jj, I use `jj describe` before I start work. It is like writing out a plan for what I want to do.
> Or, if you have, you've quite potentially just wasted time writing something that will be rewritten anyway as things change.
Rewriting it is not wasted time. It is an opportunity to look at what I have written in the plan and check whether I have really executed them, and then rephrase things to be more easily understandable.
> Restricted and summarized is good - easier to find/remember, less fluff in a list.
The first line of a commit message is already a summary of the work done. And you can use actual English instead of trying to awkwardly avoid spaces in your words.
But when I'm picking up something someone on the team has left behind because they got pulled on to something else, or are sick, or 5 million other reasons, having a branch, with a ticket in the name, explaining what the purpose of the branch is, why it exists, what it's current state is, that all matters. I can't help but think that everyone that likes JJ isn't really doing collaboration.
> having a branch, with a ticket in the name, explaining what the purpose of the branch is, why it exists, what it's current state is, that all matters
In my view, all the above information exists not in the branch name, but either in the ticket, or in the commit message. The branch name is purely a superfluous thing that does not convey any information. Many of my colleagues already use a tool to automatically name their branches from the first line of their commit messages, and jj just makes this awkward process straightforward.
branch names are just a summarization of your commit messages
What kind of dev workflow leads to this surprising opinion?I like Jujutsu so much that I've been working on massive refactors to my tooling in order to support it (example: https://github.com/LoganDark/get-shit-done)
But I don't rewrite history. It's history. While I can understand people have reasons to do it, the reasons have never resonated with me. I'd rather spend my time getting new work done and not polishing work I've already done.
To me, jj has inherent value because I do a lot of things raw Git makes difficult or impossible. For example, https://github.com/LoganDark/fabric-template supports every point release of Minecraft since 1.14, and mods like https://github.com/LoganDark/debrand derive from it. I often rewrite the history of the template with configuration improvements and then rebase the histories of each mod on top of it.
This keeps my project setup consistent throughout versions, and consistent between mods, and allows all my mods, across all supported versions, to benefit trivially from all improvements I make to my global template. This workflow is either not possible with git or would require slow, ugly and fragile scripts.
It feels like Apple vs Linux. Apple being different ... just because (it gives them an artificial moat)
I’m pretty sure `jj absorb` (and its predecessors, `git-absorb` [0] and `hg absorb`) are smarter than this, instead looking at the actual diffs.
> [absorb] splits changes in the source revision and moves each change to the closest mutable ancestor where the corresponding lines were modified last. If the destination revision cannot be determined unambiguously, the change will be left in the source revision.
I use absorb fairly often, fwiw. It's great for when I want to make a patch to a commit that will easily absorb into its right place. And I also, sometimes, prefer the more intentional approach where I decide exactly where each hunk will go.
A checkout is a working space after all, why can't it be (temporarily) dirty whilst you work?
1. Squash all your commits in this branch to one
2. Move that commit to the working directory with the appropriate git reset command
3. Commit hunks as appropriate.
Basically, if you don’t get into that sort of situation with commits containing parts they shouldn’t in the first place, you don’t need to do any extra work to clean them up. The tip of your branch should be the only “messy” part.
I start a new branch and begin work. When I’m ready to start organizing that work into a consistent narrative (or when bits are “finished”), I split it out into independent commits. As I keep making fixes and tweaks, I continue squashing bits from my working commit into the parent commits they belong on.
I don’t bother making any independent commits until pieces of what I’m working on are becoming fully-formed. Until then, my working commit just has everything.
> Some people prefer this, as it helps git bisect work better. Debuggability versus reviewer convenience is the tradeoff, I guess.
Ideally we would have a VCS that made ergonomic to store both history-as-it-happened for some purposes, and the cleaned up, squashed and rebased history for other purposes, ensuring they match
You can revisit the original PR to see the individual commits if you really want.
I see there's a similar project for JJ, but it doesn't seem nearly as polished https://github.com/Cretezy/lazyjj
It is also true in reverse. Scopes set too broadly ("dark mode implementation," "auth flow fixes") lead to un-readable diffs no matter what tool you use for version control. Un-readable diff does not stem from commitment discipline; it is a scope problem.
That said, this fact does not diminish the usefulness of Jujutsu. There are valid use cases for the rebase and stacking operations. However, the discussion about commit granularity takes on a whole new context once the constraint of having readable commits is established at the scope setting stage.
Is that a frequent way of reviewing? On GitHub you get shown all changes together in the review tab. You can select individual commits for closer inspection, but where is the benefit?
I just don't see the fuss about rebase. Merging just works fine.
Edit: OK, I realized later that I'm not really responding to the usual git rebase -i use case.
Have you heard people say that because of magit they started using more "advanced" git workflows, and how they emphasize having a better UI makes a difference?
It's the same idea with jujutsu. I'm much more likely to use git's power via jujutsu than directly with git. It's because jujutsu lets you do it all with a much simpler interface - fewer commands, and fewer concepts. And knowing that "jj undo" has your back.
As a sibling commenter said: Likely 99% of git users don't do "git rebase -i". But the percentage who do similar with jujutsu is high - perhaps over half[1] of jujutsu users do the equivalent of "git rebase -i" all the time. Many of them didn't when they used git.
The interface matters.
[1] If you told me 80%, it wouldn't surprise me in the least.
Just give me the PR, don't sweat the individual patches. But maybe also work on not committing your first idea as finished work.
`git branch` is basically my bookmark tool. I commit for a while, then when I want to remember where I am for later, `git branch wip/topic-a-finally-compiles` or whatever. I can reset hard to it when I want to revert back, or any other topic I need. If I forget to name a branch for a commit, the reflog is right there. Nothing’s lost.
And yeah, a soft reset is basically the ideal way to just say “pretend all my changes weren’t committed yet, starting from $ref” and then I make my single commit for my PR. Easy peasy.
I do switch branch for long experiments and touch up on existing PR.
It would be great if a PR was about distributing patches and not having those automatically generated from a branch.
To some of us, that's an essential structural criterion. Passing unit-level self-tests may be as well.
git rebase -i
# squash all the commits (e.g. in vim with ctrl-v)
git reset HEAD^
git add -p
# interactively pickup the RED hunks
git ci -m RED
The main difference to jj is that the RED commit is created later with git.Jj is not git and is not a git tool, it just (thankfully) uses git as a backend, so you can still carry on with the rest of the world.
In what way is that different from using `git rebase -i` to edit a commit?
There are no modal “sorry rebase failed, best of luck” gotchas. There are no “oops I put the wrong thing in the wrong part of the rebase and now I have to abort and start all over” gotchas.
It’s rebase, but without all the extra work, mental overhead, failure cases, and effort.
It tries to solve a human problem in an LLM era.
LLMs are destined to overcome humans in code merging and change versioning (already did for me).
There's little point to introducing yet another layer of indirection when LLMs just cut to the chase.
A lot of humans still don't use git too.
Many do only when they are forced.
And it's much easier for a professional to be forced to use LLMs than jj when it comes to versioning assist (not even comparable in mindshare but the obvious needs to be said sometimes).
So unfortunately I'm afraid jj is not going to achieve critical mass before 99.99% of merges are done by AI which don't need jj.
I don't know about all that. All sorts of ex-post-facto automated cut-up-and-splice commits sounds to me like a recipe for an every larger mess. I say maintain git rigor, always. Now, you could say "You only say that because you know git rather than jujutsu" or "if you use git absorb more you'll get it", and theoretically you might be right, but... meh, I kind of doubt it.
Seems straightforward, wouldn’t call it special
Yes, you can do most commit manipulations with git just like with jj. But, users of jj know they're "looking down the power continuum" (to reuse pg's terminology) when they look at git, whereas git users cannot fathom what's exactly the deal with jj. Unfortunately, the only way to get it is to spend a week with it, with an open mind. It's close to impossible to describe it except "it's really neat" and "wow it removes all git's friction I didn't know existed".
And, apparently, there's a pattern of having to try at least two times before it becomes intuitive!
It's not relevant. Don't try to convert git users--you don't need to. They're fine doing what they do, and the git backend store is acceptable. People who understand how broken git is will gravitate to jj with the lightest of prodding--give them a light poke and then don't harass them further.
The main difference is that I can teach jj (like I could teach hg) to normal people. And, because jj is based on the git store, they can operate in a Github world.
So, just teach jj to people who haven't yet broken their brain with git. Running on the git backend already gains most of the network effect, so don't proselytize the git people.
The same problem with vi for example. Which I learned, deeply and for a long time. Maybe I will be break even in a decade or two. And for example, I can code faster than anybody who I know and use vi all the time (or some vi keyset in Emacs or something), not because I type faster, but because I don't need to rewrite my code that many times than them.
The same with jj. I'm happy that it clicks better than Git for some. But I know Git from inside and out. Git was never the bottleneck for me. And really any VCS in the past. If I learn jj, then I don't expect that the effort pays off in a decade or less in the best case. My work's result would be the exact same thing, just with different commands, commands which takes almost no time compared to my other tasks.
We do get it. But have you ever thought that git inflexible nature and full control is what some people people like?
Having three different state for your work (working tree, staging, and committed) is nice for reviewing code. Picking lines and chunk give me an additional mental state to think about the design of the code.
And once upon a time, I preferred history log like the one in the article. But this days (mostly inspired by mailing list development style) I wants the commit in my main log to be either features or bug fixes. Everything else is “wip”, which I will squash. It makes it easier when rewriting history, cherry picking, or just browsing the log.