Ask HN: Git Alternatives – Sapling vs. Jj
94 points| koch | 1 year ago
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
IshKebab|1 year ago
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.
aseipp|1 year ago
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.
WorldMaker|1 year ago
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".
Zambyte|1 year ago
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.
neongreen|1 year ago
(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.
jkachmar|1 year ago
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...
mk12|1 year ago
eawgewag|1 year ago
The only thing I reach for for git now is `bisect` when I need to debug an oncall issue.
Zambyte|1 year ago
bsimpson|1 year ago
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.
ghjfrdghibt|1 year ago
hinkley|1 year ago
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.
keybored|1 year ago
barlog|1 year ago
ksec|1 year ago
dijit|1 year ago
Or… it was just resubmitted.
OJFord|1 year ago
mhh__|1 year ago
riwsky|1 year ago
riedel|1 year ago
xrd|1 year ago
ibejoeb|1 year ago
rk06|1 year ago
eawgewag|1 year ago
Lanedo|1 year ago
https://github.com/tim-janik/jj-fzf?tab=readme-ov-file#split...
(Another self-promotion)
drcongo|1 year ago
Edit: Here's that sub-thread: https://news.ycombinator.com/item?id=42112574
HALtheWise|1 year ago
https://github.com/Skydio/revup
arxanas|1 year ago
SatvikBeri|1 year ago
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.
EddieRingle|1 year ago
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?
aseipp|1 year ago
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!
lawn|1 year ago
Yeah they're doing that.
Flux159|1 year ago
The only major limitation for me is git-lfs support so for certain repos I have to revert to git.
brudgers|1 year ago
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.
aseipp|1 year ago
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.)
Conscat|1 year ago
keybored|1 year ago
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.
johnisgood|1 year ago
aseipp|1 year ago
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.
lostdog|1 year ago
optymizer|1 year ago
findjashua|1 year ago
remram|1 year ago
keybored|1 year ago
Do you also drink your tea by sticking your pinky out?