Sapling: A new source control system with Git-compatible client(engineering.fb.com) |
Sapling: A new source control system with Git-compatible client(engineering.fb.com) |
I think the design of GIT still is a big risk for commercial companies.
I for one will remain skeptical. If they release it as free software, we can talk. Probably real innovation will happen elsewhere though, without the FB flavour to chew on.
Rust and C? that sounds like it is a pain to build, especially on Windows.
Ah, dammit
Flow[1]: JavaScript typing system from Facebook. My company uses it, open development has since been halted by Facebook so we're effectively on abandonware.
EDIT: React: Javascript framework from Facebook, my company uses it, and while it has its warts it works pretty well all things considered and Facebook has continued to support and evolve it over time!
For all I know Sapling is fantastic and will be developed for years to come. But personally I can't help but feel "once burnt, twice shy" (or in this case, twice burnt once shy). I'd be happy to be wrong here because ergonomics of Git are really frustrating in many places.
0: https://www.phacility.com/phabricator/ 1: https://flow.org/
Your thought process is completely fair, but just to clarify: Phabricator was never open-sourced by Facebook. The main engineer behind Phabricator (Evan Priestley) left Facebook to create Phacility and open-source Phabricator; that was never a Facebook product.
If memory serves, Evan open sourced Phabricator at Facebook back in 2010 or 2011, then quit to work on it full time.
Shortly after (months, years?) the internal version of Phabricator diverged from the now not FB managed or stewarded OSS one.
However I think it is fair to say, assuming my memory is correct, that Phabricator was open sourced by Facebook at a very different time, before the company really committed to supporting open source projects. At that time it was more ‘if an individual engineer wanted to then go for it’ rather than there being any formal process or consideration of longer term commitments.
That changed fairly shortly afterwards with the creation of the OSS team.
I remember someone transitioning to the newly formed team and moving from Dublin to London to do so in ~2012, as we became housemates :)
React[0]: JavaScript front-end web framework from Facebook. For good or ill, the most widely-used web framework in the world.
Not to say that Facebook will maintain Sapling, but React does stand as proof that they're not incapable of carrying an open source project to the finish line.
Overall, I'm glad they do these things, though since it is better to have this code accessible than absent. Good on them!
I am a git hater myself. I mean, git just sucks. It always did, and it always was much worse than Mercurial. When they could have be seen as competition, I was forcing Mercurial as much, as I could, but then GitHub became a thing, and after a very short struggle it became just hopeless. There still are folks who use fossil or something, but ultimately git became THE SCM. So, yeah, I hate you, GitHub, I hate you, Linus, but I fully admit that you've won. So… now I can actually admit it isn't such a big deal.
Sure, it would be somewhat better if git never existed at all and we'd all just use a better SCM from the very beginning. But given it's just not the case, what it the problem, really? It isn't hard to learn git. I do know some people who are struggling with anything outside of simple pull-branch-add-commit-push workflow (usually performed via buttons in their IDE), but, honestly, I think they will be struggling with any other SCM just as much — it's just the difference between caring to build a mental model of the tool you use, and simply memorizing a number of popular commands. The tool isn't at fault here. So, really, git is kinda bad, but not that bad.
Monorepos? I mean, there were tools to work with them before, but does anyone outside of Google/FB actually work with repos that git cannot handle? Is it really a good idea to have such repos? I mean, it's nice that some tool can work with them, but is it actually important?
I mean, there is some new "better" SCM (often somewhat git-compatible) almost every year. But I've never actually seen anything that would make me push for that "better" SCM anywhere. Even for my personal projects. Git isn't "just git" anymore, there are countless tools that integrate with it, we all know it by heart and have sets of "best practices", how-to's, personal workflows, helper-scripts, etc. There is a huge downside to start using anything besides git, so what is the upside that would compensate for it? I never see one.
> First things first, please go to your phone and turn off wifi to avoid voter ring detection and upvote us on Hacker News!
/s :)
There are projects, like Apache Hadoop, that are open-sourced because they're an open-source answer to an extremely powerful, successful, commercial product. Sapling is nothing like this. The reason it's being open-sourced is because Meta considers it tech debt and I'm not surprised.
Google did exactly the same thing, but hasn't open-sourced their tools.
Projects to drive incremental productivity make not a lot of sense for small companies, but become immensely valuable at very large companies. A 1% improvement if you have an engineering staff of even just 10k is worth 100 engineers, and FB is much larger than 10k.
FB and Google started with infinite money spigots and used it to hire a lot of people who make a lot of commits; if you laid them off, or if you canceled half the remaining Google products they haven't already canceled, not all that much would change.
Under the circumstance that no existing source control system can handle a monorepo as large as Google's or FB's. The custom source control system is not a hobby. It is vital to both companies.
I understand the sentiment and my suspicion is similar. Do you have a source?
How does sapling solve that? It can't...
IMHO Sapling looks like "Git for dummies". And Git teaches some pretty useful concepts, which are worth it.
The only reason which may make merge conflicts happen slightly more often in monorepo (vs constellation of small repos) is that not having the repo cloned locally is an obstacle to make the change. So some folks won't bother contributing repo that they'd have to clone first and instead they'd file a bug to the owners.
Many companies/organizations won't hit the size/scale where this matters but there are certainly plenty of companies who have large repositories and contributors that would benefit from something like Sapling over Git/Mercurial. These tools start to become slow. Many addons have been created to ease the problem (LFS or Microsoft's VFSforGit, narrow/shallow checkouts, etc.) but they also add complications (LFS especially in my experience). Monorepos have their advantages [1], and even with disadvantages they exist and won't go away. It's more appealing to migrate a monorepo to a new tool that adds more benefits specific to monorepos than to break apart a monorepo into separate repos.
The architecture that's being moved into seems to be less decentralized which is what Git/Mercurial were initially pioneering. I believe Google has essentially also built their own server-side SCM [2] and made Git/Mercurial clients (or wrappers for a client). I believe Microsoft did something similar forking Git and/or making their own server-side SCM but I don't recall where I came across that.
[0] https://engineering.fb.com/2014/01/07/core-data/scaling-merc...
[1] https://trunkbaseddevelopment.com/monorepos/
[2] https://www.quora.com/Why-do-Google-employees-use-Piper-inst...
Bash has weird defaults so you end up googling for everything. In fish, it just works and you barely need to search for anything.
Sane defaults matter. With hg, I don't need to struggle to get it to do what I want, it just gets out of the way. With git, sure it works but like you said it has a bunch of ducktaped tools together that change the defaults or just generally make things easier.
Now hg is half the pattern here. The other half is stacked commits. Each commit should build and get reviewed separately. There isn't any waiting for reviews on each commit, they all get reviewed over time and you rebase any changes that are requested. With git this is amazingly painful and half my zshrc is about making this simple. With hg, it just works. Take a look at hg absorb or hg split, theyre features built on top that yeah can replicated in zsh scripts but its kind of nice when you can assume they just work. It means junior engineers don't spend hours trying to fight git with stacked diffs.
Sapling is trying to fight the network effect here by doing the classic built a compatible but legitly better front end. Compatible with github but sane defaults is a BIG thing.
I keep having to google the location of my configuration file. It's ~/.config/fish/config.fish. I think, if it's not in ~/.local.
The whole function thing is also not the easiest to understand, although I love that it hot reloads and is global across all instances and so on, along with all sorts of other things.
Overall fish is one of my favorite shells but it's not 100% intuitive at first.
> left Facebook in April [2011], and shortly after, we open sourced Phabricator
Although if Evan had access to the codebase after he was an employee and if it was the Facebook codebase that was open sourced then Facebook were involved. The original post sounded (to me) like the OSS code wasn’t the same as the FB code.
I think that just backs up my point that it was the Wild West back then in terms of individual decision making.
I have a hard time understanding the benefit of using a language that’s almost like a very popular one, but not quite.
But the implementation has a lot of drawbacks - the language is painful, typing is bolted-on and still incomplete after years of work (eg there are no typed arrays), the standard library is an inconsistent mess thanks to its origins of “take several other language’s standard libraries and duct-tape them together”, etc.
I agree that the Git commands are pretty primitive (aka low-level). But eventually you can learn the good patterns and deal with that.
For me, the big question is how to manage a monorepo (with zillion of branches) so you can express which set of branches are relevant to your current concern at time T:
- focusing on the dev of a given set of features,
- frozing them into a delivery,
- pushing a stable monorepo+that frozen delivery to your validation platform,
- once validated, integrating that frozen delivery to one of the master branches of the monorepo,
- management of the many master branches corresponding to each subparts of the monorepo into a supermaster branch
Does this tool (or Mercurial in general) help with all that mono-repository branch management ?
To your question about what/how Mercurial helps I'm guessing it's related to this, or other workflows enabled by Mercurial's Evolve/Topic features. It sounds like Sapling has adopted Evolve/Topics and making them functional on Git repositories though I'm not sure what it's doing under the hood.
I'd really like to see a DCVS with better signing support and with some form of access control (on the remote), so every change can be traced back to the author, and so that some parts of a repo can only be modified by specific authors. Git hooks (on the remote) can sort of achieve the latter, but it's a bit of a pain.
In Pijul, patch authors are public keys and patches are signed by default. The link with an author's identity is done outside of the patches to allow for changes in name or email address.
Edit: I'm not saying there's not a better way, just that I don't understand the problem with git.
sl help signHow I think that will happen is using CRDTs against an AST to remove most merge conflicts.
I especially like the idea of stack. It's not something git can't do, but someone should've spent quite some time on tons of trial-and-error to nail the workflow. It's certainly a well aged project - a decade old! Kudos to that.
Whatever is to come of my cute animations!
[Think of the trains!](https://github.com/mtoyoda/sl)
Git's major value proposition is that they added moving parts until the system worked great. If you don't want named branches, staging, or any other piece of the ideology, then subversion is a fine choice.
But most folks moved on from svn for reasons
Moving from SVN to git felt like liberation because there were suddenly idiomatic ways of expressing states that were sort of smushed together by SVN -- stuff like, "I have some changes in my branch I want to line up for commit" which, became the handy one-word concept, "staging".
The before-times were marked by a lack of these fine distinctions. While they existed in fact, they were obscured in-system.
Like a map, any tool should 'resemble' the sphere of human activity it potentiates, and git resembles our diverse workflows better because it has so many asinine distinctions.
This was always its strength, and indeed, likely the reason the platform is called 'git' in the first place, as 'smarmy git' (English idiom for 'smartass') implies an insufferable drawer-of-distinctions.
And like a smarmy git, it's easier to complain about git than it is to replace it.
Was bulk of the team behind this laid off wherein it made sense to open source it to involve the community to take it forward rather than paid resources?
To be clear: I'm NOT criticizing them open sourcing this.
The team working on Sapling has been planning this release for a very long time and will continue working on Sapling to support our internal engineering efforts.
Sorry, I just can't take an "open-source" project seriously that uses "we hope to open-source these in the future" in its pitch.
Or is it a new DVCS, with its own repo type, for which I can use the git client for?
I don't actually want "No" staging area.
What I want is, once I "add" something, the file stays added.
Currently, I have `git st` alias setup :
st = !git add -u && git status
This auto-updates the staging area for files that were previously staged.So I get `git add` but also don't have to re-add anything manually from there ...
Since I do `git st` quite frequently, this works out for me ...
No joke, this might solve every major pain point I've had in mid-size-to-large teams in both the FOSS and proprietary world if it can deliver on what it says here, not to mention many issues with monorepo migration, work sharing, subproject management, etc. Many of these problems are very real but mostly ignored or we've decided to live with them.
Git is great, I'm one of the earliest GitHub users there is. I was also an early user of Darcs (which formed the theoretical basis for later competitors like Pijul -- so I'm not unfamiliar with radically different approaches), have a lot of experience with all kinds of administrative Git tasks for large repos; there's still plenty of room to fill gaps with new blood.
Nobody is trying to replace git; that’s not a stated goal. Plus git is so entrenched, it’s not going anywhere anytime soon.
However, few companies have more gigantic code bases than Facebook, which not that long ago, had their entire monorepo [1] in Mercurial, which had certain advantages over Git at the time.
So if there’s an organization that knows the pinpoints of version control, I’d put Facebook on that list. They’ve been working on approving version control at scale for more than 8 years.
As long as it’s git-compatible, the git true believers will have nothing to worry about.
[1]: https://engineering.fb.com/2014/01/07/core-data/scaling-merc...
People are SUPER over dealing with using Git on large repos.
Did it? I think it had a short lived period of popularity when npm wasn't deterministic and is now mainly a novelty.
> React is.... ugh... React and it took over the whole dang industry.
Agreed there. But most people hadn't seen components before, they really were 10x better than MVC approach, even for all of React's complexity.
If you want that behaviour, you can just `git commit -a` when you create your commit, then you only have to "git add" brand new unknown files.
The reasons for that are:
1. In the vast majority of cases there are multiple files I want to commit together. Usually I change them multiple times during the process.
2. It almost always starts with some debugging in a couple of other files, and I often want to keep that debugging for a couple of next commits, but `git checkout HEAD` these files in the end.
3. For me, the most popular way of using git rebase → edit (which I do reasonably often) is splitting a commit into 2 by separating files. This is easy enough by just changing a status of a file from "staged" to "modified" (I even have `git unstage` alias for that) and commiting.
So I kinda get why GP wants what he wants. This isn't crazy.
Now, that being said, I personally have absolutely no problems with how git does that now: I've figured out a workflow that solves these problems for me, and everything is ok now. This workflow is basically making many dozens of tiny commits to a branch without even bothering to name them properly, and then just doing `git rebase -i` many-many times while working on a single branch. So I just commit the code I don't intend to keep with a label "drop that", and drop these commits when I'm done. And other commits usually are heavily reordered and squashed into 3-5 larger commits that make some sense on a higher level (like 500 LOC of refactoring first, and then 1 LOC of an actual bug-fix, which usually makes much more sense than just 500 LOC of a bugfix, that solve the problem somehow, but it's absolutely not obvious how exactly). I rarely can figure out that separation before I'm done. In fact, I often fix the problem first, then refactor, then roll-back the fix just to add it again in a separate commit in the end (if the refactoring and the fix affect the same file, which also is often the case).
git add -p
Allows you to select hunks of changes and stage them for committing...
There's nothing saying that one can't add chunks to the staging area and then immediately commit it without invoking that alias afterwards (since it is a very deliberate "add these things" rather than "adding a bunch of things and keep adding."
git commit -p achieves the same, but avoids explicitly using the staging area.
[0]: https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/
So I'm replying to OP's very specific usage pattern, and you object with a completely different usage pattern?
> `git commit -a` is basically an equivalent of having no staging.
GP doesn't use the staging as a staging, since they immediately stage all modified files. That means the staging is useless, they can just commit files straight from modified. Which is what `git commit -a` does.
> 1. In the vast majority of cases there are multiple files I want to commit together. Usually I change them multiple times during the process.
OK? `git commit -a` doesn't preclude that. You just use it instead of `git commit`.
> 2. It almost always starts with some debugging in a couple of other files, and I often want to keep that debugging for a couple of next commits, but `git checkout HEAD` these files in the end.
I'm really happy for you. It doesn't work when the files are already staged, which is the case of GP.
> 3. For me, the most popular way of using git rebase → edit (which I do reasonably often) is splitting a commit into 2 by separating files. This is easy enough by just changing a status of a file from "staged" to "modified" (I even have `git unstage` alias for that) and commiting.
https://sapling-scm.com/docs/commands/uncommit
> uncommit part or all of the current commit
You don't need a staging area to craft commits, you can manipulate the tip commit directly. With good enough support for that (which sapling seems to have inherited from mercurial), the staging is just an unnecessary pseudo-commit.
My first experience with git was using git-svn to work with my company's internal svn repository, which I did for a couple years before the company stopped using svn. There was no internal desire for decentralized version control (rather the opposite, in fact; they wanted centralized permission management and such).
There are many reasons why GitHub (or something like it) are popular, such as:
1) not having to host the infrastructure yourself (incl. hosting it on AWS/Azure/etc.)
2) discoverability -- being able to follow people/organizations creating projects you are interested in; being able to search for projects ~ having these on various websites makes it harder to discover them
3) additional functionality/capabilities like static web page hosting (great for things like personal projects), and CI/CD workflows
1. You could retroactively sign something with an expired key and rewrite history
2. The one doing the conflict resolution signs the whole merge commit, but didn't author the stuff they're signing.
2. That's the point though. The person doing the commit takes responsibility. The individual commits are still there before the merge (including signatures), so there's no loss of responsibility or credit before the merge.
When I say "not a CRDT" I'm obviously talking about HEAD not being a CRDT, a Git repo is append-only, so the history of a Git repo actually is a CRDT (but that's not what the comment above meant).
I imagine this will be settled by git steamrolling sapling in the market, but I wonder if there's a faster (and less network-effected) way to adjudicate? Both your position and mine seem lodged in a taste/touch/feel context, which seems like a data-poor place to make good decisions.
On the other hand, I'd say that absent sufficient data, one should pick the most flexible tool, which I'll bet in this context is the one with the most moving parts, i.e. git.
The findings validate the earlier conceptual design analysis in practically all aspects: https://gitless.com/#research
Git doesn't support certain workflows well. For example, how do you split the contents of the staging area into two separate groups? Sapling handles this the same way it handles splitting commits in general. Essentially, it has a greater set of verbs that act on a smaller set of nouns, where Git has a medium set of verbs that act on a medium set of nouns.
One of my favourite parts of rationality is simply admitting that the data shows you're wrong
What is the workflow behind this ask? I don't understand what the goal is. The basic git workflow:
1. Edit and save a tracked file; the changes appear in the working tree.
2. Select some subset of the changes in the working tree to stage them in the index.
3. Form a commit with the changes in the index.
IIUC you want to add a step in between 2 and 3? But the way I see it, 2 is doing what you want. I can split the set of current changes by selectively adding them to the index in preparation for a commit. I can also selectively un-stage changes if I decide I don't want them to become part of the commit.
Between the changes to a file in whatever editor buffer I'm writing in, saving those to disk, moving changes from unstaged to staged, and forming a commit in any of a variety of ways (plain ol' commit, amending a commit, a fixup commit) I can't imagine what other way I need to slice and dice changes. Maybe it's just a failure of my imagination since I've been using Git for so long now and only more basic things like SVN/TFS/CVS before that.
Outside of the Git fanboy bubble, developers don’t want to have to be version control experts, which once you get past a certain level of Git usage, you have to be, whether you wanted to or not.
Especially if your team doesn’t have that person who can get you out of any Git jam you may get yourself into.
It will also be much faster to get a new developer up to speed using Sapling than Git. And because it’s Git-compatible, if there’s something super advanced that can only be done using the Git command line, that’s still an option.
Telling the intern/junior developer to read the man page for git-log is a non-starter; it’s over 19,000 words!
The best thing for the greybeards is they can continue using Git while others use Sapling and commit to the same repo.
That said, I hear you when you say that most folks (think) they have better uses of their attention.
I daresay they're wrong, but it's not my place to dictate terms to anyone's curiosity, my own included!
SVN branches were this doofy copy procedure that made sense once you drank the Kool aid, but they were so unwieldy compared to git
It wouldn’t be that big a deal except pretty much every important git command is similarly complex for noobies.
Occasionally, I do run into the situation where I've staged some changes and then realize that I want to start staging another commit first, but don't want to lose the changed I already staged. Unstaging my current changes means I have to remember and select them again later. I could also just commit what I have staged and start staging a new commit (and perhaps reorder the commits later), but that shows that the staging area was unnecessary in the first place, and I could have used commits to accomplish the same workflow without adding a new set of concepts to my VCS.
... such as `git commit --patch`, which this discussion has taught me many people don't know about, even those who know about `git add --patch`.
(I was one such person a few years ago until my mind was blown by an HN commentor doing me the same favour as I have done here :) .)
Facebook used to be involved with the Mercurial community, but it was difficult to work with them. They always wanted to do things their way, had their own intentions, and started to demand that the Mercurial project work the way that Facebook wanted. For example, they demanded that we start using Phabricator and started slowly removing sequential revisions from Mercurial in favour of always using node hashes everywhere, arguing that for their gigantic repos, sequential revisions were so big as to be useless.
Eventually the disagreements were too great, and Facebook just stopped publicly talking about Mercurial.
I figured they would emerge a few years later with their fork of it. They love doing this. HipHop VM for PHP, Apache Hive, MyRock; these are examples of Facebook forking off their development in private and then later emerging with some thing they built on top of it.
The Mercurial project is surprisingly still chugging along, and there are still those of us who actually use Mercurial. I doubt I'll switch over to Sapling, because I disagreed with the things that made Facebook fork off in the first place. But if others like Sapling and this manages to put the slightest dent into the git monoculture, I'm happy for the change and innovation. I really hope that git is not the final word in version control. I want to see more ideas be spread and that people can see that there can be a world beyond git.
For example, I use Mercurial’s absorb command [1] and was pleased to see it in Sapling.
Overall this looks promising.
[1]: https://gregoryszorc.com/blog/2018/11/05/absorbing-commit-ch...
Hard to discover and remember but once you do it usually works smoothly.
https://lobste.rs/s/nws1uj/help_us_name_new_mercurial_featur...
Yes, I read the manual for git, but I never needed to for Mercurial.
I wish it had won the DVCS wars.
Git is a twisty maze of operations combined under poor names (e.g. git reset) with dozens of obscure options (e.g. man git-log) and broken abstractions (e.g. what is HEAD and why does Git emit a warning whenever I check out a tag?). I often feel so sad that the entire software industry has fallen to Stockholm syndrome under Git — we think these contortions are normal, when in fact they are arcane.
> The Sapling CLI, sl, was originally based on Mercurial, and shares various aspects of the UI and features of Mercurial.
common problem in open source. any project that gets big enough effectively stops anyone from wanting to work on an alternative, or use an alternative, due to the momentum of the large project.
deviating from it makes it harder to collaborate or be productive because the big project does everything (though often poorly), everyone knows it already, and no one wants to learn something new, and no one wants to work with the people using the weird thing.
same reason why it's hard to make a Facebook alternative.
Things really became one-sided after github started gamifying open-source contributions, and when a new generation who perhaps grew-up in a more competitive academic setting took it as an opportunity to make their resume more impressive.
We peer-pressured ourselves into collectively using a less-than-ideal tech because that was the price to pay to belong.
Seems to be a recurring pattern when people interact with open source communities. Why does it have to be like this? It's not just companies either...
Because motivated, high performing people need to have control over their own destiny. Because cookie-cutter solutions which work for 90% of use cases are often worse than something explicitly tuned for you.
People having specific needs, getting frustrated and then solving their problem is a feature of opensource code. Its not a bug. It is the engine of innovation and improvement. Forking means we can both get what we want, even if our needs are contradictory or we don't want to work together.
This happens with commercial offerings too - but its a mess. You can't just fork the code without paying (or sometimes at all). And every fork is private, so work is duplicated and collective learning doesn't happen. Expensive consulting-ware might be the best case outcome.
The ability of motivated people to fork projects and have their own spin on things is one of the biggest strengths of opensource. May the best forks win.
I'm certainly in that camp; and it pains me every time I have to use the hggit extension to convert a mercurial repo to git in order to work with everyone else...
Could you elaborate on what these things are and why you disagree with them?
I have been waiting ten years (https://www.google.com/url?q=https://stevebennett.me/2012/02...) for someone to develop a better CLI for git, someone with the scale and clout to do it well and gain mindshare. It's not that useful to learn a new workflow if no one you ever work with will be familiar with it.
This looks incredible. A simple command to uncommit or unamend makes you further realise what a disaster the Git CLI is.
Sure, most people are probably fine with Git once they learned it and if they only work with small to mid sized code bases (like me). But I'm still happy Sapling is out there, I might use it or learn from it if I ever run into the problems it solves.
- It's too hard to scale for a large monorepo!
- Google does it just fine!
- But I don't have access to Google's tools!
So kudos to Meta for both solving the problem and making it available to others. It will be interesting to see how useable it is outside of Meta. I know for example that while Netflix open sourced a lot of tools, most of them weren't useable unless you ran all of them together. So far Meta has been good at avoiding that, so hopefully that remains the case.
How does sapling let me take a long list of commits and break them into larger but more manageable chunks?
git add -p allows me to add chunks easily and create commits, git commit --fixup allows me to mark a commit as fixing a previous commit, and with git rebase -i --autosquash I get to easily take those fixup commits and meld them into the previous commits.
Also reviewing a stack of patches is annoying in many cases as I care more about the end result vs each individual commit. But that may just be my experience talking in open source where I am working on smaller but better well defined projects vs a large mono-repo where there may be a lot of changes across many disparate parts of the code base that make it difficult to look at the "whole" vs a patch that is more localized.
Its design is inspired by Sapling, and, in fact, it uses some of the same code, such as the segmented changelog implementation. Possibly some of its ideas made their way back to Meta, such as interactive undo?
Jujutsu also supports colocated Git repositories: https://github.com/martinvonz/jj. It also has the working-copy-as-a-commit idea and conflicts are stored in commits (so rebases always succeed). I think it's a step forward compared to git/hg/sl.
https://www.mercurial-scm.org/repo/hg/graph/tip
, seems to have been included since 2005 :)
Yes, this would be awesome for Mercurial.
...until I got to pull requests (Granted, that is github, not git). But it looks like you cannot generate a standard pull request with it.
https://sapling-scm.com/docs/git/intro#pull-requests
Haven’t tried it yet, looking forward to it.
Of course, when it comes to github PRs, there are so many different "styles" of pull request, I'm not even sure which one should be considered "standard".
(a) People arguing git is fine, and shouldn't be simplified
(b) People arguing about the right way to use git, and flame wars about best git workflows
I mean most people simply see (b) and conclude "this is a huge hassle, I don't want to annoy some git-workflow-purist, I'm just going to walk on eggshells on this tool and hope I don't break anything"
It's as much a social problem around conventions, and lack of opinions in the tool itself, then anything about the underlying technology (which is rock solid IMO)
absorb split histedit uncommit unamend revert metaedit
Once you use them, it's hard to go back.
It's also easy to commit / amend part of your work by selecting the lines to include in nice curses interface (--interactive).
I still commit small, frequent. But i like `git add -p` to skip debug lines, hardcoded conditions, etc. I don't want to mistakenly auto commit a whole pile of lines and then have to remove debugs/hacks/etc from things i've committed.
Stage + Unstaged is my working area, and the two live together quite nicely to me personally. I could live without it, definitely.. but i'm not sure i'd want to.
I don't care for an interactive tool, IMHO I prefer using commands that are repeatable and learnable instead of stepping through some interactive workflow all the time.
Is the branch-tip simply the staging area? What if you're only half-done with that final commit?
The fact that they have concepts like unamend suggests that they have thought about this in a way more turtles all the way down way than the Git designers. A versioning for your history changes—why, of course.
You can thank the Mercurial developers for these concepts.
However, I don't understand why I would want 1 PR per commit. I feel like that's a non-starter for me.
Is the idea that no one should use branches - so there's only 3 points of interest: HEAD, main, and origin/main? And then is the idea that it's only 1 commit per feature to merge?
So I would work on something, make a PR, continue working on something else without making any git checkouts and then make a new PR?
But you can certainly create new "branches" of development which aren't stacked on top of each other. They just don't have to have names. You can consider them to be "anonymous" branches.
The main advantage of 1 commit per PR is to review and commit smaller changes (a single commit at a time).
Doing this doesn't really make them good, but it makes them at least reviewable.
That's actually a deal breaker to me. Effectively using Git's staging area has become so integral to the way I work with repositories that I don't think I can ever go back to the old style.
The utility should obviously be called `sap' and not `sl'.
Non native here, could you explain? I know git is a slur and sap is the "tree blood", but are there other meanings I'm missing?
Stacked PRs are a blessing and a curse - still not convinced they are the correct way to build software as a team.
Obviously life is simpler if all your work is sufficiently non-intersecting that you can send separate diffs/PRs and e.g. rebase them separately, but if you have Big Feature X and you still want small, single thesis diffs, where else do you turn?
None of this makes any sense to me.
> Local branch names are optional.
As are they in git, just hang out with a detached HEAD.
> There is no staging area.
Practically the entire world sadly invokes `git commit -a` anyways and you still have to add untracked files.
Neat project but I don't get what this is solving for.
But this is mercurial. Or rather, it's mercurial rebased on top of the git data store, and it's a fork with breaking changes so it has a different name.
I do agree that the requirement to be online gives me pause. But I guess I don't know how much of a problem that would be in practice, since there's a mystery subset of functionality that works disconnected.
> Neat project but I don't get what this is solving for.
For us external people, it seems like it's mostly for using the hg interface with a github-hosted repo. The internal reason appears to be scalability to massive monorepos. Since I much prefer the hg interface to the git interface, I'm good with both of those motivations.
Same.
And the problems you describe aren't really relevant outside a monorepo or low-volume repositories, of which the vast majority of open source code falls in. I much prefer the ability to clone an entire repository and be able to make changes in a distributed manner.
If this is for companies who aspire to have Google or Meta scale problems then this sure is a weird way to advertise it.
$ sl clone https://github.com/facebook/sapling
$ cd sapling
$ sl
@ fafe18a24 23 minutes ago ricglz remote/main
│ migrate packer to new CLI framework
~
From [0] under "Cloning your first repo". I get the following: ~/sapling (main)> sl status
abort: '/full/path/sapling' is not inside a repository, but this command requires a repository!
(use 'cd' to go to a directory inside a repository and try again)
Hopefully this does not assume we are authenticating with GH just to clone and see sl operating?[0] https://sapling-scm.com/docs/introduction/getting-started/
I do wonder:
1) How it handles large (binary) files. This is a major pain point when using git and even the standard solution (git-lfs) leaves *a lot* to be desired.
2) How does server hosting currently work? I didn’t see any mention and am assuming it’s not an option currently? (two dependencies of Sapling are currently closed source)
So yes, in short I agree.
Put my stuff from the last commit back into working directory?
Very unintuitive (soft?) and I’ve just memorized this for the past 10 years.
just they build one for switch.
i hope they build a migrate one, where you can switch to new/other hashing standards.
(Disclaimer used to make VSCode)
Harder with an amend due to having to get the difference of commits within the reflog, sure.
...and yes, I realize it's weird to say this considering Google is known for abandoning things. Maybe it's just coincidence that I've run into more abandonware from FB than Google?
Better than Microsoft? I don't think I've ever been able to talk to a human at Google, whereas with Microsoft, I get feedback very quickly on issues and pull requests. Does Google even interact with people with open source? For example, I am using Skia via SkiaSharp, and the only place I know of to go for Skia help and issues is their Google Groups page, a website out of the 2000s. And very few seem to actually monitor the group. I'm not even really sure what Google does in open source. Even the things that are released to the public, like Skia, are well known to come with a huge amount of internal baggage.
Whereas Microsoft has dozens of active projects on GitHub where you can talk directly with the people working on it at Microsoft.
As far as I can tell, most of zstd's development is still by Facebook employees, though not all of it. I tend to think zstd has enough traction that development would continue even if FB were to abandon the project.
This is my naive understanding. A for profit company open sources a project that they have been using and developing internally. The have built a philosophy and understanding of the project as they use and develop it. Most of their action regarding the project is that they must use it and they usually don't have any other options.
Because the foundation is already laid the solution for its shortcoming is having just an understanding of them. Then you open source the project knowing that you have developed the project to it's completion.
Now comes the OSS community. Either we request features that goes against the project philosophy or we don't want to get involved because we don't need to compromise and acknowledge the shortcomings because we have options.
A good solution can be open sourcing projects that the org thinks isn't complete and needs further development without compromising security, philosophy and usability. Because if you have a list of things you need, you can ask the OSS community to fix those things rather then be critical of the foundation and philosophy.
Whatever is cool at Google IO XYWX is already abandoned by the time we reach into Google IO XYWX + 1.
If it comes to stuff I actually want to _use_, I avoid projects backed by a single or a few companies - like Sapling. So from that angle, I'm not particularly impressed either.
A few years ago they had a Virtual File System extension for Git. Now it's a public fork of Git that is intended for large repositories (several hundreds of GB). It adds a `git scalar` command, see https://github.com/microsoft/git/blob/HEAD/contrib/scalar/do...
Firstly, it's not "giant amounts of binaries" it's "a very small amount of binaries". A few GB is enough to cause significant problems.
Secondly, This _is_ an issue with git. If my project requires binary files, git should handle it. How should we handle logos in a mobile app, branding images on a website, audio files for background? That's before you get to the question of "how does a video game store the source version of a 100GB worth of compressed assets?"
I think another thing that matters is how you store branches/code under review. In Linux, each team/person has their own repo. The main "Linus" repo has mostly the finished code. In a company it is much more common for everyone to store their unfinished code centrally. Perhaps this also accounts for some increase in size.
To split a single commit, you can use `sl split`, which is quite difficult in Git. (I miss that feature in Git quite a lot.) You can also use the `sl absorb` command to automagically merge local changes into the previous patches where they seem to belong (roughly speaking, commute changes backwards until they would cause a merge conflict, but it's a little smarter about avoiding certain merge conflicts).
It sounds like I would need to:
- switch - amend the commit - restack? - switch back to the HEAD?
Fold based upon the documentation seems to move older commits into the current commit? vs the other way around? https://sapling-scm.com/docs/commands/fold
This doesn't seem analogous to git rebase --autosquash which merges the mixup into the old commit.
your workflow resembles mine so I'm in the obligation of mentioning https://github.com/jesseduffield/lazygit which allows you to stage individual lines among other features. https://www.youtube.com/watch?v=CPLdltN7wgE
Sure, but you can use `git commit -p` to get the same benefits without explicitly using the staging area.
I also use this workflow. Lots of detached HEAD mode, using the index to commit things piecemeal, then rebase as needed, until I'm finally done.
What do you mean? Can't you use Sapling in the same Git repository you normally use? The first sentence is "Sapling is a new Git-compatible source control client". Is there something they're not telling us?
EDIT: Looks like it calls out to the git executable occasionally (https://news.ycombinator.com/item?id=33615576) and presumably works on the git object model under the hood, but you can't use `git` on a repo checked out using `sl` nor vice versa. It's a stretch to call it Git-compatible but I guess not completely wrong.
EDIT2: Here's a good summary https://news.ycombinator.com/item?id=33617689
git-branchless is only an extension to Git, so it naturally operates in the Git repository. Jujutsu has a mode to create the `.jj` directory alongside the `.git` directory and co-locate them, which I find very convenient in practice. (Originally, Jujutsu only supported Git compatibility in the same way as Sapling, via pushes and pulls, but they added co-location later.)
> Looks like it calls out to the git executable occasionally
I believe Jujutsu never calls out to Git, and that all of its `jj git` interop commands are implemented via direct bindings to libgit2. This is less fragile in many ways, but it can also mean that `jj git` interop might be missing some new feature from Git. Fortunately, you can oftentimes just run the Git command directly in the repository when co-locating.
> presumably works on the git object model under the hood
There's no guarantee of this: the Mercurial (and therefore possibly Sapling?) revlog model is a little different from the Git object model, as I understand it. But it doesn't really matter, as long as it interoperates seamlessly. For now, I believe they do literally have a `.git` directory somewhere under the `.sl` directory, but they reserve the right to change that.
Sapling, on the other hand, has much better support very large repositories, since they've spent a lot of time on that over the years. We're going to copy some of Sapling's solutions to Jujutsu soon, since we're working on integrating it with Google's monorepo (slides: https://docs.google.com/presentation/d/1F8j9_UOOSGUN9MvHxPZX..., recording: https://youtu.be/bx_LGilOuE4).
Is this pushed to the remote when running as a git porcelain?
I use git begrudgingly because that’s where the world is, but I long for an improvement in this space.
Git has a lot of incidental complexity and unforced design problems, but the fact that it's inherently flexible is not one.
(c) Git is a disaster that has destroyed source control for 15+ years and the industry is unable to recover from due to Stockholm syndrome
It’s impossible to discuss source control without people coming out of the woodwork to shit on git. It doesn’t work right. It’s too hard. SVN was better. Mercurial should have won. Blah blah blah.
Git isn’t perfect. And the command line has improved (I don’t care much, I use a GUI).
But the number of people who seem to insist that because it doesn’t work for them or they don’t personally like it it’s horrible and everyone should abandon it is crazy.
And it makes trying to read/participate in discussions like this painful.
Is git sometimes obtuse? Sure, but it's fast and incredibly powerful. My everyday commands are easy to use, and if I need something special I go to the documentation - just like any other SCM.
I believe we actually only use clap for some side binaries, not for the main sl executable. We have a custom parser for that (https://github.com/facebook/sapling/tree/main/eden/scm/lib/c...), to match the preexisting hg parse behavior. Unfortunately I'm not familiar enough with clap or why we didn't go with clap in the first place to say what we would need to use clap for the main binary.
`abort: please use 'sl init --git .' for a better experience`
What's going on here? I couldn't find info in the `sl init --help --verbose` output or in the Sapling website.
I'll take a look at the help later to see what we're missing here.
My impression from the blog post is that I can use sapling and have everything "look" git-like from the remote repo's point of view.
In order to work with Git repositories is this essentially the Mercurial client using hg-git on a converted repo under the hood?
This does not use hg-git under the hood. Sapling's internal structure differs from Mercurial in substantial ways, and we've built some cleaner layering that allowed us to shim Git in under our storage layer. This also means that we read and write directly to the git repo, instead of duplicating and importing all the data like hg-git did. This has some nice benefits, like the hashes you see in the output are actually Git hashes.
I'd be curious about your use case, since we don't actually use hooks internally all that much.
https://sapling-scm.com/docs/introduction/installation/#maco...
The "download via curl and then install with homebrew" method struck me as unusual
Were there problems getting Homebrew bottle building/publishing work as you needed?
One example we mention in the blog post is that when you push, it doesn't actually need to be a fast-foward push (using Git terminology) to succeed. Our server can rebase the commit on top of the destination bookmark for you (with some limitations, like not merging file contents). This allows many people to push, and not have to race to rebase. Then we have substantial optimizations around the critical section of final-rebase-then-move-branch-forward, which yields pretty good throughput.
AFAICT there are only two workflows involving the staging area: staging partial commits and resolving conflicts. The first case is taken care of by partial commit support, and the second case presumably has its own dedicated mechanism.
* get the hash of the HEAD commit * run `git diff <hash>` and see that there are no changes * make some change to a file * run `git diff <hash>` again and see the change you made * stage the change with `git add` * run `git diff <hash>` again and no changes are show! * commit the change * run `git diff <hash>` again and the changes are back
It's super bizarre to me that there would be some sort of intermediate state where changes aren't visible. I feel like it would make more sense to have some sort of formatting difference indicating unstaged versus staged but not committed versus committed, but I imagine changing that now would break all sorts of scripts, so we're stuck with it.
edit: yep, so long git
check if a given commit is included in a bookmarked release:
sl log -r "a21ccf and ancestor(release_1.9)"Phases are a property of revisions that essentially let you know their state. By default, there are three phases: public, draft, and secret. You can't rebase a public revision, nor can you have a public revision with a secret parent. So you get out of this concept things like safe rebasing, or barriers that let you keep internal and external repos separate.
But revsets really shine. This is basically a full-on query language for revisions. So you can define a query alias "wip" that specifies all of the, well, interesting revisions: every revision that is not in the public phase (i.e., not in the upstream repo), the tip of the trunk, the current revision, and sufficient ancestor information of these revisions that you can see where you based all of these WIP branches on. In a single query: "(parents(not public()) or not public() or . or head())".
Sure, composing revsets is definitely a somewhat painful process... but it's possible to describe more or less arbitrary sets with a Mercurial revset, and I've never been able to find a similar workable setup in git.
you can always just use another commit as a staging area, I figure, and it'll make all the commands simpler and more intuitive so it wins in my book.
And than you have to do gymnastics with rebasing and rewriting history afterwards. Using the staging area upfront is much simpler!
We develop HighFlux[1] which also gets rid of the staging area. It simplifies your mental model of what's going on a lot.
Because everything you save is automatically committed, switching to a different task/branch is also always instant without needing stash.
Because what you're testing locally is what you're committing, I also never have CI failures anymore (with the staging area I frequently had unexpected interactions with unstaged changes and sometimes even accidentally forgotten added files).
Sorry, but no. "No staging area" is what VCSes were like before Git and it was worse, much worse.
Rebasing, cheery-picking, or reverting of commits becomes impossible when every save of a file is pushed.
You could just publish local IDE history… Would be equally "good" I think. (My IDE is saving files every few key strokes btw; the resulting history would be a bloody mess).
Why not go one step farther: Just make an automatic block image of the whole systems of every developer machine every few seconds. You could than just deliver the image. No docker setup needed any more. Just write code. And when the local version works, ship the whole local system just as it is. ;-)
Will try `git-absorb`.
hg init
instead of git init --bare
does not matter to much..In git, with `git commit --patch`
Occasionally one takes off. Really just a function of how many friends the author has, their stature in "the community" and/or their aptitude for creating cute marketable landing pages.
There is a multitude of people capable of jumping in with hot takes explaining why the new framework is superior/inferior, tweets, blog posts, courses, books and conferences abound..
In contrast re-inventing git is hard. Few people can wax poetic about the differences between alternatives. Even fewer can come up with a new one. The audience is far smaller not to mention skeptical. Less profit in it.
Rather the difference between a new age cult/mega-church and the Catholic church.
But with Git, every conversation about improving the CLI has 50% of the participants claiming that the other 50% are just too stupid to use it, and that the CLI is brilliant.
> I'm not even really sure what Google does in open source.
Kubernetes (and a bunch of the offshoots), golang, a bunch of ML things, etc. It's just that many have independent foundations (CNCF) running them now to keep project management independent from a single company.
Idea for projects not owned by mega-corps (half real, half fantasy):
1. Get the project added as a package to one or more major commercial Linux distros, e.g., RedHat, etc.
2. Grant commit access to one or more devs at the same Linux vendor. Allow them to do whatever they want. You might not like their direction, but it should survive.
3. Retire from the project whenever you like.
4. Also, you could post a note in README about retiring. If people want to add features, ask them to fork, or just grant them commit access and let them go wild.
The Sapling support for remote repositories was a little rough in my opinion. Jujutsu and git-branchless can both co-locate with the Git repository, so you can always drop down to Git commands if there's something you're having trouble doing. (I find the `jj git` commands to also be better at interacting with remotes for now.)
Other commands useful for amending changes to previous commits:
* `sl goto --merge <hash>` - if theres no conflicts you can just switch commits with pending changes and those pending changes would be applied on top of other commit. If there are conflicts this command would fail https://sapling-scm.com/docs/commands/goto
* `sl absorb` - this automagically finds the last commit that touched the lines that are pending and amends that commit with them https://sapling-scm.com/docs/commands/absorb
If you want to run tests on commits without checking them out, you might want to try my `git test` command: https://github.com/arxanas/git-branchless/discussions/643
You can use `sl fold --exact` to combine arbitrary commits without including the current one. (To be honest, I just always used `sl histedit`.)
https://github.com/keis/git-fixup
git-fixup will add fixup! commits, so it still needs the mentioned 'git rebase -i --autosquash' afterwards. Usually you do not even need to give it a specific commit if your branch is set to track an upstream branch.
> This looks incredible. A simple command to uncommit or unamend makes you further realise what a disaster the Git CLI is.
I said that simple command already exists in VS Code. Yes it can be done via CLI, but not as simply as in VS Code. Not sure what your claim is.
I... what? Do you have a source or speculating to create fear of future support?
I'm nearly certain this is untrue.
A bit like submodules, LFS has its own warts that seem to multiply when you add more people to the mix. Working with git LFS has been the _only_ time the solution to my problem has been "nuke and clone again", in almost 15 years using source control.
Last time I used git LFS, it didn't support ssh cloning at all, and the issue had been open for years at that time.
usually to run linters and validators, speeding up the feedback loop (otherwise it's annoying to push changes to a PR and then get a CI failure minutes later for trivial linting issue)
Just to finish up, most of Mercurial has been rewritten in Rust, although the Python version is still the default install.
(My other two posts in this thread are -4 and +7 although they both have the same point. Never sure how to interpret that.)
If developing has some loop like "consider -> implement -> evaluate", then the quicker you can implement it, the more budget you have for considering the problem.
Personally, my workflow is to make many changes, then use `add -p` and `commit` to create a series of small commits. While staging, you might decide that you don't want to commit some bit of code and `restore -p` to toss it away.
I think your workflow would work well if you see commits as "development checkpoints" rather than semantic patches. It's not an invalid workflow, just a different one.
I'm sure you could configure VSC to be analogously ergonomic for any git workflow. But people who are comfortable with git and their shell of choice tend to develop comfortable workflows in the terminal as well.
It's a little slower than "add -p" but serviceable. Having editable diff in the diff view is really nice though.
I believe Yann Collet, author of lz4, eventually went on to work for Facebook and finished it there.
Oh, I was referring to Sapling. I know even less about Jujutsu than I do about Sapling!
> > presumably works on the git object model under the hood > > There's no guarantee of this ... but they reserve the right to change that
Interesting. So it would translate between them whenever you push to or pull from a Git repo?
I'm very keen to use Sapling if it's basically a polished interface to Git but less keen if it's an entirely different object model, because then I'm going to have to learn more about what's going on under the hood to understand it properly.
I was just remarking about Jujutsu, in the case that it was important to you for some reason whether or not your VCS called out to Git.
> Interesting. So it would translate between them whenever you push to or pull from a Git repo?
To be honest, I don't know. I suspect that, for now, they store real Git objects, rather than translating on the fly. You'd have to ask a Sapling maintainer.
> I'm very keen to use Sapling if it's basically a polished interface to Git but less keen if it's an entirely different object model, because then I'm going to have to learn more about what's going on under the hood to understand it properly.
I might have muddled some layers of abstraction and brought up something unhelpful. Git's object database and Mercurial's revlog are more comparable in terms of where they lie in the abstraction hierarchy, but these are just the storage layers. In practice, I find the Git and Mercurial object models, as exposed to the user, to be similar enough that I pretty much never have to worry about the differences. (Well, perhaps it's true that Mercurial file contents are not addressed by blob hashes, but do I ever really want to address by "blob hash", or just by "the contents of this file at this commit"?)
What I meant to emphasize is that you can't directly use Git to access Mercurial/Sapling's internal object store, if that's important to you (perhaps for scripting). In comparison, with Jujutsu, if you modify the Git object store on disk, it will try to "import" refs the next time you invoke it in order to update its own internal object store to match.
Improved UX is nice and all, but why would anyone migrate without getting killer performance features like the virtual file system?
We think, and many of our internal users agree, that the UX alone is a worth while upgrade. Since the majority of Git repos don't actually need the performance of a virtual filesystem, the UX is the main sell for them anyway. At the very least maybe it will inspire some UX improvements in Git.
It's a pet peeve of mine folks that use python subprocess as a replacement for bash because it takes special discipline to not eat stdout and stderr, or to correctly try:finally: to show the Proc details before the raise eats the variable
That's completely made up on your end. I've been doing FOSS for 17 years and the vast majority of people were barely competent with any of them at all beyond whatever their chosen ponyshow was (including off-brand ones like Darcs and Monotone), and any switching from a persons preferred one to the use of another project was often met with grunting and complaining, if it was done at all.
The reality is we only think this because we saw people do this, at great cost of their own time -- but that's the literal definition of survivalship bias. For every 1 person doing this 50 just stuck with whatever they used and wouldn't bother. I've literally seen people refuse to contribute to a project over tabs vs spaces, and people still do this with git vs hg today, just not as much today.
More people use Git and contribute to FOSS in a single day in 2022 than every developer who knew all these tools combined back in 2008 or whatever. Whether this is good or bad is up to you, but you don't need to make up claims about developers being epic journeymen in the past and mastering 50 version control tools to do a single days work. They did not.
> Things really became one-sided after github started gamifying open-source contributions, and when a new generation who perhaps grew-up in a more competitive academic setting took it as an opportunity to make their resume more impressive.
Sorry, but I consider this to be a similarly made up claim that's just sour grapes. I've been using GitHub since 2008, I'm one of the first users. GitHub didn't even have "gamified" social features until the past 3-4 years IME (what, stars are about it?), and before that its product was pretty poor in some key areas like code review and project management, org permissions, on-prem control, etc. I didn't even use GitHub commercially until like, 2018, because most orgs had setups that were better in some key areas. But it was pretty easy to use and get started with, which mattered, and still matters, and soon enough nobody could compete with the same ease of use for free projects.
If I had to "blame" "someone" in this vein, a better place to start: global monetary and fiscal policy for the past 20 years resulting in software development becoming one of the only places with rising wages to meet cost of living demands in places like the US -- resulting in an influx of new blood to increase their wages and quality of life, combined with political choices like low interest rates, and huge explosions in demand for software devs for things like VC adventures, etc. Subsequent developments like bootcamps designed to churn devs out to match rising demand, etc which solidified platforms like GitHub further as it was easier for them to paper over these fundamentals when there was a clear winner (git/github) to focus on and ignore everything else. Forest vs trees and all.
> That's completely made up on your end. I've been doing FOSS for 17 years and the vast majority of people were barely competent with any of them at all beyond whatever their chosen ponyshow was
I doubt either of us has actual figures, so it's "my experience" vs "yours" (and full of anecdotal bias which I'm willing to admit). At least what's factual is that a decade ago, the versoning and tooling ecosystem was much more diverse: where today github/-actions/-CI/-issues/… is a quasi-monopoly you would bump into a new hosting solution/bug-tracking, reviews and CA build systems every other week, and the major open-source projects were either using CVS, SVN, GIT or HG. So, in proportions, more people had to be able to switch from a system to another, just out of practical considerations.
And I'm not even looking back pretending that things were perfect back then, I'm only suggesting that the monoculture which ensued killed a lot of competition, innovation and convenience, from which we could benefit today, on top of increased standardization (did you know for instance that hg can pull and push to git?)
> For every 1 person doing this 50 just stuck with whatever they used and wouldn't bother. I've literally seen people refuse to contribute to a project over tabs vs spaces, and people still do this with git vs hg today, just not as much today.
There's some truth to that, but it's a pretty extreme view. All projects can benefit from a lower entry bar and should be as welcoming as feasible, but optimizing for drive-by contributions at the expense of more meaningful involvement is destructive on the long run: anyone having worked on larger projects knows that the bulk of the effort is carried by a smaller group of dedicated people over long periods of time, not hundreds of over-the-fence-throwing typo-fixes. And I'm totally siding with projects who don't want to adopt the github ways of organizing their work where it means making long-haul contributor's lives more difficult.
> More people use Git and contribute to FOSS in a single day in 2022 than every developer who knew all these tools combined back in 2008 or whatever.
[Ref. Needed]
> > Things really became one-sided after github started gamifying open-source contributions, and when a new generation who perhaps grew-up in a more competitive academic setting took it as an opportunity to make their resume more impressive.
> Sorry, but I consider this to be a similarly made up claim that's just sour grapes.
If "gamified" may not be the right term, you certainly can't be oblivious to how often people equate their github activity to their resume, and how it's used as a token of value by job hunters and recruiters alike. Putting aside the "merit" of most contributions, this really contributed to people "demanding" from projects to move to github, to bring visibility on themselves (before the interests of the project itself), hence the centralization around the single largest platform. I don't know about you, but I find this state of affairs quite discomforting.
Staged changes, excluding renames.
So git-fixup and git-absorb will now happily live together for the moment on my box.
Made a good first impression, thanks again for the reference.
The most common workflow I have is that I've got a couple of old working branches (like featurea and featureb), and I want to see if I need to update featureb to a newer head or not, or if featureb was based on featurea or featurea-v2. A demonstration of this kind of thing is 'hg wip' here: http://jordi.inversethought.com/blog/customising-mercurial-l....
Another thing I would use revsets for is answering queries like "which of these changes that's on the public repository made its way into the internal repository (which periodically merges from the public repo)?"
We often (a.k.a. constantly) want to see a subset of commits that meet some criteria.
The way Git handles this is by adding more flags, which doesn’t scale.
Just look at the man page for git log… it’s nuts.
Having a concise functional query language [1] is one of Mercurial’s and I guess Sapling’s killer features.
I have used (actually introduced) Mercurial before at a company and considered them basically equivalent enough, only to get stuck in some horrible design choices of early Mercurial (named branches and not having rebase by default). I am happy to see these elements corrected in Sapling, giving me enough confidence that I might actually use Sapling over time...
Staging just means "I'm happy with the changes so far but didn't finish everything I want in my commit; let's ignore this changes for now".
What `git diff` does by default becomes useful when you touch the staged changes again. Then you see only the new changes compared to the staged stuff. This helps building up a commit step by step, with some trail and error in between.
Think for example about something like: You use some tool to do some automatic changes. This creates hundreds of changed files. But the result isn't working. You could commit that, sure. But than you would need to rewrite history before pushing because creating not working commits is a terrible idea. Or you could just stage the changes for now. Than you can change / repair the still missing parts. Git diff will helpfully show you only the new changes but ignore the staged stuff as long as it's untouched. You would now for example easily see changes that you made to the automatic rewrites. Without the staging behavior you could only compare with a committed state, and drown in hundreds of changes that are unrelated.
The main problem with the staging area is that quite some GUI tools don't use it correctly. The tools try to "simplify" Git by ignoring how the stating area is supposed to work, or ignore it completely like the infamous JetBrains IDEs. (IDEA is the tool that needed almost 10 years to implement Git sub-modules…). I think the VCS handling in IDEA is on the surface very polished. But when it comes to something like the staging area the UI-wise very crappy VS Code Git support beats that by far. Sublime Merge does also the "right thing"™ and hides the staged changes at the bottom so you see only the the changes to the changes. Exactly as the staging area is meant to be used!
Git is conceptually very sane and logical. But the UX is indeed (still) terrible.
But a lot of people seem to complain about the complexity of the underlying concepts. That makes no sense to me as the concepts are complex because the problem at hand is complex. Also it makes no sense to me that people are constantly crying for a new tool even they have obviously issues with understanding the problem space and all requirements. A new tool would not make all this complexity go away! It could at most try to "hide" some of the complexity by introducing magic. This wouldn't be helpful at all as magic is way worse than bad UX, imho. Bad UX is bad UX you can deal with it. But when magic goes wrong all bets are off and you're usually in deep trouble.
This looks like people would argue to rewrite the back-end (some propose form scratch!) even only the front-end needs some face lift…
But you can make a Sapling clone of your local git repository, so you don't have to clone from the server again and you would get all your local work from your git repo. That might be the easiest way to try Sapling, so you don't have to delete your git checkout at all.
Whoa I didn't even know you could do that in git. I always considered clone to mean "download stuff from this location" but now it makes more sense. Thanks I'll give that a try.
git reset --soft HEAD~n
where n is the number of commits I want to undo.Known issue: can't undo all the commits.
Git switch is also something I learned recently so sometimes I type checkout because of force of habit but I am trying to do better (even though I'm not sure what switch dies that checkout can't but don't want to get into arguments, just want to do things the prescribed way).
Or if the commit should for some strange reasons really never exist just move HEAD one commit back. You could even get the changes back by merging the "bad" commit back without committing the merge (using the `--no-commit` switch).
That Git is able to handle even completely weird requirements, like making history disappear?
Complete shit is what it is.
It's awkward, messy, inconsistent, and hard to compose.
I seriously doubt anyone who uses a sane interface to Git (e.g. a GUI) has any trouble with clicking + to add changes to the draft commit before committing it.
Most GUI tools let you automatically add all changes before committing anyway so you don't have to know anything about it if you don't want to.
They just needed to name things better (what is a "soft reset" again?).
A better fix would be to make the staging area an actual commit, and then reframe everything as easy ways to edit the latest commit. (This meshes well with adding features like Mercurial's phases or changeset evolution that make commit editing somewhat safer).
1) tfs: shelves are named and can be worked with independently; git: stashes are numbered in a sort of a stack and only the top stash is unpacked and deleted destroying your data, infuriating, also local edits are moved into the stash, not copied.
2) tfs: branches are mapped to different folders and can be worked on simultaneously; git: branches are mapped to single folder and switching branches deletes local edits.
3) tfs: pulling from server merges new text preserving local changes; git: pull and checkout deletes local changes.
4) tfs: can't commit unresolved merge conflicts; git: commits just fine, it's also not obvious if you have merge conflicts to commit or not.
5) tfs: handles concurrent edits as merge conflicts and handles them as they occur; git: you create feature branches and in case of concurrent branches you have merge conflicts when you merge to master, then you have p.4. Feature branches are advertised as a big fat killer feature of git, but I don't quite see the win here, you still have merge conflicts.
6) tfs: all commits in a branch are visible, it's not obvious how to delete them, you can only create rollback commits; git: if something happens to the branch label, the commits are gone.
I want my VCS to be quiet, out of sight and do as it's told, because my main focus should be programming, not how to tame a tool that's supposed to save text. The fact that you have to "learn git", and that there are so many StackOverflow git question on how to do (what should be) trivial operations is probably a hint that things aren't great in the usability department.
For hg, I just read an introductory guide (I think it was Joel Spolski's one) and that was enough. I used to be able to do a more in-depth comparison and criticism but nowadays I use git and try not to think about it too much.
The entire CLI is badly designed, with highly non-orthogonal commands interacting in unexpected ways. Recent versions of git has started introducing commands with a more top-down design (e.g. git switch), but that's a very novel development
Git also diverged significantly from the SVN command line, but instead of following the tasteful Darcs path of making commands clearer and cleaner it commonly:
- reused the same terms for different operations, usually less intuitive ones (e.g. the absolutely awful "git revert")
- removed clear commands to confusingly tack them onto others (e.g. "git add" to resolve commits)\
On that front, mercurial extended the existing commands-set much more cleanly and clearly.
Mercurial's CLI felt like an improved extension of SVN's, Darcs felt like a drastically different take with plenty for it, Git's felt like one of those ransom letters cut out of newspapers, full of jangly bits which make little sense, and concepts which worked fine altered for no perceivable reason.
Users that started with Git are more likely to internalize Git's concepts as "the natural way to do version control", and more likely to find Mercurial counterintuitive.
I feel like the Mercurial fanbase is just another loud fanbase. I did start with CVS and SVN and git was absolutely fantastic when I started using it. On the other hand I could never get the hang of Mercurial. From MY PERSONAL perspective it has a terrible UX(which is the exact opposite experience of the loud hg fan git critics on HN). I absolutely cannot relate to the people who say that Mercurial has the better UX, but I don't remember myself constantly bashing mercurial either like the other side does. From my perspective `git add -p` is an important essential functionality that hg does not provide. I believe there was some sort of plugin but it was no where near as polished.
Yes, there are a handful of nice features in mercurial, but none which are actually necessarily needed inside of the git core.
I do faintly remember that my biggest problem with git was understanding that a commit doesn't push automatically. But then again that's just a difference between a DVCS and whatever was there before.
Mercurial has an interactive commit mode (hg ci -i) with a slick TUI for navigating and selecting chunks to commit.
But where mercurial shines with a clean, consistent and simple UX, git is a mess where storage-layer abstractions leak to the user and where single commands serve multiple unrelated purposes.
To give you a practical example, any command that takes commit(s) as argument (for checking-out, logging, rebasing, …) would be passed a `revset` in mercurial-land. Revsets are a simple DSL to address commits (by hash, lineage, topology, distance, …), which makes new commands easy to learn, and renders one third of `git help log` inadequate. Most commands that output something use templates as argument, which renders another half of `git help log` laughable.
There is nothing "natural" about the git UX, you've got to accept that it grew organically with no attention to details.
All this to say, I love git, and as a versioning system, it seems obvious to me that we can do better than git for 90% of workflows. Just yesterday I was surprised by how `git push --tags` worked and had to read the man page for `git-push` to see I wanted `git push --follow-tags`. Just reading this forum today I see that I alternately probably(?) could have figured out what I wanted with `git help push` which I didn’t even really realize was a thing.
But do I want to use an easier versioning system? I’m not sure. git has a kind of forcing function for a growth mindset. I value it for its creative expressivity.
Edit for sibling comment: Stockholm Syndrome, quite possibly. But as the “victim,” I still love git!
I'm not saying mercurial is better, but there's a reason I have to remind people that this[1] is satire - the real manuals are so convoluted that they seem like parodies of themselves.
[1] https://git-man-page-generator.lokaltog.net/#c2NyZWVuJCRnYXJ...
Google does this, it has saved my butt on more than one occasion.
> Sounds like saying bye-bye to any meaningful history.
I'm so confused, you just amend the most recent commit, or work with changes unstaged and uncommited. Like my normal workflow is basically "change 2-3 files such that things are passing, hg commit, send for review", and then I continue working on the next thing, either back to HEAD if its unrelated, or on top of the just-pushed changes if it depends on them.
It's vastly simpler than having to git add at random times.
> Google does this, it has saved my butt on more than one occasion.
You mean backups? Yes, backups are a very good idea.
But this has nothing to do with VCS. That are separate topics.
> Like my normal workflow is basically "change 2-3 files such that things are passing, hg commit, send for review", and then I continue working
As long as the requirements are so trivial even CVS would suffice.
But even considerably simple refactorings (in e.g. static languages) can be much more complex. It's easy to end up with hundreds of files changed. Than you need more powerful tools. Doing such things without the staging area is almost impossible to get right. (The only alternative would be quite some rebase sessions; and those are way more complicated than using the staging area upfront; also you would need some way to do diffs against "pined" changes—which is something you get for free with the staging area).
No, I mean that the filesystem I edit code in has a full snapshotted history of every save and I can recover to a particular revision or particular point in time, even one's that weren't committed to vcs[0]. I guess you can call that a "backup", but like it's not what people usually mean.
I have used this to recover some things I was working on three months ago but ended up throwing away.
(citation:
> All writes to files are stored as snapshots in CitC, making it possible to recover previous stages of work as needed. Snapshots may be explicitly named, restored, or tagged for review.
via https://cacm.acm.org/magazines/2016/7/204032-why-google-stor...)
> It's easy to end up with hundreds of files changed.
Sure, doing a rename can touch 100 files, but you should isolate that change to a commit and PR that don't do anything else. Running sed and then committing or using your IDE's refactor feature, and then committing and running tests doesn't require a staging area.
[0]: The truly wild thing about this is that the vcs state is also stored in the snapshotted, point in time recoverable fs, so if you do the equivalent of absolutely botching your git history, you can jump back in time a few minutes and start from a known good state.
It would be very difficult to handle quite some "WIP situations" without the staging area.
I think we’ll be okay with this stack workflow [2] taken from Mercurial’s Evolve command [3].
[1]: https://en.wikipedia.org/wiki/Stockholm_syndrome
[2]: https://sapling-scm.com/docs/overview/stacks
[3]: https://www.mercurial-scm.org/doc/evolution/tutorials/topic-...
I lived through the alternative and the staging area is superior. If it wasn't, I might not be using Git, or at least begrudge when I have to; neither is the case.
I also don't see anything that couldn't be trivially added to Git. A few lines of shell script would likely suffice. What do I miss here?
This opinion seems to be peculiar to software and I think it has something to do with the fact that software is one of the few verticals where you can (attempt to) intellectualize everything.
Having control over your own destiny in any other skilled labor job seems to be 98% about finding a brand and model of tool that works the way you do, and 2% building your own tools or jigs for that specialty task nobody thought to build a tool for.
In software it's anywhere from 90:10 to 10:90 depending on how much emotional baggage your coworkers are carrying around.
I don't quite buy this: Those same "motivated, high performing people" don't seem to have anywhere near the same "need to have control over their own destiny" when it comes to the commercial closed-source tools they use.
I’ve seen people reinvent the wheel all over the place because their tools weren’t quite working for them. This instinct is the reason most good software has APIs - so you don’t have to ditch the tool entirely to customise it to your workflow. And most medium to large companies have all sorts of wacky customisations on top of existing software.
Eg perforce at Google. Well, everything at Google. And a friend at a big broadcaster has a bunch of company specific plugins for Reaper for their audio editing pipeline. And everyone insists on customising Jira.
Because switch is built on top of checkout, there's no functional difference between the output of the two subcommands when used for the same purpose (assuming the presence of a skilled operator). It's strictly a matter of ergonomics and abstraction.
At the end of the day, as long as you don't fuck up, just do whatever best keeps you in your flow state.
That's not to downplay git qualities, but as a social experiment in soft peer-pressure and group-thinking, I think it has value (though that's beyond my field of expertise).
I came to mercurial when, after shooting myself in the foot with git for the N-th time and going on a rant about it, someone on IRC told me to give mercurial a shot and move on with my life. I confess that TortoiseHG helped me translate my git habits into the equivalent hg commands, and the kind of history exploration that I was doing then set me up to speed with the revset way.
Then, what I found formidable was that all the knowledge about git intricacies that I had accrued and internalized with pride over the years became absolute no-brainers and irrelevant in the hg world: I remember a famous stackoverflow thread in 10 steps for merging two unrelated repos (including arcane git commands, shelling-out to sed, and non-transactional storage-level ops that would warrant a backup, as was the norm back then). How do you get history from a repo in hg? `hg pull`. How would you go about getting history from a repo (unrelated) in hg? `hg pull` as well. And thinking about it, would have git been nicely designed, it wouldn't have had to care about the difference and even less so had to expose it to the user.
Mercurial, although not perfect, really opened my eyes on what good UX design should look like.
Isn't git switch syntactic sugar for git checkout? What's wrong with checking out a branch?
The fact, e.g., that it's a completely different operation than checking out a single file or folder? (One changes HEAD, one doesn't. One warns about overriding local changes, one doesn't, etc.)
The whole point of the "draft commit" is that you can easily see changes against your (uncommited!) changes. That helps to build up a commit step by step.
Committing WIP stuff (and maybe even pushing that) makes the history useless. Branches don't help as you end up with millions of WIP branches that are all incompatible to each other (and the evolution that happened elsewhere). Only keeping WIP branches up to date is a full time job than.
Git has already a means to edit the latest commit easily: `git commit --amend`.
> Committing WIP stuff (and maybe even pushing that) makes the history useless.
Here's the thing. I'm a very big proponent of keeping history clean, and making sure that commits are atomic, and exorcising any "typo fixes" or the like commits from history. Not once have I found the concept of a staging area useful. Features like `git commit --amend` or `git add -i` are incredibly useful [1]. But not the staging area itself--it's only a thing that screws me up if I forget to add `-a` to `git commit`.
"Draft commit" also I think elucidates the other problem. You see, drafts of regular documents are frequently shared with other people, multiple versions of them created and shared, etc. Drafts don't become final until it's actually published--and there is utility in being able to track the differences in drafts as they are discussed. If you've got a "draft commit", then it should be able to go through this process--this is basically the process of code review.
Of course, we're already working with a VCS, which is designed to handle different versions of code, so... what if we made the "version history" of commits just... regular commits? Sure, shade them a different color, so you know that a commit is a draft, and you can tell which of the commit's parents [2] is the previous version. And knowing that a commit is a draft, when it actually gets pushed into the trunk, you can commit only that final commit and not include any of the previous history. Since the commits are using the same DAG logic under the head, questions like "what changed between version 2 and 5?" become just regular diff commands [3].
By the way, this system already exists. It's known as changeset evolution in Mercurial, and it appears that Sapling here has adopted it. My workflow in git tries to emulate this model to a degree, but the approach of having branches-based-on-branches doesn't mesh well with how git wants to do things.
[1] The number of times I have painstakingly sorted out which changes go into the commit with `git add -i` onto to immediately and accidentally undo them with a `git commit -a` is quite high. And because the staging area isn't an actual commit, it can't be recovered by digging into the reflog like actual commits can.
[2] If you amend or otherwise modify a commit, it has one parent, which is the previous version; if you rebase a commit, it has two parents, one of them the new commit it's based on and the other is the previous version.
[3] Worth noting that this question often turns out to be difficult to answer with most code review systems. Building a model of "commit history" into your VCS makes it come out for free!
You can just use the tip as your staging. Use interactive amending to move changes from the working copy to the commit, and when you want to "commit", finish up the message.
hg actually has an "unamend" command (part of the "uncommit" standard extension) which... reverts the last amend. Rather than having to remember how to contort reset into the right shape to move changes back out of staging without destroying everything.
Combine this with the case where "I want to break one commit into two commits," where now I have to worry about making sure I know if the command is going to change the revision HEAD points to. At least there, the old commit will still exist as backup in the invariable scenario I screw something up.
You can use `git commit -p` to get the same functionality but without explicitly using the staging area.
I don't think your comparison makes sense. Git stash is a way to quickly get to a clean local workspace that can be reversed as you see fit. You use local branches to track independent work.
> tfs: can't commit unresolved merge conflicts; git: commits just fine
Again, this doesn't make sense. In git, users determine whether a conflict is resolved or not. If you commit a changeset originating from a merge conflict, you have to explicitly state that the conflict was resolved and your changes are good.
> Feature branches are advertised as a big fat killer feature of git, but I don't quite see the win here, you still have merge conflicts.
Honestly I didn't understood what point you tried to make. Merge conflicts happen because multiple sources of change touch the same document region in a way that can't be resolved automatically, thus needing human intervention. To the best of my knowledge, there is no cvs in the world that eliminates merge conflicts.
Regarding Git's support for feature branches, the fact that you don't understand the big win Git brought to the world with it's branching model is already a testament to how groundbreaking Git was at the time, and how everyone around was quick to roll out Git clones that follow the same approach. To see what I mean, spend a day working with a SVN repository trying to do work involving feature branches.
> git: if something happens to the branch label, the commits are gone.
Aren't you actually saying that if you delete a branch then the branch is deleted?
Local branches store immutable state, but shelves can be unpacked anywhere (like a stash), thus local changes carry over, but git deletes them on every occasion.
I see this claim often, but it never is accompanied by evidence or any concrete example.
I've been using Git for years and I never noticed any semblance of unintuitiveness or bad defaults. Everything in the happy path is straight-forward, and all obscure things are a quick googling away.
Do you actually have any concrete example to back your claims? What's the absolute best example you can come up with of said unintuitiveness and unfriendliness?
Just compare the man pages! "git help clone" vs "hg help clone".
A random (trivial) example off the top of my head. When working with branches:
> git pull
> git switch another-branch
Your branch is behind 'origin/another-branch' by 2 commits, and can be fast-forwarded. (use "git pull" to update your local branch)
... why? I literally just pulled, why are you asking me to pull again? 99% of the people on the planet literally want the last version of that branch (provided there's no local changes leading to a conflict).
Compare with hg:
> hg pull
> hg update another-branch
Done.
I haven't worked with hg in a long time so I can't really provide an "absolute best example". All I can say is that, from memory, hg always got out of the way, and when I wanted to do something out of the ordinary I could either guess how to do it or it was easy to figure out from the manual.
With git, almost nothing's easy. It can become easy if you invest a lot of time in understanding how it works internally (which explains some of its CLI choices). But that to me is a sign of a bad tool. "all obscure things are a quick googling away" - why expose the user to obscure things to begin with?
We've had dozens of discussions about this here on HN – with lots of evidence and concrete examples.
https://www.google.com/search?q=git+user+experience+site%3An...
The common case it to amend mistakes. Git makes it very easy to accomplish that.
The other thing is: Git is conceptually very simple. There are almost no "esoteric" concepts. It's just a Merkle tree and some pointers to nodes on top of a very simple plain-text database.
My experience with people that have problems to understand Git is that most of the time those people never tried to understand how Git actually works. But everything (besides the concrete commands and switches, oc) becomes almost obvious when knowing the inner workings.
The main problem with Git is its UX.
I don't know anything of this stuff out of the top of my head! I have to look up the concrete commands or switches every time. But from the conceptual point of view Git is very easy to use. Because the underlying concepts are indeed so simple and straight forward.
The UX is exactly what we're talking about, yes
I have a CS background and I don't even know what a Merkle tree is without looking it up, and I'm sure after looking it up I'd have to do more digging/research before it gave me a clear mental model of how git works. I'm pretty comfortable in git at this point - I know how to navigate the space of normal-ish states - but that came after years of exposure.
For a person who's learning to code, who's expected to jump straight into GitHub as a part of their very first real project, the situation is kafkaesque.
The whole point is that this things are treated differently.
The concepts are very simple. The UX on the other hand is at least "sub-optimal".
> I have a CS background and I don't even know what a Merkle tree is without looking it up, and I'm sure after looking it up I'd have to do more digging/research before it gave me a clear mental model of how git works. I'm pretty comfortable in git at this point - I know how to navigate the space of normal-ish states - but that came after years of exposure.
That's exactly the point that I've tried to explain: People make their life substantially more difficult because they never learn the basics. This way Git keeps to stay guess work till the end of days.
The theory behind Git may seem off-putting when words like "Merkle tree" come up. I understand that.
But actually it's something that I could explain to a 12 year old in 10 minutes…
Instead of looking things up people chose to struggle for years and years, without ever having any understanding about the "magic" that happens behind the scenes. But without the theoretical knowledge Git is not really intuitive, that's true. Coming up with a "plan" how to accomplish something becomes than a matter of black arts. But it really isn't! Git is very straight forward. Really. Just take the time to look up how it actually works. Everything (besides the weird APIs) will start making sense than.
The whole point is to have some form of "draft commit".
The staging area lets me "stash" WIP changes in a transparent way.
Having a "draft commit" feature avoids the need to rewrite "bad commits" after the fact.
The staging area is really useful to build up commits gradually.
When thinking about it I've just realized that the staging area should not only be kept as a feature but could be even extended. You could add a "change-set management system"—which would be essentially multiple staging areas (maybe coupled to improved stash functionality to be able to quickly move / copy changes between change-sets).
Yes, such a thing would very likely need to be built on top of the mechanics behind branches / commits. But this should be transparent and not interfere with the said features, imho.