Having worked at Google I have unfortunately been exposed to what is possible when in comes to version control systems. I have been looking for a git alternative that is just generally simpler, more ergonomic, and allows for things like stacked PRs while maintaining git compatibility, since everything is on github.
I am uninterested in `you can do that in git with [insert esoteric commands]`.
My main contenders right now are Sapling[0], a project from Meta, and jj[1]. I am wondering if anyone has experience with either, or definitely those who have tried both, what was your experience? They both have a lot of nice features.
[0] https://sapling-scm.com/ [1] https://github.com/martinvonz/jj/blob/main/docs/sapling-comparison.md
There's also Pijul. I have only had a brief play with Jujutsu and I haven't tried Sapling but from what I can see, Jujutsu is definitely the best option if you want to actually get stuff done while mostly maintaining Git compatibility.
Pijul is definitely still in the research prototype phase, and definitely not Git compatible. I don't know how Git compatible Sapling is, but large parts of it are still labelled "Not yet supported publicly, OSS is buildable for unsupported experimentation." It also feels like a VCS that was designed for Facebook and then open sourced, so it is targeted at the use case of "massive company monorepo, and we have 10 guys that run the infra". That's great, because Git is bad at that use case, but it might not be what you want.
The command line interface for Sapling called `sl`, which is Git compatible, is fully supported by the team at Meta. You can file bugs and feature requests, etc, though the repository is a bit intimidating. It is only the non-Git server components (Mononoke, EdenFS) that are not yet really supported [1] but I think most people aren't really concerned with that, when writing a post like this.
For all intents and purposes, Sapling works very well, I think, and in some places it has a lot more polish, like the "isl" graphical interface, which makes things like rebasing and restacking incredibly intuitive even for new users. (I consider isl to be a significant advantage over Jujutsu, and I say that as a Jujutsu developer!)
[1] Though, Mononoke does support features like exporting Git repositories to remote hosts from the internal model; that's not really what people are looking for in a lot of cases though.
> The command line interface for Sapling called `sl` [...]
This is a really unfortunate choice of the binary name - it collides with a classic UNIX utility. I use it everyday and it would be very annoying for the program to do something unexpected.
Edit: apt install sl
The package name will be sl-vcs like chromium-browser
Just the name makes it a no-go for me, it would interfere with my favorite command-line utility, `sl` - Steam Locomotive
What's the advantage of using Sapling as an alternative Git frontend?
You don't need to manage the stash or index, those are just expressed as commits, so you have fewer commands and a simpler UX, and can use universal tools like 'split' to handle cases you'd otherwise need stash/apply/switch to handle.
It supports Mercurial-like "revsets", so it is easy and flexible to query the commit graph for all kinds of information, in a user-controlled way.
Features like 'sl absorb' can do git 'fixup commits' automatically.
It supports a notion of changeset evolution, so if you have `A -> B -> C` and `A` gets merged into main, it will automatically rebase `B -> C` on top (among other things).
"isl", the "interactive sapling" GUI, is absolutely stellar and I don't think there's a faster way to do tasks like 'rebase X onto Y' or "reorder commits in stack Y" than that, even with Jujutsu.
It comes with integration for a tool named ReviewStack so you can do stacked code reviews while working on GitHub.
There is an undo command to undo your mistakes.
And, while I'm not sure this is in the Git backend today, many algorithms like getting the history of a file are O(N) in terms of file history as to the history of the whole repo (e.g. try `git log file` in gecko-dev or Linux and it is slow.)
Many of these advantages (not all) are shared with Jujutsu, to be clear.
> You don't need to manage the stash or index, those are just expressed as commits,
You can also avoid managing the stash in Git. By not using it.
But you still need to deal with a dirty working copy somehow. This blog post from today happens to describe one scenario where it's nice not to have to worry about changes in the working copy:
https://drewdevault.com/2024/12/10/2024-12-10-Daily-driving-...
Pijul's "upstream" (and git predecessor) darcs is still useful today. It doesn't see itself as a "research prototype" and has decades of experience in the real world. It isn't git compatible but does offer a fine fast-export to git in the worst case you need to switch.
Unfortunately some of those decades of experience with darcs are lessons in how it performs poorly in large repos or with large teams/lots of merge conflicts, but that still leaves darcs a good experience for small projects and "just getting stuff done".
Jujutsu replaced git for me in February of this year, except for managing tags, which I reach for the git cli for in my colocated repositories. I find it is much easier for me to create a sensible set of revisions that linearly approach my desired state for the working directory, even if I did not linearly arrive there.
I also use features of jj that are not available in git all the time, like rebase -s (rebase a tree from the root), split (turn one revision into two), absorb (cascade changes into a stack of revisions where the lines were last modified), etc.
Given how stable git is as a repo format, I find it unlikely that I will ever go back.
At work I’ve been using jj for the internal Standard Chartered monorepo (6.5 MLOC). I didn’t ask anyone, just installed and started using it. Git compatibility is a killer feature.
(if anyone from SC is reading this -- search our wiki for "Jujutsu" and come say hi!)
Pretty much a strictly better experience than git so far — I’m not going back. `jj undo` is something that I expect in every program now and get vaguely annoyed it's not there.
Not having index/staging is great. Checking out another branch, switching to work on another thing, fixing a typo in an unrelated module, etc are all frictionless. "I'll insert a new commit five-commits-ago, do the refactoring there, and resolve conflicts" turns out to be much nicer than "I'll do the refactoring here and carefully stage it hunk-by-hunk". (I get distracted a lot -- maybe if you aren't tempted by shiny refactorings, this isn't a big deal for you.)
The merge story is also great. I have a commit with multiple parents. I can add more parents to it, change parents, rebase it somewhere, move it around. I have no idea how "rebasing a merge" works in git, but I'm afraid to try. In jj I don't care.
There are a few issues with jj that happen to not be a big deal for me, but I can imagine they could be a dealbreaker for someone else:
- No submodules support (yet)
- No LFS support (yet?)
- Doesn't track renames (yet?)
- When you do `git pull` with rebase, git skips duplicate commits -- this is great if something got rebased/amended on the remote. I was always suspicious that `git pull` just works even if I rebased the branch remotely, and now I know why it works. jj doesn't handle this yet. Not a big deal unless two people collaborate on a branch and want to do it the jj-way with rebases of everything.
have you experienced particularly slow pushes with large repositories at all, and if so were you able to resolve them?
I did some profiling & it looks like the issue lies with `libgit2`, but I haven’t been able to replicate the issue outside of that work codebase[0].
[0]: https://github.com/martinvonz/jj/issues/1841#issuecomment-23...
I just started a new job where I’m collaborating with the maintainers of mercurial, and was asking them about these alternative VCSs last night. It was interesting to learn that all these people are in contact with each other and there’s a lot of cross pollination of ideas. And for some newer ideas e.g. in jj and pijul, where just reading the website would have me 100% sold, they had more nuanced takes on the pros and cons. So I feel less confident in giving advice than I would have a few days ago. But if you need seamless git compatibility, I’ve personally found git-branchless to be the best solution for the requirements you listed as a thin layer over git. I also tried jj a while back and I liked it but I found being further removed from git made it harder to drop down into regular git when I needed to. In particular I had issues with jj log showing lots of irrelevant commits but that was probably because of our particular Gerrit setup and might have been fixed by now.
JJ is incredible. Highly recommend it. I can't put into words what a game changer it is for my workflow.
The only thing I reach for for git now is `bisect` when I need to debug an oncall issue.
I have never really made bisect a part of my workflow, but something I believe would work well with just jj is making two workspaces before and after the issue, and iteratively walking their working revisions toward each other. That has the advantage of being able to run both versions simultaneously easily.
What do you mean both versions? They are all different versions.
You have N versions between your endpoints, and you test log(N) of them. You don't test any single version more than one time.
You can run the tests on each commit in parallel if you're okay with wasting CPU time to save wall-clock time. git-branchless can speculatively run linear or binary search in parallel up to a user-specified number of jobs [1], and I'd like it add it to jj someday, as it's one of the features I miss most.
(To run the tests in parallel, git-branchless provisions its own worktrees. For binary search, it speculatively executes the search for the potential success and failure cases; when the number of jobs is a power of 2, this partitions the search space evenly.)
[1]: https://github.com/arxanas/git-branchless/wiki/Command:-git-...
For certain applications and bugs it may be helpful to see a version of the application with the bug running side by side with a version without the bug. By "both versions" I meant the versions checked out in both workspaces. See: https://martinvonz.github.io/jj/latest/working-copy/#workspa...
But you don't know in advance whether a given version has the bug, that's kind of the reason for bisecting. Or do you mean you have 3 versions side-by-side: the last-known-bad, last-known-good, next-unknown-to-test?
FYI git has "worktrees": https://git-scm.com/docs/git-worktree
I mean making two workspace, and iteratively walking them towards each other in the revision tree, until to you cross the revision that introduced the bug (either both instances show the bug or neither does). There isn't really a reason to have three workspaces. If you want to mark where you were so you don't forget, you can just use bookmarks, but really you can just look at the operation log to see where you were.
This is a nice reminder for me to check it out.
I've liked Phabricator, and Google's internal variant of Mercurial in the past (and have always despised GitHub's PR=branch model). Sounds like Jujutsu might be right up my alley.
I like fossil. Much prefer it to git. No idea what stacked PRs are but it's compatible with git and way simpler in my opinion. Plus comes with some nice extras like tickets, wiki, UI.
It comes up a lot in split repos or split deployments.
To make a change you need to deploy part of it here, then another part over there, and maybe fiddle with some settings in between.
So your story ends up with several PRs that have to land in a specific order or things break. Eg client calling a new endpoint that doesn’t exist yet.
We call these chains of dependent reviews “stacked” for reasons I’m not entirely clear on.
That sounds like a nightmare, and I'm glad I've never had to deal with something like that. Benefits of not being a professional developer.
Stacked PRs is GitHub users (or Phabricator) reinventing commits as pull requests.
Off topic. I saw this thread the other day and thought it will be an interesting topic. But then it dropped off and disappeared. I doubled checked the topic was 2 days ago but now it reappeared as 2 hours ago. Anyone knows why?
Hackernews has a “second chance pool”, where the mods decide to reignite topics where they feel there was no enough deserved attention.
Or… it was just resubmitted.
Do you mean the link stopped working, or just that it fell off the front page(s)? It was probably second-chance pooled, iirc that resets the submission date. Timing is a factor in submissions' success, they don't necessarily get the right eyeballs to get upvotes & attention before more else comes along.
I have been using `git-branchless` a lot and really liking it. It should be part of the main git project, consider it a halfway between git and switching to some other tool.
For what it’s worth, the main developer of git-branchless is also a `jj` contributor
One of the main reasons to use git-branchless over jj or Sapling is if you need support for a workflow that's not supported in jj/Sapling yet, such as Git LFS. I (git-branchless author) would like to see both systems get to feature parity one day to unblock users who would like to migrate but can't.
These days, there are relatively few things that git-branchless can do that jj/Sapling can't, one example being its (somewhat opinionated) `git test` command: https://github.com/arxanas/git-branchless/wiki/Command:-git-...
Do you perchance have something directly comparing jj and your branchless work?
Regardless keep up the good work. Assuming some one hasn't done it while I haven't been paying attention I will some day write some code to support gitlab in the submit command (I have a script I use all the time, just written around it rather than within).
I don't have anything written. These days, the only unique things git-branchless has are certain commands (`git test`, `git sync`, `git submit`, which would be good to implement in jj), and a few minor features like `git record --stash`, and of course compatibility with various Git extensions like LFS.
Lots of discussion on this jj post: https://news.ycombinator.com/item?id=36952796
A question: I prefer jumping into the command line for most of my git work. But, I'm intrigued by this discussion and wonder: how well do these tools work within an editor? I am using Zed, which IMHO has poor git support anyway. I'm curious if the experiences here are mostly from people who do not use their editor as their main point of contact with the code repository they are working on.
I use jj and zed. More appropriately, I happen to use jj and I also happen use zed, and I never really think about them together. All repo-level work I do with the cli. The only thing I really care about in-editor is recency on a line level, and since jj uses git, zed has no problem showing line-level metadata. There is a slight difference because of jj's stage consolidation, but I don't find that to be a problem, since there's not much of a difference between a line in a staged file vs a line in the working tree.
Thanks so much for this!
I use git gui (git extensions) so I don't know bother with cli unless I have to
I'll use JJ through an integrated terminal in my editor
For a quick impression, the jj-fzf README has a number of screencasts that showcase tasks easily accomplished with jj (using fzf to preview the jj log and key bindings to invoke jj commands):
https://github.com/tim-janik/jj-fzf?tab=readme-ov-file#split...
(Another self-promotion)
I tried jj recently based on a sub-thread here on HN, have to say I did really like it, but still came away feeling like it was going to take a lot to train the muscle memory away from git.
Edit: Here's that sub-thread: https://news.ycombinator.com/item?id=42112574
If you're looking for a polished way to manage a stacked-PRs workflow with git and GitHub, I highly recommend Revup. It was invented at Skydio when I worked there, and quickly developed a cult following among engineers there. I wouldn't describe it as simpler than default git, especially since you still mostly use git commands (like rebase -i) for lots of tasks, but for power users it provides a really nice workflow.
For me, the most interesting differentiating factor at this point is probably the GUI tooling for Sapling. Try out their "interactive smartlog" and see if it resonates with you.
I switched to jj about a month ago and love it.
Broadly speaking, commits in git represent two conflicting ideas – a mechanical representation of the state of the codebase, and a logical series of changes for bisecting and human readability. It's possible to manage this in git, but painful.
In jj, these two concepts are separated – you have Revisions which represent the mechanical state, and are saved every time you run any command, even `jj status`. And you have Changes, which represent the human readable stuff, and can be edited at any time. This makes it really easy to save lots of snapshots, while carefully crafting your Changes for a readable history.
I was surprised at how easy it was to adapt to jj. It didn't feel like I had to learn a lot of stuff or a big new mental model, it turns out to just be pretty simple to craft the Changes at any point I please.
> I am uninterested in `you can do that in git with [insert esoteric commands]`.
Why? If the only requirements you specified are that you're looking for something that is compatible with Git but with better ergonomics, wouldn't something that wraps Git (whether that's via aliases or something more comprehensive) fit the bill?
It's a fair question, but the answer is simple: because there are significant design choices in the UX and algorithms which are user visible, and percolate throughout the entire system design, which can't just be wrapped or alias'd away.
There is git-branchless, which is kind of like this[1][2] and is something like a half-way point between Git and Jujutsu/Sapling. However, it needs to be stated that git branchless does NOT just "wrap" existing things or alias them. It has significant engineering to add features, using a lot of code, because you can't "just" add things like revsets or 'undo' using wrappers or aliases, at least not in an efficient way.
Some examples from Jujutsu are that:
A) jj rebase is lightning fast compared to git rebase, because it works in memory. Git rebase touches disk for all operations, so it becomes slower the larger the repo, the more history, the bigger the files etc you have. You may spend significant IOPS moving large-ish files around, flushing the index to disk, and so forth; and you also cannot do things like rebase inside a bare repository (imagine you want a handy "Rebase branch on main" button in your GUI -- you need to have the whole working copy to do that!) jj rebase works entirely in memory so it never touches the disk for any files in the commits themselves. This is called "git move" in git-branchless, but requires significant code. Git itself is trying to solve this with a new "git replay" command, but it is extremely new and has some current limitations compared to, say, Jujutsu, IIRC. (But the fact they have to add a whole new command with significant code is a good example of how the algorithmic differences matter and can't be papered over.)
B) Revsets are a non-trivial addition to make the commit graph "queryable", but they add open ended features in a way that can't easily be recreated without them, because they are composable. For example, "list all commits authored by me that are not merged into main that can be rebased on main" is written as `all:mutable() & mine()`, but to recreate this level of flexibility you would need a dozen one-off features added to something like 'git log' -- but these revsets can work with many more commands than log! You can use the above revset to automatically rebase all your open branches at once for example, which is not possible in Git without shell scripting (what about Windows users?) and duct-taping stuff. But then where's the reuse?
C) Jujutsu has a notion of first-class conflicts, which can only be vaguely approximated with something like `git rerere` and `git rebase --update-refs`, but this isn't quite the same because for example you need to know details like purging the rerere cache if you get a conflict resolution wrong and want to undo it and start over, not to mention you can still easily screw things up mid-way with `git rebase` in a form that requires you to start over. These "catches" do not apply to Jujutsu and I have no idea where you would even begin if you wanted to add a feature like this.
So, the details matter a lot in practice for users, and delivering them a good experience is something that I think is way more difficult than just a bunch of opinionated commands. To be clear, if you like opinionated aliases and wrappers, that's OK! But there's a lot more underneath the surface if you scratch at it a bit.
[1] https://github.com/arxanas/git-branchless
[2] The main developer of git-branchless also is a Jujutsu contributor, so these ideas and the implementations aren't totally a coincidence!
For more info, here are some git-branchless write-ups on the topics:
- https://blog.waleedkhan.name/git-undo/ — has a link to this article explaining some things that can't be undone in the Git model via reflog: https://github.com/arxanas/git-branchless/wiki/Architecture#...
- https://blog.waleedkhan.name/in-memory-rebases/ — It's non-trivial to support workflows like "rebase just commit X out of its branch and insert it before commit Y in that branch" in a single command. jj implements the same workflows as well.
You mean how jujutsu uses the same git repo and you can use jj while other people you collaborate use git?
Yeah they're doing that.
I've been using Sapling along with the VSCode extension for ISL which mostly gets me a better workflow with diff stacks locally (Github isn't great dealing with stacks though).
The only major limitation for me is git-lfs support so for certain repos I have to revert to git.
Documentation, training, and relative ease of acquisition and installation are properties of the git ecosystem that are hard to replicate outside of an organization with a business case like Google.
That's the setup for: Who are the intended users and in what context will they use it?
If it's just you or you and your employees, selling no github can be straightforward. If it's your boss and some other teams, it's gonna be harder. Good luck.
Both Sapling and Jujutsu are compatible with Git repositories, and there are even settings to have the `.git` directory exposed so that all of your existing tools will be able to run Git commands, show hunk changes in the gutter, etc. For all intents and purposes, you can use them in place of or alongside Git, and none of your colleagues will really need to know. This is a significant advantage over competing non-Git systems, and one of the major selling points that incentivize people to even try it at all.
If it means anything, I have been using Git for 15 years and am one of the earliest GitHub users, and I have not regularly used Git for nearly anything, in any job, for over ~1.5 years now. (Disclosure: I am also one of the Jujutsu developers though, so take that for what it is.)
Not to dissuade people from looking into alternatives, but the high quality integration that Git has with every single code editor in wide use today is a huge advantage over every other VCS imo. As far as I can tell, the closest to it in that regard is Subversion, but it's not all that close. One of my friends is getting into Plastic SCM, for fair reasons, but Plastic doesn't have a UI as fun as Magit.
Genuinely what’s the big deal? I used Git as a frontend to a Subversion remote because that’s what “IT” had. Any decent Git contender (read: worthy early adopting) will have the same capability.
Right now both Git power users and Git anti-users (minimum care) cooperate on the same code. Some making fantastic Git histories (or yak shaving with rebase too hard) and some doing “backup for the dayy”.
Maybe one of them is even using Jujutsu behind the scenes. Who knows? Ahh, maybe that’s why he has forgotten that one switch to git-rebase that you need two times a quarter.
You don’t need any momentum or organization backing or people in your corner in order to start trying out a Git alternative.
Opinion on Darcs or Pijul?
I've used both quite a bit, first Sapling and then Jujutsu, and now I exclusively use Jujutsu and am one of the developers. I previously used Git almost every day for ~15 years. Frankly, I think you'll be very happy with either of them; they are pretty much straight upgrades from Git in most ways. Some notes (random, non-exhaustive):
Both of them are heavily Mercurial inspired; Sapling is a heavily evolved fork of Mercurial, while Jujutsu was strongly inspired by many of its concepts but shares no code (the two main developers, Yuya Nishihara and Martin von Zweigbergk, are former heavy hitting Mercurial developers.) They support features like revsets, filesets, have a notion of "changeset evolution" built into their internal models, and more.
These features actually make it possible to do things in an "open ended way" that would be difficult or not-possible to do in Git; something like finding all commits with 'description(foo) & author(aseipp)' for instance is not something I'm sure you can do in Git in a one-off way, as a counterexample to the "just run this command in Git to do that!" argument.
Both of them have a significantly simpler conceptual model because they replace concepts like "stashes" or "the staging area" with commits. To be clear: you can do all the things you like with Git, but with less conceptual overhead. There are fewer "nouns", and consequently fewer "verbs" you need to use and memorize.
They also don't tend to muddle a bunch of stuff together under one name; rebase is just rebase, not "rebase and edit commit message and reorder and throw away commits and merge commits and ..." like in Git. Or consider `git revert` and the dozen options that make it work on this-or-that. This and the previous point mean their UX is also much smaller than Git, a bit more clean and well separated, etc.
Jujutsu has an even further simplified model because it doesn't even have a concept of things like "the working copy." Everything is a commit. This has a large list of downstream consequences on things like performance (jj rebase is vastly more efficient than git rebase), internal design choices, etc but the takeaway is that you have an even simpler cognitive model. The flipside, I think, is that Jujutsu might take slightly longer to "internalize."
Both of them have the ability to expose the `.git` directory next to their own VCS directories (.sl and .jj) so your existing tools like showing status lines in the editor gutter can work. Jujutsu calls this "colocation", and Sapling calls it "dotgit" mode. Sapling's "dotgit" mode is still experimental; Jujutsu's colocation mode is well supported, and likely to become the default in the near future.
Both of them have 'undo' commands. Imagine that! A command that can undo your mistakes! Users are almost always universally filled with joy when they discover this feature.
Both make workflows like stacking or rebasing a lot easier, conceptually, so you will probably be happier with either. Sapling has ReviewStack so you can do stacked reviews a bit more clearly on GitHub. For Jujutsu we don't integrate with ReviewStack, or Reviewable/Graphite (yet), so you are still at the mercy of Github's review tools, which are a bit weak when it comes to interdiffs/stacked PRs.
Sapling has a command called "interactive sapling" or "isl" which is a web-browser based GUI that you can use to drag and drop, reorganize, split, restack commits with ease. isl is an incredible tool, it is easy to use even for newcomers, and I consider it a major advantage over Jujutsu!
Jujutsu has the notion of "first class conflicts" which make most forms of conflict resolution far easier. It's a bit difficult to explain but think of `git rerere` combined with `git rebase --update-refs`, but on steroids. I consider this to be a major advantage over Sapling.
Sapling is the VCS of choice at Meta, and they are working on making the scalable server-side components available too. Jujutsu is designated to (hopefully) become the true successor to 'fig' at Google, which I suspect you're familiar with. Maybe this matters to you as a former Googler, but maybe not. (Note: I do not and have never worked at Google, but Martin does and is the leader of this effort.)
Jujutsu actually exposes a set of APIs so you could in theory use it with other backends; that is how the Piper/CitC integration at Google works, and people have floated ideas like a Mercurial backend, for instance. In theory it is extensible, but this might not matter to you.
Jujutsu is a pure Rust codebase, having been written from scratch, while Sapling has a much longer history; it is a mix of Python and Rust. I personally think this makes it much easier to contribute to Jujutsu, and it was one of the reasons I switched because I personally tend to write patches for tools I use. OTOH, Sapling is much more refined in some ways. It is up to you if you think this matters.
Compatibility-wise, I believe Sapling uses `git` commands underneath to drive a lot of its features, while Jujutsu instead uses libgit2/gitoxide for interop. IMO, libgit2 has caused us and users a few issues long-tail issues that are hard to resolve; things like Git Credential Manager or OpenSSH config support for instance don't work as well with libgit2, which causes annoying bugs. Other features like partial clones don't work (shallow clones do.) You can just use `git` commands to work around this, typically, but I think Sapling might handle some of these quite a bit better.
In short, I think you'll probably be happy with either of them. If you have any questions about Jujutsu at least, you can open them on GitHub, Discord, IRC, etc.
It sounds so nice! Sadly, $work uses git LFS, so neither is a possibility for me.
I learnt Sapling while at Meta. I was skeptical when someone said "it's better than git" but then I used it and I will in turn now say that it's indeed better than git. At the very least it doesn't yell at you for not being on a branch and losing code, but it has easy commands for working with a source tree and working with diff stacks. I haven't used it outside Meta's infrastructure though.
Shameless self-promotion: https://pypi.org/project/stacksmith/
Can you say something about it rather than just dumping the link? :)
> Having worked at Google I have unfortunately been exposed to what is possible when in comes to version control systems.
Do you also drink your tea by sticking your pinky out?