365 comments

[ 4.1 ms ] story [ 355 ms ] thread
"The mental model for Git is needlessly complex"

News flash: Many programmers love complexity.

Complexity == popularity == profit

Prove me wrong, please (I seek simpler stuff)

Many new/inexperienced programmers love complexity.

I used to get into exploring every nook and cranny of every config file and endlessly tweaking settings.

Now I strive to use everything with default settings if at all possible.

> Many new/inexperienced programmers love complexity.

Not sure if you're trying to argue that Linus was a "new/inexperienced" programmer when he first wrote git.

I think the "it's too complex" argument against git is misplaced, or at least not complete. I don't find git "complicated for complexity's" sake (e.g. looking at Enterprise Java Beans back in the day), but it has a very specific workflow in mind for its conceptual model, and if you don't understand that conceptual model, you're just going to be confused.

It took me a while to grok that model, but once I did it clicked and I understood it. Not saying it's optimal, but it also has a lot of benefits.

OpenBSD uses CVS to develop an entire OS, kernel and userland. Git's complexity is not required.
Exposing the user to the totality of the complexity of the problem is, perhaps, the most complete and indefensible failure of an otherwise successful software design that I can imagine.
All abstractions are leaky, but an abstraction meant to never lose the work of a power user is maybe more defensibly leaky than average.
Whatever I read about Linus seems to imply that he is far smarter than me but git is a great tool for his personal purposes.

This is an 18wheeler that can haul anything but for "basic" dev doing simple administrative apps, a bicycle VCS is more than enough. A lot of dev I've met don't even understand the deep ramifications of multiples branches with any VCS so understanding the complexity of git is way above what we require of them.

Git has a lot of benefits but I'm not quite sure that it's really a good thing that it is slowly becoming the de facto standard.

Wait and see...

Yup. When I have to install it for the sixth time the last thing I want to do is remember what I had to configure the fifth time and what I had learned that I needed to stop configuring from the third and fourth times.

Now I want my operating system and my tools to shut up and get out of my way because whatever irrelevant thing they think is important is not what I ever need to be working on.

I think the mental model is "I can use this tool, since it's hard it will make me look smart"
People who have stuff on their monitors specifically so others think "they must be really smart" are the scum of the earth.
(comment deleted)
Wow. Maybe this is why most software sucks.
I would say it's more like complexity == feels like I've accomplished something
Best feeling in the world, as a programmer: removing code! (My implication: removing complexity.)
Removing code while maintaining or increasing functionality.
I think you're right. And as much as I want to think I'm ruthlessly simple, I do notice this in myself as well.

Everyone will agree with us of course, but suggest something minor like "hey maybe you don't need react" and here come the reservations. To paraphrase Alan Kay, everybody likes simplicity except for the simplicity part.

Do you mean the UNIX way (cp, diff, patch)?
You are right there is a correlation but not because programmers love complexity.

It is easier to design complex systems and harder to simplify. Also complex systems have positive economic incentives like consulting training books or that if simple will not be sustainable.

The entire job is managing complexity, either by developing good abstractions for adding and maintaining necessary complexity, or by removing unnecessary complexity. I love this process, so I guess you could in some sense say that I “love complexity,” but not in the sense that I increase complexity whenever I can.
I think some of it also comes from treating symptoms instead of problems.

"Git doesn't do X so I'll just make this tool to add the feature"

One hundred tools and a few consolidations into toolkits later you have a massively complex tool chain scope creeped from some much smaller problem deep down in git

My observation is that it all depends on scale. Huge projects (such as Linux code base) can’t survive with simple solutions (e.g. non-distributed VCS).

Loving complexity for the sake of complexity or sake of job-security or competitive advantage covers only small subset of situations.

There’re a lot more cases where seemingly simple problem has a lot of hidden complexity, and only complex enough solutions succeed at successfully solving it and staying competitive on the market…

Complexity is fine in something like a programming language or a text editor where increasing mastery can mean better software and hopefully more money. How do I make more money by learning arcane Git commands?

We don't use DVCSes for their own sake, we use them to accomplish something else. To the extent that the DVCS gets in the way, it's an opportunity cost.

> Complexity == popularity == profit

Entire node/js/ts ecosystem resonates strongly here. They reinvent the wheel, assign it a new name, thought-leaders market those inventions to every corner of the tech ecosystem, and then they add another few layers to their build chain.

"The mental model for Git is needlessly complex"

This, in a nutshell, sums up my feelings about git.

BuT It MaKEs SeNsE If YoU KnOW HoW ItS ImPleMEnTeD
I never feel this way. When I started to use it, I only had to understand a few concepts. And when it started to get more complex, it was because the things I wished to do were more complex in the first place.
Did you ever use any other VCS?
I used mercurial a bit when I was starting out but I saw which way the wind was blowing and switched.
Kind of similar. I went from Subversion to git, then tried mercurial. I found mercurial to be more natural, and still use it for my own projects. I have never seen it used in the workplace though.
My workplace switched from hg to git. Hg didn't get support for all the other tools we use. The Jenkins hg maintainers were all using git when we checked, and it showed. That is but one example of a tool that didn't work with hg.
Subversion, and mercurial to a lesser extent.

CVS and Visual Source Safe way back in the day.

Intersting. I always found git needlessly obtuse, with for instance the status reporting diffs to local remote-tracking branches instead of the actual remote branches, the staging area having an unclear purpose to me at the start, that it mixes up "local" "remote" and "base" depending on how an operation is implemented, commands doing double duty providing wildly different functionality etc..
Yes, coming from Subversion the whole staging area concept seemed like needless complexity. For my purposes it still is, but I've gotten used to it.
It seems like a nice way of having changes you don't actually want to commit but I'm not sure how other systems approach that problem.
I really liked Perforce changelists, so in theory I should like the staging area, but I kind of don't :)

I use it nowadays, but I think it's too limited to provide value like Perforce changelists does.

I'd like to have one changelist for random local dev changes, like setting debug flags or turning off optimizations. Stuff I have no plan on checking in.

Then I'd like to group my edits into maybe one to three possible future commits.

The staging area doesn't allow this, I need to keep doing "git add -p" and carefully sidestep all the debugging stuff, plus that I can only work on one commit at a time.

So could have been useful, but not so useful in it's current state IMO.

> plus that I can only work on one commit at a time.

This is that part of git that bugs me the most! It's totally hostile to the way I prefer to work: one screen session containing all the editors and shells per change that I am concurrently working on. Git simply cannot do it, unless I clone the entire repo for every change, which is not practical for large projects.

Because it’s file based, and that’s obviously behind a lot of the criticism coming from the author of Fossil.
> simply cannot do it, unless I clone the entire repo for every change

Note that you can have multiple working copies from one clone for a few years now. git worktree add <path> <branch>

When I am working on assembling multiple commits at once, I make a large number of small commits with commit messages that indicate which commit they're going to end up in, and then do an interactive rebase at the end. The workflow looks something like:

    # At the point I realize I have two commits
    git add -p
    git commit -m 'first'
    git commit -am 'second'

    # Do some more editing
    git add -p; git commit -m 'debug' # commit the debug stuff so that I don't have to keep skipping it
    git add -p; git commit -m 'first'
    git add -p; git commit -m 'second'
    # After repeating the above a few times
    git rebase -i origin/master
    # Remove the debug commits, move the first/second/etc. commits together, squash the runs of first/second/etc. into one commit each, and then go back and write commit messages for each of them
I have used SCCS, CVS, VSS, SVN, Clearcase, darcs, git, and hg.

I found darcs to be the most ergonomic, except for the fact that it was orders of magnitude too slow.

SVN was good in that it fixed most of the pain-points that CVS had.

git and hg are both great. I tried them both out at about the same time and found hg to be more intuitive, but it didn't take me long using git to be comfortable with it.

The UI of git is honestly quite terrible. Commands are often confusingly named and have seemingly disparate uses. However the underlying model of git is straightforward enough for me to reason about what operations should be possible.

Pretty much all VCSs require some such knowledge and reasoning; e.g.:

- The lack of atomic commits in CVS stems from the underlying RCS stack it is based on.

- SVNs brain-dead branching stems from the fact that there are no branches in SVN, just O(1) copies from one path to another.

Yes, it can be that way.

I know/use clone, diff, add, commit, and pull/push.

That is all I ever do with Git, and it's pretty straightforward. I have found no need for the rest of it, and it confused me when I tried to look into it.

Honestly, git is absolutely needlessly complex. The worst aspect of git is the almost arbitrary naming of tasks that hardcore git users swear are obvious. E.g. "cherry picking", "fast forward", "rebase". Anyone not familiar with git will balk at the concept that the intent of these phrases are obvious.

Note: I use git frequently every day, not by choice, but simply because it is the defacto version tracking system. I have grown to like it, but I miss the more straightforward every day use of Mercurial (which is rarely supported by any services anymore).

Edit: ... and as a native English speaker, I can't help but feel bad for others who are expected to become familiar with these functions without familiarity with these colloquialisms.

If you used SVN or something similar, daily, prior to git existing, git operations actually does seem pretty obvious.
As the poster pointed out, he's coming from Mecurial, which is a DVCS similar to Git.
Fossil was designed by someone coming from CVS, so its everyday CLI is actually closest to that. As a Subversion expat, I found Fossil quite easy to pick up, modulo a few quibbles that muscle memory sorted out quickly enough.
Perhaps, but it originates from the days you'd run `man git <command>` before using it. `man git rebase` works and has a very lengthy description with example tree states.
Well, sure, the names aren't obvious if you're not already familiar with them, but neither are names like "linear probing." New concepts come with new names.
(comment deleted)
The complexity isn't needless, it is hard to find a part of git that can be simplified without losing something important.

But the command line user interface is one of the worst I've ever seen. The names are bad, discoverability is poor and which command line tool does what doesn't always make sense.

I completely agree. Git is a product of its requirements. It's not perfect, but it gets the job done, and obviously it does it pretty well.
Products don't have requirements, users have requirements :)

The requirements of Linus and the kernel developers are completely different from the requirements of the vast majority of users of Git, who are using it in small teams in a centralized way.

I would argue that the only benefit that this decentralization gives is a local cache, which makes things nice and fast. Most users don't need to be able to create branches easily (code review tools already let you do that, effectively) and it's just given people enough rope to hang themselves (e.g. GitFlow).

IMO the worst aspect of this needless complexity is having to explain to people "you've got 1) the branch central repo, 2) your local copy of that branch, and 3) your local branch". It gets even more complicated when personal forks come into the picture, as there are just so many copies of things to manage or trip over.

Try explaining to a junior developer why "git fetch" takes two arguments ("origin" and "master") while "git rebase" takes just one: "origin/master".

I'm not sure it's so obvious that it does it well. The thing about the tech industry is there's a lot of cargo cult and leader/follower mentality. There are plenty of shops that use git just because every other shop uses git. Chances are, most of them don't need anything nearly as complex as Git and other version management approaches for their project would suffice just as well.

It's sort of how a lot of shops decide they need to incorporate 'AI' into everything, or they need to use microservices and Kubernetes to solve their problem. Some of it is just resume driven development but a lot of it is just observing and following trends.

> The thing about the tech industry is there's a lot of cargo cult and leader/follower mentality.

> Some of it is just resume driven development but a lot of it is just observing and following trends.

Couldn't agree more. That's exactly what I think happened with git.

Why the while "first stage, then commit" workflow though? Wouldn't it be simpler to just commit?
One of the ways I use the staging area is as an ephemeral wip commit: I've got a change that runs and gets me incrementally closer to the desired result, but isn't yet an atomic commit. Changes to that state can be built upon, undone etc until I've got something I'm happy to commit.
I often have local changes that I do not want represented in my commit (e.g. that code isn't done yet), so what would I do with those changes? One solution might be to stash them, select files while doing a commit, or otherwise put them aside, but that feels like reinventing the stage-then-commit workflow. That said, adding an alias for adding everything and committing it in one shot seems like a worthwhile quality of life change.
I find it's common that I want to change stuff in my local dev environment with changes I don't actually wish to commit -- let's say hardcoding to some folder on my local machine in a configuration file, or something like that.
Loosing something that a lot of people doesn't need and will probably never use. Beside the Linux kernel (that git was created for) or other big projects, most developer will only use a bunch of features.

The command line is shit, one example: `git checkout` can both switch to a new branch or restore a file.

Fossil is that thing: a simplified DVCS that doesn't have important bits missing.

There are certainly cases where Git is the right tool, but it's vastly overapplied, used because it's popular, not because it's the best tool for every job. For smaller projects without a lot of randos offering PRs from the outside, Git's probably costing you more in its complexity than it's saving you by having that complexity at hand.

> Fossil is that thing: a simplified DVCS that doesn't have important bits missing.

One of Fossil's selling points is that it's missing several important bits (i.e. all the tools for rewriting history)

Exactly. The Linux requirements are the single most complex problem and they need the power of git to handle that complexity. The problem isn't git.

The issue is that everyone is using the most complex tool, from solo developer, to 10 developer teams, to 1000 developer projects. You should use the simplest tool that gets the job done for your project[0]. That isn't git, but it's so easy to just pick the thing that "scales".

[0]: https://blog.codinghorror.com/the-principle-of-least-power/

If you've used a tool like Looker that tried to ignore the difficult parts of git, you'll quickly realize they are not ignorable, but necessary.
Genuinely curious: what would you rename cherry picking, fast forwarding, and rebasing?
I would eliminate these tasks from the aspect of the user and provide a more straight forward way to accomplish the same intent. You make a good point though because this is easier said than done with a typical terminal based application.
You want to remove fast-forward and rebase from a graph based version control system? What would you do instead? Always merge?
It sounds like he wants a GUI so you’d just drag and drop.
Isn't that the hg concept, no history rewrites? Well it's more nuanced than that but you have much less freedom, I think
I don't think it makes sense to eliminate these, but I'll toss in "Take Commit" as an alternative name that might be more obvious than "Cherry Pick". Still, once you know it, you know it. You'd still need to understand what Take Commit means to use it effectively, but it would make it easier for a dev to learn it the first time.
Take commit sounds like some weird version of merging a pull request to me. Like you've sent me some commits and now I'm going to take them.

Cherry pick on the other hand has a non-technical definition that closely approximates what it does in git: https://www.merriam-webster.com/dictionary/cherry-pick

I’d answer that if I knew what they did. But I’ve only used git for 3 years now, so still a novice I guess.
If your git history were a tree: cherry picking is ripping a leaf off and gluing it some arbitrary place on the tree, fast-forwarding is ripping the leaf off and moving it to the end of the branch it’s on, and rebasing is ripping a branch off and gluing it somewhere else.

EDIT: cherry picking is actually making a copy of the leaf and gluing it elsewhere. And fast forwarding isn’t really moving the leaf, it’s taking the leaf you call BRANCHNAME and now calling a leaf further up the branch BRANCHNAME.

Yeah, all these are useful to prune the bonsai. It matters more when the project is big or has lots of branches, of course, but they have benefits even for a single developer.
agreed.. cherry-picking is actually a ridiculously good name.
git rebase -i (interactive rebase) is, however, to kill for.
I don't know, git doesn't have very good memory when doing rebases. You need to redo the same conflict resolution several times. You need rerere to get around that. Plus that it's quite hard to rewrite dates, names, or split commits into several.
Some fair points, but these things are possible. Last time I was using Mercurial—which was admittedly a long time ago—there wasn't /anything/ like fixup.
> I don't know, git doesn't have very good memory when doing rebases.

https://www.git-scm.com/book/en/v2/Git-Tools-Rerere

> Plus that it's quite hard to rewrite dates, names, or split commits into several.

Read the documentation for 'rebase' and 'cherry-pick' and 'add'.

> > I don't know, git doesn't have very good memory when doing rebases.

> https://www.git-scm.com/book/en/v2/Git-Tools-Rerere

Thank you for this, looks like exactly what I need at the moment maintaining a dev branch alongside a bugfix deployed main branch and having to do lots of rebasing.

If you read my post again, you'll see that I already mentioned rerere :)
And its friend, "git rebase -i --autosq" for when you knew at commit time that you needed to fold a fix into an earlier commit, by setting the commit message as "fixup! cafebabedeadbeef" or "fixup! the old commit message" (but I have less experience with the latter form)
I think it's not that bad. There is a local commit graph and there are one or more remote commit graphs. The main operations with git are to manipulate one's commit graphs and, when the time comes, reconcile the local graph with the remote one.

Once users figured out what they want to do with the graphs, they then need to figure out how to achieve that with git's cli. And I feel that is where many of the complaints about git's complexities comes from.

IMHO the best way to use git is through a GUI so that one only needs to figure out what they want to do with the commit graphs, leaving the second part of the puzzle to the GUI.

We say this now, ignoring the hot messes that were SourceSafe, Pervasive, CVS, and SVN. Git is light years more elegant that predecessors, and its holding power is evidence of that. We're able to criticize now because we've had the privilege of forgetting (or never having experienced) just how bad it used to be, and the sheer amount of time with one tool that's been a staple for far longer than previous tools lasted.
Most of the previous version control systems you mentioned were much less complex and had an extraordinadily easy mental model to understand in comparison.

Git set out to solve a different problem: adapt VCS to an agile, CI/CD world. It does this much better than those previous VCS generations, but its mental model does seem needlessly complex.

Well, I think it was also meant to be highly distributed as well (many different people all over the place could then come back and bring their changes together)

In order to achieve that, I think you end up with some additional complexity like local vs remote and a complicated graph structure to accommodate people coming "on" and "off" line

>Well, I think it was also meant to be highly distributed as well

Yeah, I guess I kind of consider that an agile tenet: in general, that people can work quickly and iteratively with limited interdependencies.

Said another way, it would be difficult for teams to work in an agile fashion--where the work itself is frequently distributed and happening in parallel--using most older VCS models.

Git set out to solve the problems the Linux kernel development faced, which is not particularly "Agile" and doesn't do CI/CD.
Point taken. May be more accurate to say that it solves some core common challenges that made it attractive for those later use cases.

Main point being that comparing the complexity of Git and, say, SVN isn't apples to apples, as the former is suited to use cases that are inherently more complex.

> Git set out to solve the problems the Linux kernel development faced

Which were "send patches to the maintainer", and a little bit of "work offline".

Linus fixed those as needed, and people who haven't those problems are using his solution a bit like painful fashionable shoes - they hurt but dagnabbit, that's what the fashion is ...

I've used RCS, SCCS, CVS, Subversion, SourceSafe, ClearCase, AccuRev, Perforce, and probably at least one more I've forgotten. ClearCase was a garbage fire for reasons of performance and stability, but none of them had an internal model that was as much of a hot mess as git's. It's not the OP who has forgotten what things used to be like. Maybe you-now understands git better than you-then understood CVS (for example), but that might have more to do with personal learning curves than with inherent complexity.
Git’s internal model is trivially simple: everything is stored as objects addressed by content. These objects can point to each other. Additionally names can be associated with objects and which object a name points to can be updated.
Arguably a big part of the confusion around the internal model is that git half-hearted pretends it’s actually just a pile of patches.
>> but none of them had an internal model that was as much of a hot mess as git's.

> Git’s internal model is trivially simple: everything is stored as objects addressed by content. These objects can point to each other. Additionally names can be associated with objects and which object a name points to can be updated.

I'll do you one better: it's just some byte arrays on disk.

I think the OP has a section that gets at some of the complexity of git's model:

> The complexity of Git distracts attention from the software under development. A user of Git needs to keep all of the following in mind:

> a. The working directory

> b. The "index" or staging area

> c. The local head

> d. The local copy of the remote head

> e. The actual remote head

> Git has commands (and/or options on commands) for moving and comparing content between all of these locations.

clearcase, lock the branch, go on vacation. yeah good model. And then there's the multisite replication mess.

Maybe they fixed that in the 20 years since i used it.. but that was a disaster.

CVS arguably has an internal model that is as much of a hot mess as git's. It's a hack on top of RCS and that fact leaks out in user-visible ways all the time.
I used mercurial for years before being forced to use git, and historically hg came first (by only a few weeks, but still first)
Certainly, but those other systems stuck around a while after GIT was around because people possibly thought SVN/etc were as good as it gets.

That said, Mercurial and Fossil came out within a year of GIT so GIT at least outcompeted them early on.

> That said, Mercurial and Fossil came out within a year of GIT so GIT at least outcompeted them early on.

Git, Mercurial, and Bazaar all came out within three weeks of each other (late March/early April 2005).

Bullshit - Git won because it was incredibly easy to clone a project and have all it's history there _and_ you could work on stuff offline seamlessly. You could git commit things without working internet.
The git model is really not that complicated. What's awful is the command-line UI to the functionality.
I'm not sure about that. Ironically I think git would be extremely intuitive if you had the right GUI for it and could e.g. rebase by clicking and dragging branches onto master.
git was a great breakthrough in terms of performance and supporting distributed workflows, but now like many technological breakthroughs there needs to be an interface that exposes completely different abstractions based on the user's workflows rather than the implementation's data structures.

For example, why can't I do something like

    git view filename -3  # shows file before last 3 changes _made_to_the_file_ (irrespective of how many commits)

    git view filename $date # shows state of file at date

    git revert filename $date | number # roll back a specific file to what it looked like at $date or file version

I have the feeling that the developers of git even understand this, but they needed to get git out the door and assumed the community would build the layer atop git to make it more user-friendly. Sadly, attempts to make git user-friendly have so far boiled down to GUIs rather than introducing new concepts. Certainly the current collection of shell scripts that exist as the ui for git definately have a hackish feel to them.
I think the explosion of the internet sort of squashed some of the great distributed feats. Having blazing fast internet connections (at least relative to source code transfer) available all over the world makes decentralization less important (in the normal pull, change, push model)
Yeah, fast internet helps a lot, but being able to grab open source code, work on it, and then push in changes with something better than an email of diffs is certainly nice. The technology of pull requests/cloning has a lot of advantages when you want code to cross organizational boundaries.
I suspect this is highly subjective. I learned git when I barely understood programming. Figured out the basics and went from there. It’s never gotten in my way. I don’t deny it’s been confusing at times, but I’ve used svn and hg and had a similar experience. People seem to have highly variable experiences of it - maybe due to how they think, or perhaps an element of chance and first impressions?
Directed Acyclic Graphs and SHA hashes are not hard concepts to understand. From that every commands make sense very quickly.
>Directed Acyclic Graphs and SHA hashes…

… of what, though? On GitHub, and on every other project I've worked on that used git, the natural unit is a set of changes (e.g. a GitHub PR, a patch). If you run `git show $SHA`, git will show you a set of changes. But that's a lie; that's not what git stores.

If you run `git log`, it'll give you a list of commits. If you run `git show` for each, it'll show you a bunch of changes. Many users expect (quite reasonably, before they've been bitten) that if you start from scratch and apply those changes in order, what you end up with will be the same as your current tree. Nope.

> the natural unit is a set of changes

What "natural" does even mean? That's a vague philosophical argument. And even then, all versioning systems deal with versions, not changes. Changes are relative to different versions. This is true even for SVN. Changes are always relative, it doesn't make sense to track them as the based unit conceptually or even for performance. Different versions implies change, not the other way around.

> If you run `git show $SHA`, git will show you a set of changes. But that's a lie; that's not what git stores.

Each new version will bring a change. This is not a lie. Sure it could show the entire corresponding tree by flooding your console, or it could be more practical and merely show the diff from the previous parent(s). This is the kind of thing that people who do not bother to take the time (about one hour) are stuck with. Don't worry, it's not that hard.

> Many users expect (quite reasonably, before they've been bitten) that if you start from scratch and apply those changes in order, what you end up with will be the same as your current tree. Nope.

The author, the date and other data about the commit do matter. If you rebase your commits, which is effectively applying those changes in order, then very very likely you will not have the same snapshots of the filesystem. And even if the filesystem remain the same, the data about the commit will be changed. It seems that your expectations of what a CVS "truly stores" is naive and based on a lack of experience.

> And even then, all versioning systems deal with versions, not changes.

No, Darcs and Pijul (for which I have high hopes, though it's not ready for prime time) deal with changes.

> It seems that your expectations of what a CVS "truly stores" is naive and based on a lack of experience.

Thanks, but attempted insults notwithstanding, I know what CVS truly stores, and what SVN, RCS, SCCS, git, Mercurial, darcs, and pijul truly store. (I admit I don't know what Perforce or ClearCase truly store, or others I may have used too little to recall.) And before SCCS I knew what a stack of labelled backup tapes truly stored, though I wasn't _quite_ as proud as git of my fancy labels.

> No, Darcs and Pijul (for which I have high hopes, though it's not ready for prime time) deal with changes.

I didn't know about them. From what I read, Darcks is slow and Pijul doesn't really bring anything new to git and seems to "solve" the problem not being based on patches while not really doing better at what git already solved. At the end of the day, both can compare what was applied and what wasn't but the algorithms used around it are just more complicated no good reason, this means less tools and less community support.

An easy dismissal without any solid arguments. First, saying "Darcs is slow and Pijul…" is strange, since Darcs and Pijul aim at solving the same problems.

Then, Darcs has never been slow for me, I've been using it for about 15 years, I can remember of one minor performance issue. It doesn't scale well to very large projects, but there are extremely few of them. Since concrete arguments are important when discussing with others, the main event which started Darcs' decline was its inability to handle conflicts in GHC (the Haskell compiler), which was at the time the open source project with the largest history (as measured in number of patches).

As for Pijul, I'm curious where you got your information from. I know Pijul's authors well, at least enough to know that they are well aware of the algorithms used in Git. Pijul does solve a number of problems:

- I know at least one very large-scale project where collaborators are well aware that 3-way merge can mess with their code in really bad ways, and complain about wasting tons of time with that. Unfortunately, I can't embarrass the project's authors by sharing their name, but I can say that it is a widely used piece of software with a really long history.

- Knowing that the code you review is the code you merge is the only thing you should care about if you care about your code at all. This is not what 3-way merge gives you, as the Pijul manual clearly explains (see "lack of associativity").

- Patch commutation is what Git tries to do all the time (rebase, merge, rerere…), except with bad hacks which fail in the more complex situations, which is where we need them the most.

Creating patches out of commits and commits out of patches is trivial in Git. I don't see what patch based systems bring more except more complicated algorithms. In the end I want to checkout revisions. Maybe they are equivalent is some respects, but then Git works, is fast and is widely supported by various tools and extensions and if you take one or two hours to learn the documentation is actually intuitive.
First, congrats for replying to a comment asking you for concrete arguments without using any of those, nor replying directly to anything that was said.

Then, I don't think you actually understand what we mean by patches: for anyone who has looked into the topic, patches are obviously not equivalent to commits except in the most basic cases (where all tools "work", in your own terms).

A datastructure is defined only with respect to the operations you define on it, I'm sure you use other commands than checkout. For example, people who review snapshots rather than patches before a merge (or even a commit!) either have really small projects, or way too many man-hours to spend.

> if you take one or two hours to learn the documentation is actually intuitive

Git isn't "intuitive" at all for anything but the most basic operations (I agree it is easy for those, if you are willing to work with snapshots). For example, the existence of `git rerere` clearly shows that Git doesn't model conflicts at all. Then, merges are not unique, Git chooses one at random when there are more than one. Rebase is a horrible hack, "replaying" commits doesn't even always work.

Moreover, saying Git is easy isn't a very effective way to show off on HN: if you feel you have to defend Git so strongly, even though it wasn't actually attacked, and to the point of refusing to reply directly to any rational argument, it clearly shows you invested enough time in Git to feel you would lose something if you had to move to a better solution. So, sorry, but I don't think it was just "one or two hours" for you.

I agree. The reason why it doesn't feel that way is because of the wealth of tutorial website on how to run git commands or the users already got used to it.

Mercurial names are much more natural but it lost the war already.

I use git every day and don't complain when using it. But when a junior is learning git, you start seeing the oddities.

Well, whatever the article says, isn't the actual reason "we have this other one we built using SQLite"?
It does come off as excessively NIH, with the first point even just being a client UI complaint.
Well sqlite is more of a passion project than about doing things in the most capitalistically efficient way right? So "it makes me happy to invent things here that scratch my itches just so" is a valid reasoning.
SQLite is in every phone on the planet and the author has a company that makes money selling it to environments that require extensive validation (eg airplane software).

It's not a "passion project" by any means. It's a highly developed, well engineered piece of software and there's lots of other non "passion projects" that would do well to learn from it.

D. Richard Hipp has mentioned that SQLite and the TH3 test suite were heavily inspired by DO-178B, but none of the core SQLite developers have been involved in a DO-178B certification nor has anyone purchased the TH3 test suite. Furthermore, SQLite by its nature is not fit for hard real-time systems since it cannot guarantee the execution time of an arbitrary query and/or an arbitrary dataset.

I don't mean to disparage SQLite in any way, it is quite the achievement, but your characterization is mistaken.

If the end result weren't so stable and high-quality, I might agree with you. But Fossil has become my VCS for personal projects because I can host a repo-farm trivially through CGI on my webhost, and it includes issues/wiki/forum. This makes me feel like Fossil has carved out a nice niche for itself that provides a real benefit for at least some folks, rather than simply being a reactionary project motivated because git was written elsewhere.
I don't get that at all. To me the answer is "we want things out of the vcs that we don't get from git nor github/gitlab."

The fundamental difference is: sqlite is a cathedral, git is for bazaars. That's kind of a big deal.

The reason is they didn't need the complexity of the git model. They came up with their own way of doing it and there's nothing wrong with that.
I can’t recall where, but I think I heard Richard Hipp say that developing Fossil helps the SQLite developers dogfood SQLite. There’s certainly some synergy between the projects.
> Git does not track historical branch names

That's my biggest pet peeve on this list. Git branches are really just pointers to the HEAD of some commit history, but if you've had a bunch of merges in the past it can be very difficult to tell which commit belonged to a particular branch at some point in the past.

Is there a good solution for this? Seems like it would be trivial to add a piece of metadata about which branch someone was on when a commit was made.

Git _does_ keep track of historical branch names. It is called the reflog. For each ref there is a log of what commits it pointed to. See `git help reflog`.
The reflog is

  1. garbage collected
  2. local only
Also the branches are indicated at their positions at the moment you call reflog, not as they were for each operation of the log.
If you keep your history linear by using rebase only, then this becomes a non-issue.
This actually makes it much harder to answer the question "What happened with the branch of X name 2 years ago?"
What is the value of that information? When I’ve looked at older commits, I either want to know about the resulting code or the context (e.g., motivations, discussions). A fixup commit, or some other intermediate commit isn’t useful.
If you always rebase, aren't you hiding even more of the history than if you have unlabeled branches?

I have to admit I've never understood the point of keeping the history linear.

I find it easier to read linear history.
Could that be because if the history isn’t linear then it’s difficult to read, precisely because of the reasons given above, which would mean you have the same problem but you’ve simply decided to avoid it via a (legitimate) workaround and not complain.

That wouldn’t make the complaint invalid though.

I have to admit I don't fully understand the problem as originally formulated. I've never had trouble figuring out what's going on in a Git repository. I do agree that GitHub's interface for these things is anemic. As for that part, I typically squash-merge on GitHub and that links to the PR, which is good enough for me.
And that goes for this Fossil too. When I look at the SQLite timeline, I see confusing swimlanes. I can't make heads or tails out of some of it.
You're also hiding history if you repeatedly edit the code while you're debugging it, and sometimes undo 17 changes and re-do them differently in your edit buffer and such.

A True Scotsmans non-history-destroying version control system would reveal and be able to replay every single editing keystroke that went into a change.

I think you're misunderstanding what's meant by history. I don't care at all about your local history while working on a feature. I care about what code existed where and when in multi-branch workflows and making sure merges are easy to follow when integrating changes from multiple long-lived branches.

If your workflow is single branch all PRs merge into main then of course you want to rebase since the only thing that matters to your history is "when did this batch of changes land in main"

I mean, it would be good to keep that locally too.

But that's all local stuff. It doesn't matter if you delete something nobody else ever saw.

Branches are very often passed around to other people, examined and validated in that form. Rebasing a public branch loses some amount of important history. And even for private branches, if you rebase multiple commits at once then the testing you did between those commits gets invalidated.

Does fossil have a way to rebase or ammend commits on a local branch though? My understanding is it doesn't.
Fossil does not have a "rebase" command, but anything you can do with rebase you can do in Fossil, and more.

Fossil allows you (for example) to fix typos in the commit messages of published branches, safely and in a way that does not destroy history and propagates cleanly with "sync". It allows you to modify the DAG safely, and in a way that does not destroy history and propagates cleanly. It does this by providing special tags that when added to a commit change the check-in comment, or branch name, or parents of the commit. The original immutable check-in is preserved, but for display purposes, the tags can override some properties of the original check-in.

Real example from just this morning: Last last night I mistakenly merged the wrong way. I merged the reuse-schema branch into trunk, rather than merging trunk into the reuse-schema branch. When I saw the problem this morning, I was able to fix it, even though this mistake had already propagated to other repositories. The change entered the DAG as a supplemental "correction" tag, so no history was lost, and if in 20 years somebody wants to go back and figure out what happened there, they can, because all information is preserved. But for day-to-day viewing of history, it looks as if I had done the merge correctly to begin with.

What about shun and scrub? Those can be similar to some common uses of rebase.

And I really am curious: why preserve the incorrect merge? What scenarios involve needing that information, why is that ever a good thing? If the default view of history doesn’t present these preserved mistakes, how is that really different from a rebase?

I’m also troubled by the language about “immutable” history and “destroying” history. Git doesn’t destroy any history. When you rebase, it creates a new branch. The old one is still there. You can get it back. The only reason it goes away is because it gets garbage collected later, because the user chose not to have anything pointing to it.

The incorrect merge is preserved because that is what actually happened. The incorrect merge was published. People saw it (and commented on it in the SQLite Forum). If I "disappear" the merge, that would be airbrushing history. The correct solution is to fix the problem, while maintaining an immutable audit trail, not to delete the problem.

When I was in high school, I was taught that if I worked as a bookkeeper and I make a mistake, I should never erase the mistake. Instead, draw a line through the mistake, notate what is wrong, and enter a correction. To erase an entry in the financial ledger of a company is fraud. It is a felony. Making a correction is fine. But do not erase. Always preserve an audit trail.

I believe that VCSes should be treated similarly. While you are assembling a change, you can make as many erasures and corrections as you like. But once you commit the transaction - once you check-in the change - it then becomes part of the permanent record. To alter that transaction after the fact is akin to felony fraud. Sure, mistakes happen. By all means, correct the mistakes. But the original mistake and the correction should all be part of the audit history.

If you want to say that commits to your private branches are not part of the permanent record, and that you should therefore be permitted to edit those private branches, then I think you have a stronger case. That does not come up as much in Fossil. Fossil does support private branches, but they are seldom used. The usual case in Fossil is that all check-ins auto-sync up to the parent repo.

Shunning is not quite the same. Shunning is a mechanism for removing illegal are illegitimate content. Shunning is sometimes required to comply with legal mandates. But it is not a part of day-to-day practice. Shunning is an exception - and escape valve - undertaken only in an emergency.

As I was reading your comment I caught myself thinking this was a post defending git but then I saw you username. All of what you mention are what git allows to do and also how git is used 99.9% of the time. I can't help but notice your lack of experience with Git, and I say that very respectfully.

Most organizations' repositories will have one or more protected branches (e.g. master). What is published there remain. Even mistakes. When the history on those branches are erased it is for very good reasons only. Usually it involves the size of the repository getting too big, illegal / private content and paths only differing by lower and upper case messing with Git on Windows. Even in those very rare cases the history of the vast majority of the files remain. And this is also something all CVS has to face so this is not specific to Git itself.

Dev branches are pushed, overwritten and erased. I don't see how that's a problem. In the end having small intelligible commits that reads like a dish recipe accelerates code reviews and corrections and I haven't seen any other VCSes doing that as efficiently as Git.

> Most organizations' repositories will have one or more protected branches(e.g. master)

If you're using git, everyone has a local repo, and that repo's master branch is local: they can rewrite their unpublished content in it however they want. It's really quite convenient; a good feature of git.

An automatic merge is just some algorithm's often poor idea of how some parallel changes should be integrated. This has to be verified by a software engineer and put through QA, and adjusted as necessary so that it works to the best of everyone's knowledge. Then you publish the result as the result of the merge.

If you commits the result of a merge before doing anything with it to fix it up, that implies that you will sometimes be committing non-buildable code which still contains conflict markers. That's not even allowed under a continuous integration policy that every build has to build (and pass unit tests and whatnot).

What actual reasons do you need to preserve your merge mistake? When will it be needed again, and what for? Why should people who saw it need to see it again later? Do they want to build the code with the mistake, or do they just want the fix? Who is going to look for the mistake? Who is going to complain if they can’t find it?

Git doesn’t erase mistakes. It presents a second, separate graph of commits after rebase than before. Both graphs are still there, nothing is erased, and nothing is destroyed. It’s quite important, as a VCS, that nothing is destroyed because it means if I do it wrong, I can undo.

> To erase an entry in the financial ledger of a company is fraud. It is a felony. […] I believe that VCSes should be treated similarly.

You want people who fix code mistakes to go to jail if they don’t keep a record of the mistake? Why? There’s a very, very good reason that actually lying on financial ledgers is illegal, while quietly fixing a merge mistake is not. You are conflating so many things in this broken analogy that it’s difficult to respond to.

Financial ledgers are one of the very few things in the world where history is required by law to be sacrosanct, and companies know this and agree to it in advance. The number of editable things in the world that aren’t expected to preserve history and aren’t illegal are uncountable. Nobody’s going to jail if they erase a bad chapter in a book or movie script. Nobody’s committing a felony if they tear down a house and rebuild it. Nobody is being called a deceitful liar when they erase a mistake on their math test and write down the correct answer.

Your belief was not shared by the designers of git (nor of any other DVCS before Fossil). This is the core of why your claims about git are wrong. No promise was ever made to preserve history as it happened, that was never part of the intent in its design. Therefore the very argument that git is being deceitful is a dishonest argument - it’s a projection of your personal goals onto other people and other’s people’s software, not a true story about why git was designed the way it is. The fact that your telling is motivated by trying to convince people to use Fossil over git just makes the hyperbolic framing seem extra cheesy.

> If you want to say that commits to your private branches are not part of the permanent record, and that you should therefore be permitted to edit those private branches, then I think you have a stronger case.

That is, in fact, the primary use of rebase, by a mile. I’m certain you already know this. Which is a big part of why all the hyperbole about fraud, lying, deceit is ironically not an honest narrative.

> Shunning is a mechanism for removing illegal and illegitimate content.

So is rebase. Sometimes that’s how it’s used. Maybe it happens, but I’ve never seen public history intentionally rebased other than in emergencies.

So what, exactly, is preventing people from using shun for legitimate content day-to-day? Are you policing it’s use?

> You want people who fix code mistakes to go to jail if they don’t keep a record of the mistake? Why?

Are you actually unable to engage in a significant discussion without using strawmen?

Maybe. You? What’s the straw man? @SQLite said quite clearly they believe failing to keep immutable history should be treated the same as failing to keep a financial ledger, and that editing ledgers is a felony. What other conclusion did you reach? Have you read the Fossil docs that talk about git? Do you believe they are accurate and justified?
Should be treated similarly, in terms of taking it seriously.

"it should be a felony" is definitely a strawman.

Mine was a serious question about what, exactly “similar” is supposed to mean.

You are presuming to speak for @sqlite by claiming they did not mean felony, when the very example they provided of what it means to take it seriously is that it’s a crime.

What makes you certain that they weren’t suggesting exactly that?

I don’t think it’s fair to call my question a straw man. @sqlite has been making a strange moral argument out of git rebase for many years. I honestly want to understand where it’s coming from.

Fwiw I also don’t think it’s fair to ask a bullshit adhominem straw man question like “Are you actually unable to engage in a significant discussion without using strawmen?”

> What makes you certain that they weren’t suggesting exactly that?

Stop it stop it stop it.

Stop it.

Stop what?? What are you talking about? Did you read @sqlite’s comment? “To alter that transaction after the fact is akin to felony fraud.” https://news.ycombinator.com/item?id=29133758 @SQLite literally said editing code history should be considered “akin to” a felony. It seems like you’re misunderstanding me because you’re misunderstanding @SQLite.
It's not even remotely similar. If you're developing a program, you're not legally required to show anyone any version of the source code at all (without some court order or something).

If it the program is open source, you're legally entitled to have an FTP site where only the current version of the files is available, and yesterday's version is gone. Moreover, you actually don't have to have yesterday's version retained anywhere else. Obviously, that will cause problems for you.

In between that extreme, and the other extreme (every little thing being fastidiously recorded and immutable) are rationally workable alternatives that allow reasonable mutation.

As an employed developer or contracting consultant, you may be required to adhere to certain version control practices as part of your contract. If that doesn't rule out revising history, you can revise history.

Too late to edit my comment, but why don’t you go back and read @sqlite saying about code: “To alter that transaction after the fact is akin to felony fraud.”
> If you want to say that commits to your private branches are not part of the permanent record, and that you should therefore be permitted to edit those private branches, then I think you have a stronger case. That does not come up as much in Fossil. Fossil does support private branches, but they are seldom used. The usual case in Fossil is that all check-ins auto-sync up to the parent repo.

This is probably one of my biggest problems with fossil. It is very opinionated about the workflow you use. My typical workflow involves making many commits on a private branch while working on something, many of which won't be able to build or pass tests, and then clean everything up before pushing to a publicly visible branch. This allows me to easily roll back if an approach ends up not working out, or cherry-pick smaller changes to other branches if a change ends up being needed in multiple feature branches in progress at once, etc. With git that sort of workflow is trivial, with fossil, it might be possible, but it doesn't fit with fossil's blessed workflow.

Git on the otherhand is pretty flexible, and can be used for a lot of different workflows, and doesn't push you towards a specific one.

I kinda hope you’re being sarcastic, but it doesn’t sound like it, so I’ll respond with a straight face. Why would anyone ever want to capture typos, especially if they never got saved? I definitely don’t want that kind of pure noise when I review changes.

The context & argument you’re repeating here but either missing the true essence of, or teasing about, is the view that since git rebase edits commit history it is bad. The Fossil devs have long been advocating this view using hyperbolic language like saying git is ‘lying’. This unfortunately incorrect framing stems from Fossil having different goals and assumptions than git, and the Fossil devs projecting their dogmatic views on their perceived competition.

But… even the Fossil devs are not actually advocating capturing every single keystroke.

He's not being sarcastic I think.

The point is people talk about rebasing and squashing a commit with a typo, and then people argue against this because it's "rewriting the history". But, as you say, why would anyone ever want to capture that typo?

I actually managed to get Dr. Hipp to slightly soften the language on the Fossil page once, in a thread right here on HN regarding git. I’m a huge fan of his work and SQLite, and respect him a lot, but I think the git is lying thing is a terrible tactical mistake backed only by assumption and (possibly willful) misunderstanding, and just needs to die. Fundamentally, git consciously and intentionally provides tools to edit history. It’s fine, it’s great, to write a new tool with a new goal of making history immutable. That’s awesome. But that does not mean git or the people who use git are being “deceitful” and it seems a little bogus to throw around that kind of judgemental hyperbole, especially when there’s an underlying competitive conflict of interest.
> I actually managed to get Dr. Hipp to slightly soften the language on the Fossil page once, in a thread right here on HN regarding git

He did because AFAIK he's an extremely nice guy who gladly suffers fools; I guess that's for ideological reasons, and that's his choice.

I found your own participation in the whole ordeal deeply insulting. But, again, that's me exclusively. I'm just a happy Fossil user.

I understand your emotional reaction to me criticizing Dr. Hipp. Believe it or not, I have no doubt he’s a nice person, and I mean it when I say I respect him. But you seem to be making assumptions and defending him reflexively without knowing what happened in the past, or even really understanding this argument. You haven’t explained your insult, therefore I suppose I have no choice but to ignore that remark. I made a very small amount of headway before because he agreed with me that I was right about one very specific piece of the exaggerated language on Fossil’s web page. He has, however, and despite my pointed questions, held firmly to his belief that editing commit history is lying and should be considered a crime, as demonstrated here.

Look, I think it’s absolutely great if you like Fossil. And I also think it’s great if Fossil has immutable history and cares about it deeply. My beef here is with saying that git rebase is a “lie”, being “deceitful”, “fabricating” things, etc. That is an untrue claim, it’s ironically itself completely dishonest.

If you like Fossil and want others to use it too, it might be worth reflecting on how Fossil’s marketing pages are actually pushing some people away from trying it. That’s what the claims about git really are: marketing.

The dogma that allows someone to go around calling others a liar over the tools they use to write code is what’s deeply insulting, and Dr. Hipp has had far, far more influence already than I ever will. You can stand next to this dogma if you like, but I think you’ll be on the wrong side of history. For now, blind followers everywhere like to parrot the claim that git rebase is a lie, without being equipped to defend this idea because they don’t actually share it deeply and haven’t been thoughtful enough on their own to understand the implications.

> Why would anyone ever want to capture typos, especially if they never got saved?

Thus why would anyone ever publish bad versions of private commits in an anonymous, unpublished branch that were locally rewritten N times?

I don’t understand what you’re trying to say. I don’t want to publish bad versions of private commits. That’s a reason to rebase. I like cleaning up local changes before publishing, and I like it when other people do too. I want to understand and preserve the semantic content of changes, not some useless timestamped log of every keystroke.
> the Fossil devs projecting their dogmatic views on their perceived competition.

Meanwhile, you project your disdain towards Fossil in your own hyperbolic comments and the use of intentionally divisive words like "perceived competition". Fossil is not competing with anyone.

> Fossil is a distributed version control system (DVCS) written beginning in 2007 by the architect of SQLite for the purpose of managing the SQLite project. Though Fossil was originally written specifically to support SQLite, it is now also used by countless other projects. (Fossil docs)

I'm not speaking for the Fossil project, but I'd bet that the only undesired consequence of Git's existence in their minds is the unfortunate phenomenon of ocasional Githeads stumping into Fossil's forums, foaming in the mouth about how Fossil is All That's Wrong in the Universe and how its existence is unbearable unless they change it to be more like Git.

Yeah, I can use hyperbole too. How nice!

> Fossil is not competing with anyone.

False. This page is proof. https://www.fossil-scm.org/home/doc/trunk/www/fossil-v-git.w...

> I’d bet that the only undesired consequence of Git’s existence in their minds is the unfortunate phenomenon of ocasional [sic] Githeads stumping into Fossil’s forums

Wrong again, you lost that bet. You owe me a beer. https://www.fossil-scm.org/home/doc/trunk/www/rebaseharm.md You need to actually read the Fossil pages first to understand what this argument is even about. You are providing evidence that you’re just attacking me without understanding the history.

> I can use hyperbole too.

Do you realize that you’re totally validating my whole argument? Because you’re calling my argument hyperbole and a straw man, when I’m accurately describing what Fossil and it’s author have said about git rebase, without realizing it you are agreeing with me and disagreeing with @SQLite. You claimed that my question about rebase being a felony was a straw man, when in fact that’s exactly what @SQLite said literally. You called @SQLite’s idea ridiculous, not mine. You are disagreeing with the core belief that Dr. Hipp holds that modifying code history should be at the level of a criminal offense.

I’m upvoting you because you are proving my point.

Someone was complaining that git's non-recording of what branch name a commit was done in can make it hard to figure out the history. Then aaaaaaaaab mentioned that not having branches solves this problem.

I don't see how that helps the problem.

One of git's goals is to record the history of a project, and one can argue that that feature can be improved.

I think recording every typo would be worse, as it becomes harder to find the edit you're looking for. More hay covering the same needle.

I don't think rebasing is a bad feature, but I think merges and branches in the history provide o more useful story of how the code was written.

But unpublished branches don't make sense to fuss over. They contain the rough "manuscript" revisions with the typos and whatnot.

If a branch is public and is merged, then we need to preserve the original and track the relationship.

Git is fundamentally broken with both rebase and merge.

If we consider a branch which has a single commit, then rebase and merge achieve something very similar. The text is merged and a new commit is created. The target branch head is updated to point to that commit, which has the previous head as its leftmost parent.

The merge version will record two parents, whereas the rebase (actually a cherry-pick under the hood) records only the destination branch parent. This omission is unfortunate for the rebase.

What people do when rebasing an already published commit is put something in the commit message like "Cherry-picked from <SHA>", which really wants to be a parent pointer in the meta-data, so that it shows up under "git log --graph" and such.

On the other hand, if we merge multiple commits, rather than rebase, another idiotic thing happens: a single, squashed commit gets created out of the merge result and planted into the target branch.

We need a flavor of git rebase which records a parent pointer for every single cherry-picked commit. That will create a merge which makes sense. Merge a feature branch with 7 commits, and you get 7 individually merged commits, each with a parent. (Or, maybe you will just get six: perhaps one of them became obsolete and was skipped.)

Also, if commits have additional parent pointers, then any editing workflows involving rebase should preserve them. Say I locally merged the foo-feature branch into master. I now have 7 new unpublished commits coming from the merge. But, uh oh, the merge was actually bad. While textually it went fine, something is wrong and needs to be fixed up. Say I need to reach for interactive rebase to manipulate these 7 commits; maybe adjust something in the third one. This interactive rebase job should preserve the above-described parentage.

These are mostly straw-man arguments. People don’t generally rebase published history unless there are mitigating circumstances. It’s not common, and it’s not recommended. Rebase is for cleaning local history before pushing it to anyone else. Similarly, git does not squash commits upon merge unless you ask it to, that is not some idiotic thing that just happens.

BTW, Fossil has commands called “shun” and “scrub” that do effectively rewrite history. Every version control system has them, because you have to have them. Being on a high horse over rebase is 1- not going to change rebase, and 2- makes it seem like you don’t fully understand git, and it’s design decisions and goals, therefore not qualified to opine on it. See Chesterton’s Fence.

All of this is mostly irrelevant to getting coding done. Wanting immutable history is fine, if that’s what you want. I’ve never heard a compelling reason to need it, and it’s not one of git’s goals, and never was. (Nor was it a goal of any other version control system either, not of svn or p4 or hg or source safe…) Git is version control, and it does what it was designed to do which is keep multiple versions around, let you share versions with other people, and be a safety net against code loss. I can’t think of a single time in my decades of professional software career where it mattered that someone edited their local history before pushing, and/or didn’t preserve some strange sacrosanct history of the exact order every line of code was written. I don’t have anything against holding this goal, but I’m unconvinced that it’s relevant.

Git users rebase published history all the time. What they don't do all the time is just don't plant the rebased history under the same head; moving that head that way would then be the non-fast-forward change, not the creation of the rebase per se.

> I don’t have anything against holding this goal, but I’m unconvinced that it’s relevant.

I am likewise not convinced of the value of immutability.

I see the git repository as an object being edited, and that object has no history of its own. When we add a new commit, say, we are making a new version of the whole git-object which now has some new objects in it, plus a moved head.

The old git repo in which that head pointed to the previous commit doesn't exist any more. Well, some people have copies of it. They can stick with those, or get this one. Take it or leave it.

We should be able to control any aspect of our work. If I want to rewrite thousands of commit messages in the published master branch, that's my privilege. Git deals with this just fine; someone who fetches that is informed that their master is divergent by thousands of commits. They can disagree with what I did and then just cherry pick things onto the original branch going forward.

> I have to admit I’ve never understood the point of keeping the history linear.

Bisect, blame, and log, among other features, are all easier to use with a linear history. They’re not unusable with non-linear / many branches, just easier linear.

I’m not quite sure I understand your comment though - it implies that you consider linear history to be a strange and/or non-default thing to do. What’s the implied point of not keeping the history linear, or what is your preferred workflow? I’m not entirely sure what’s being compared, but linear is the default you get from more than 1 commit. Linear is very natural with a team of one or only a very small number of people. Linear is a lot nicer than branchy for branches that have exactly 1 commit.

Ok, that makes sense.

> I’m not quite sure I understand your comment though - it implies that you consider linear history to be a strange and/or non-default thing to do.

Sometimes you get a branch, I get them even on personal projects if I forget to push and work on a different computer.

I've heard people say that, when they do get a branch, they will rebase to make the history linear instead of having a merge. I don't think that is default.

There are two solutions that come to my mind, both are more by convention:

1. Always use merge commits (--no-ff) a la git flow, and leave the branch name in the merge commit. That doesn't get you the branch name on the commit, but it should help identify the branches.

2. Use a pre-commit hook to put the branch name or bug tracker ID at the bottom of the commit message. There are some tools built around this, I've done it at $DAYJOB with a custom python script I manually copy around into `.git/hooks/pre-commit`.

Good solutions. FF/rebase are very nice, but I've seen devs sleuth into a squashed PR commit, find the PR the features came from and read it on GH, and that's powerful.

I saw a new dev do this recently. They dug into the original summary of the changes from the dev (for a PR that landed 6 months before they joined) and the flow of conversation around the work. They had insights into the decisions the team made around the feature as it was developed. The PR linked to the product artifacts that led to the work, so they had the business context. They nailed the implementation, first time :-)

There's a nice benefit to doing merge/squash and providing a link to a set of context around the specific set of commits, not just a contextless line of commits, as clean as it may be.

Git merge does something pretty awful; it takes multiple changes and turns them into a single patch bomb in the destination branch.

What if the branch has 17 commits, the 9th of which introduces a regression? Moreover, suppose that the 9th commit of the original branch didn't exhibit the regression; rather, its change had that effect when it was merged into master.

You need all 17 commits, in their rebased versions, on master, so you can search through their history (e.g. with git bisect) and discover that the 9th one broke it.

Rebase is the correct thing: it calculates a new sequence of commits that are individually merged, and retained as separate commits that you can dig through in the new branch.

What's missing is this: the rebase of an entire branch into a new branch should record a second commit parent (for the final commit of the operation), pointing to the final commit of the original branch.

Like this:

          X-Y-Z--<< branch
         /
   -A-B-C-D-E--<< master
rebase it:

           X-Y-Z--<< branch
          /     \___
         /          \
   -A-B-C-D-E-X'-Y'-Z'---<< master
where X', Y', Z' are the rebased versions of X, Y, Z.

A regular git rebase is missing that second parent link from Z' to Z. You just get this:

           X-Y-Z--<< branch
          /
         /
   -A-B-C-D-E-X'-Y'-Z'---<< master
The only way you can identify that Z' was cherry-picked from Z is by clues in the commit message: identical commit message text, or something like a Gerrit Change-Id.

Possibly, each cherry-picked commit should have the original as its parent:

           X-Y-Z--<< branch
          / \_\_\___
         /    \  \  \
   -A-B-C-D-E-X'-Y'-Z'---<< master
now that is almost like iterating over the branch and doing a commit-by-commit merge.

At first we pretend that the branch is just X, and merge it to get X'. Then we merge Y', and then Z'. We never merge a sequence of two or more commits into one.

If you do that, you have both: nobody can say you're not merging, but you have the effect of a rebase.

A rebase (cherry-pick) is a kid of merge: of one commit (at a time), without recording all the parents.

A case can be made for rebasing commit-at-at-time using merge. (Not for private work, obviously; just already published, permanent history).

The nice thing about rebase is that it doesn't introduce the crufty parentage, which makes it ideal for rearranging unpublished history and then presenting a clutter-free end result.

> What if the branch has 17 commits, the 9th of which introduces a regression? Moreover, suppose that the 9th commit of the original branch didn't exhibit the regression; rather, its change had that effect when it was merged into master.

For some developers, the commit is the cohesive unit of change. For others, the PR as a whole is the cohesive unit of change. I fall into the second group. The ninth commit of my branch is meaningless -- it's only the branch as a whole which can be understood as a single coherent thing. Squash merges reflect and support my methodology.

I also have found myself in a shop that uses this flow, and don't get me wrong, it works pretty darn well, but it's also just turns PRs/branches into commits and is effectively a single-branch linear workflow with extra steps. It's the closest thing to not using git that exists.
> it's also just turns PRs/branches into commits and is effectively a single-branch linear workflow

Yes! This is ideal.

This is Continuous Integration or Trunk Based development, and it often shows up in surveys as being a very effective tactic.
> It's the closest thing to not using git that exists.

Totally disagree, because the whole reason for this is to support multiple developers working simultaneously of the same master branch. That is, sure, master may just be a linear history of commits, but at any specific point in time there may be 10 feature branches off master, each from a different branch point.

Factually, the commit is the unit of change.

(Gitwise-factually, a commit is a snapshot, not a change, but a new snapshot represents a change relative to some other snapshot, like any one of its indicated parents.)

Your "methodology" is not rooted in facts.

It can be described as wanting every version control to be CVS.

Back in the day when those kinds of systems were widely used, the most common complaint from knowledgeable CM people was that there are no change sets: related sets of changes treated as a unit which contains the fine-grained changes, with individual descriptions, references to tickets and so on.

If we regard a feature branch as a change set, when you do a squashing merge in git, you're vandalizing the change set; the merge you're doing is only slightly better than "cvs -j from -j to" (merge the delta between from and to onto the working copy). How it's slightly better is that it records the extra parents, for tracking.

One of the main improvements in git over things like CVS and Subversion is that you can at least halfway simulate change sets, due to the relative ease of manipulating individual commits and the scripting done around it (like git rebase scripted around cherry-pick).

I think we're just speaking at different levels of abstraction. I agree that, concretely, a commit is a Git domain concept that signifies a unit of change, and has certain properties and relationships to other domain concepts. But in the context of my project, I get to assign whatever semantics I want to that lower-level concept. So a commit for me is more of a time-based snapshot of my work in progress, rather than a single unit of software or project change. That's what I'm speaking to.

> If we regard a feature branch as a change set, when you do a squashing merge in git, you're vandalizing the change set

I'm not. The change set is atomic, the individual commits are essentially implementation details which the PR encapsulates, and when it's merged to main those details become opaque. I mean this is just my methodology, it doesn't have to work for everyone but it's the natural expression of my work for me.

Yes, there are different levels of chunking we can consider: a branch is a change, and a commit is a change.

Be that as it may, a squashing merge is focused on one level of abstraction and mostly poops over the others.

The nice thing about levels of abstraction is that we can have them all and preserve them.

Commits which you did not actually produce as part of a merge are not an implementation detail; something which isn't there does not provide implementation. Opaque implementation details are something which exists; they can be looked at debugged into.

I'm clearly failing to communicate my intent here :) If I don't treat a commit as a meaningful layer of abstraction, then it isn't one. If I say a commit isn't meaningful then it isn't; Git's semantics are secondary to mine. Right? Is this controversial?
Yes, seems to me it is controversial if you then also complain about not being able to see exactly where -- in which commit -- some breaking change happened. Doesn't that mean commits are actually meaningful to you; why else would that be what you're looking for?
Commits aren't meaningful to me. Breaking changes are properties of PRs, not commits. But I basically never care about breaking changes, because they shouldn't ever get merged to main. CI should have prevented that outcome.
As a variant of option 2, could one create a new tag at the pre-merge commit?
We do exactly that. If you are on the main branch and merge "feature/my-feature", we use an bash script to create a annotated tag called "integrated/my-feature" which replaces the feature branch. So on our clients it looks like we have a tag folder "integrated" with all previous branch names.
The Gerrit review system tags every change (i.e. commit) with a durable Change-ID, which is represented int the log message, usually as the last line, like this:

  Change-Id: I7321a7fddab667af7a418eeeb7d48c0240570260
The Change-Id will be the same whenever that commit is cherry-picked anywhere, even if it has to change due to merging. It is not a hash, but a random UUID.

If you trowel through the log messages you can find the places where that change has "been" by looking for the Id.

A common problem when using Gerrit is the Change-Id being copied across from different branches (via, for example, git cherry-pick).

The idea is ... interesting, but the implementation of Change-Id has quite a few problematic corner-cases which make normal git operations (rebase, cherry-pick, merge) more delicate than the need to be.

> Seems like it would be trivial to add a piece of metadata about which branch someone was on when a commit was made.

I often make commits without being on a branch at all (detached head). I like this about Git.

"When I want to see what has been happening on SQLite, I visit the timeline and in a single screen I see a summary of the latest changes, on all branches. In a few clicks, I can drill down as much detail as I want. I can even do this from a phone.

GitHub and GitLab offer nothing comparable. The closest I have found is the network, which is slow to render (unless it is already cached), does not offer nearly as much details, and scarcely works at all on mobile."

This is a valid point. I've always wondered why it seems Github goes out of its way to hide the typical commit tree navigation that so many git clients support (Sourcetree, gitk, tortoisegit, etc).

Yes! I find it odd. Maybe they just expect you to use one of those clients if that's what you want to see?
That is a good point. I know now when I visit a project on Github that I am seeing the latest version of all files, but that is only because I'm already aware of how git works.
Depending on what the default branch in GitHub is set to you might not be viewing the "latest" version of the files. i.e. the default branch is `main` but all development happens on a long-lived `dev` branch that is only merged into `main` once a month.
Someone who doesn't know what version control is will also just assume they are seeing the one and only version of the files.
It is because the features on github.com directly correlate to a git feature.
Curious: What git feature does Network mirror then?
git log?
Hmm, GitHub Network is much more than log. I think "GitHub Commits" page mirrors git log.
Network is more like `git log --graph --decorate --oneline`. Still git log, just in a slightly different format.
`git log --graph --decorate --oneline` is specific to a branch of a repository. Github Network shows the relationship between forks. It is similar but really the question answered by it is "what and where is the work being done" and "what is the relationship between work being done and this repository I'm looking at". It sucks that Network is buried, I think it should be much more accessible.

Eg https://github.com/sindresorhus/delay/network tells me that this work is being maintained actively, but most forks are not merging back. Another one might tell me work on the main fork is stalled, and many users are now doing PRs against a fork of the original.

Maybe git log --graph --decorate --oneline --all then? Github implements forks as just fancy branches in the same repo. Adding the all param includes all branches.
(comment deleted)
> Network is more like `git log --graph --decorate --oneline`

... across all forks, which makes the UI much more cluttered than it needs to be. What if you are only interested in commits in your own repo?

Github really does seem to lack a clean equivalent of `git log --graph`.

Under the hood, “forks” are really just fancy branches. So realistically that would also be git log
so where’s the one that correlates to git log —graph ?
Click 'commits' on any repo and you will see the graph.
Where does it show the branches and merges?
That would be the network view.
that only shows you inter-repository activity, not the branches within a repo.

that would be worthless for most people, and for the sqlite authors, who'd surely have a million people pressing the 'fork' button.

it also isn't what anyone in the thread, or post, were asking for.

all i've ever seen is something which displays a single branch, and does not contain the graph structure information present in git log --graph.

perhaps you'd be so kind as to provide a link to a page on github which demonstrates the same graph structure?

I’ve never found that either. I try to limit my interactions with GitHub to copying the URL to clone and doing pull requests. GitHub has the same relationship to Git as OverLeaf has to LaTeX: a layer of excrement smeared over and defacing a beautiful program. The saddest thing is that much of the current generation of programmers think that GitHub is Git.
If SQLite used Git, they could self-host a more reasonable web view of the repository using GitView or CGIT.

> why it seems Github goes out of its way to hide the typical commit tree navigation

Wild guess: because those kinds of features requires the back end to execute Git implementation code which can invoke some pretty expensive cases. Imagine that across thousands and thousands of repositories being accessed at once.

They want to steer the user toward doing a clone and doing their own in-depth drilling on the copy.

CGIT caches for better performance; but caches require extra storage and some sure-fire expiry mechanism so it doesn't grow and grow. Caching things for internet rando visitors doesn't seem like a good idea.

> because those kinds of features requires the back end to execute Git implementation code which can invoke some pretty expensive cases

Github has the blame view of files, which is much more expensive.

An ex colleague uses GitHub Enterprise at work, and he reports running into some issues that are never seen on GitHub proper. Most notably, network view of repos and GitHub pages experience extended downtime. Wonder how GitHub manages the uptime of these features for millions of repos because I never see these fail there.
I will note that some features actually don't seem to scale reliably on GitHub proper. For example, the profile pages of prodigious commiters tend to time out on. As an example of one that pretty much always does it, check out https://github.com/scala-steward (not on mobile).
> Imagine that across thousands and thousands of repositories being accessed at once.

Not the idea of a decentralised system, is it?

No; github isn't decentralized, except in the sense of whatever load balancing they do across their server farm.
I have definitely felt this pain when navigating i to the past to investigate the origin and evolution of changes.
At some point in the last year I stopped being able to find the “search for a file” function on GitHub’s mobile site. On the desktop website you can hit “t” from a repo page to quickly search for a file by filename. The mobile website used to have a button labeled “Jump to file” or similar, but now I can’t find that functionality anywhere.
"How should I change to a different branch?" asked the programmer.

"Use git checkout."

"And how should I create a branch?"

"Use git checkout."

"And how should I update the contents of a single file in my working directory, without involving branches at all?"

"Use git checkout."

https://stevelosh.com/blog/2013/04/git-koans/

In fairness, git has improved on this and separated these into `git switch` / `git restore`
First time I hear about this
`git status` will tell you about `git restore` if you have staged or uncommitted changes
`git status -s` also gives the shorthand version of this. I have it aliased to `gs` pretty much everywhere because it's really useful to me.
Yeah, but they denied the problem for the longest time, so they deserve some flak for it :)
Probably true. IMO the crime of checkout is that the command really is `git checkout <tree> -- <path>`, which updates that local path to match that git tree, but it implicitly fills `tree` with the current branch and `path` with all files.

It actually makes sense if you learn the full command but makes zero sense when you google individual common operations and then they thought "this command should also have a shorthand to create branches" I suppose

I don't even use *the multiple uses of `git checkout`. It may be suboptimal but I think it's easier to quickly recall in my mind-- `git branch name` to create a branch and `git checkout branch` to check out a branch.

`git checkout` for restoring files is dumb though, but as others have mentioned the UX has been improved with `git restore`

> It actually makes sense if you learn the full command but makes zero sense when you google individual common operations

I call this "hacker tunnel vision". It is a state afflicting a lot of programmers at the top of their game when it comes to writing end-user API and documentation. It can be summarized by "it is so obvious that people will think I'm mocking them for explaining this"

I had a calculus teacher who would routinely use IOTTMCO for various proofs. Intuitively Obvious to the Most Casual Observer, follow by a 5 page derivation
This is because git is a tool to interact with the git tree, not the mental models you've built on top of it or imported from other tools.

Git checkout covering multiple usecases makes sense to me, I've never thought, hey this is used for all these different things they should be separate. I think, hey, this tool is always checking out a hash and a path.

The fact that can be a branch or a commit is entirely inconsequential. If it irks you it's because you think there is a difference between a branch and a commit then you're likely lacking some fundamental understanding about git.

Git is a tool to get work done and is used by people besides programmers (sysadmins, data analysts). If people don't understand everything is a hashed commit its Git's fault for introducing distinctions without making the cli reflect those distinctions, not because those people didn't take a data structures course on Git.
Yes coming from Mercurial I find Git very confusing.
Once I understood that git was basically a DAG of filesystem snapshots enforced by hashes then everything started to make sense very quickly.

I'd even argue that hiding this fact is what makes all of the other CVS a pain in the ass to use because they are trying so hard to hide the truth from their users.

Other VCSs aren't a DAG of filesystem snapshots enforced by hashes.

For example SVN is strictly a linear snapshot of a single tree.

SVN is effectively a badly designed database. Git has a much more effective and simple data structure because each command correspond to a way to work with it and external tools and extensions and future version of git can work with that very easily.
I had a very similar reverse experience- coming from git, Mercurial felt very confusing and limited…
I love git because it's fast, but the UX is trash
Have you written your own UI yet? I recommend trying out Magit.
Agreed. If you have to use git, Magit is a great tool.
And if you’re implementing a git ui, it’s a great place to steal ideas from too!
Git isn't perfect but for me it was a huge improvement over SVN. The complexity was worth the ability to do stuff I never did with SVN.
Agreed. Perforce has much better UX and tooling than git though.
P4 has better UI than git, but I’d argue the UX of command line p4, and of workflow issues like workspace mappings and connections and of course branching, are all dramatically inferior. (Caveat, I haven’t used p4 streams yet.) The one thing p4 has that I sorely miss and nothing in git-land comes close is the time-lapse view!
I probably supressed my memories of connection issues :D I love DVCSes, hated not being able to work offline I agree with the time lapse view and p4merge. Maybe one should hack together a time lapse tool for git? :thonk:
Git gui blame tried, but lands very far short of time lapse view. Git’s underlying representation might make time lapse technically difficult. I think there might be some other UI attempts too, I just haven’t tried because I’m usually on the command line and using different OSes often.
The thing is, Fossil is also a huge improvement over Subversion without losing its day-to-day simplicity.
The funny thing is that the xkcd cartoon isn't even that much of an exaggeration. Countless times, I've literally copied files from a working branch, nuked the branch, then pasted them into a new branch because I couldn't get something to merge for some stupid reason that would've taken like half a day to figure out.
Seen it happen so often when people try to get fancy with branches and merges.

Yes I'm sure there's always a way to recover using the tools, but if you are not a git guru and don't have one handy, deleting and cloning is usually the more pragmatic way.

IMO conflict resolution is almost always harder than redoing the change by hand, especially while looking at the old diff and redoing it towards the new branch. Kind of ironic given how hard diff editors try to help.
When I get into a three way merge it's usually just too late in the day, so I will just save off my stuff and merge in manually :) like you said. Two things to compare against is plenty.
I don't see the issue. This is how people fix everything else, it is what comes naturally, and it works every time. I would much prefer it this way, than what Fossil appears to do in section 3.3 of this article, having a single copy of the database per system.

    mkdir ~/fossils
    fossil clone https://sqlite.org/src ~/fossils/sqlite.fossil
    mkdir ~/sqlite; cd ~/sqlite
    fossil open ~/fossils/sqlite.fossil
Yeah, probably just about every dev has had to do this when first learning git.

One way to measure the over-complexity of software might be:

1. How easy it is to screw up

2. How hard it is to fix things once you've screwed up.

Git doesn't score well by that test IMO.

Back when I first learned Git, I thought it needed an undo, at least for the local repository. Not a revert commit or partial/piecemeal undo this or that, but an "I screwed up, take me back to x point in time or snapshot" level undo.

Yeah, me too. I'm usually only working on a couple of files at a time but then there a conflict. I try to resolve and just keep digging the hole deeper until I just save off my files, do a new checkout and patch them in manually post what ever merge was giving me hell so there won't be any conflicts.
What I still can't believe is that the world chose git over hg.

Why would you use git if you could use Mercurial instead?

Basically, GitHub.

GitHub would have won even if it were MercurialHub. It had a better user model of the problem to be solved than any other SaaS code forge, and it supported both open-source bazaar-style development and private enterprise. The gamification and social network features are KILLER.

Also, the Mercurial developers never had the built-in fan base of Linus Torvalds. Anyone who wanted to work on Linux had to use Git, so that was another major reason to learn (and stick with) Git.

> Basically, GitHub.

This. Which basically means: no time to setup, no operations overhead, no administration required. This means, no dedicated team member needed who is the "admin" for version control, no dedicated infra required, etc. In the early 2000s when we were a team of 8 developers, one was a "ClearCase admin". He was a single point of contact for all things ClearCase (request him to create a new branch, add a new user, create a label, create a new repository and so on). He also had to ensure regular backups were done, the server was regularly patched, the disk had enough space. GitHub/Gitlab simply remove all of this just for a few dollars per user.

While I can identify with the ClearCase/Perforce/etc admin issue, there were a multitude of code hosting solutions that predate GitHub. Google code supported subversion and mercurial; Before that, tigris.org supported subversion; before that, Sourceforge supported CVS.
I watched git take over in several companies before anyone had ever heard of GitHub. One reason for Git’s success in my mind is that the actual competition in practice was Perforce, not Mercurial, and Perforce’s workflow and scripting UX and design are stuck in 1997… still! ;)
Because Linus created it and Linux community adopted it.
...or bzr, or monotone, or other contemporaries implementing extremely similar models. Git won because of its author's fame in an entirely different domain; both its use for the Linux kernel and the existence of GitHub are secondary to that.
It's been ages at this point since I used Mercurial (around 2010) and probably these things changed along the way.

- But with mercurial branching where more like forks with different directories. Made me avoid that feature in web development work (that way I didn't have to fiddle with my webserver config every time I would have liked to create a branch)

- I recall having to deal with a bunch of gotchas around mercurial bookmarks (tags), like not being able to delete them, problems with sharing them with others, and things like that.

I was actively exploring different DVCS around that time, coming from a SVN background where I remember spending a lot of time fixing merge conflicts like a sucker. The one I liked, for its theoretical aspects, was darcs (as I was also leaning heavily in the Haskell ecosystem of the time).

Anyway, in short for me git overtook mercurial because it was easy for me to hop around multiple branches, pick off individual commits, and rebase commits (I was still pedantic about how I formatted my commits before a PR, nowadays, not so much).

> But with mercurial branching where more like forks with different directories.

That's bzr, not Mercurial. Mercurial has always had more advanced branches than Git.

It's been more than 10 years since I've used mercurial, so I had to try and dig up old documentation (hard to do with my Google-Fu), anyway I've found an older HN post that discuses the separate directory thing back in 2009 https://news.ycombinator.com/item?id=1013320

I'm sure a lot has changed in that timespan, and maybe it was a bit more of a nuanced situation wrt branching, but the pain points are the things I can only vaguely recall at this point.

That post may have been discussing it, but it was not based on the reality. Having multiple clones is just one of the workflows, one Git users also frequently employ. If anything, Mercurial’s branching model has always been richer than that of Git, since even when if didn’t have Git-style branches (bookmarks), it supported named branches and anonymous branches, which already allowed for a wider variety of workflows than Git ever did.
branching is just better in git. sorry. I like Hg, we used it for like 4 years, but switched to git, and have been using it for 10 years now, never looked back.
> Why would you use git if you could use Mercurial instead?

Because Mercurial was (Still is?) hopelessly slow on large repositories.

not true, for instance, git being slower than hg for things like large monorepos is why google and facebook invested so much in hg (while microsoft has been pretty busy reinventing large parts of hg in git, as git-vfs for instance).
Git made it easier to fix problems when I screwed up my repo. Mercurial was great when everything was working correctly, but for a long time it lacked the tools (or required third party tools) to fix problems I ran into.

Mercurial did have one killer feature, and that was hginit.com. Git's documentation was terrible for a long time. I would send programmers used to old fashion version control to hginit all the time, even when I was teaching Git.

I’m going to solidly blame Mercurial for having hg as a command - I couldn’t figure out why mer tab didn’t find anything and moved on.
- Speed

- The fact that it was Linus developing it

- The fact that it was released just after Git

- It's pretty much like Git and evolved to be usable like Git

- Git had way more advanced tooling and still does to this day

> - It's pretty much like Git and evolved to be usable like Git > - Git had way more advanced tooling and still does to this day

Very untrue.

Mercurial has advanced concepts and features that Git cannot dream of, e.g. changeset evolution.

For me: `git gui` and the stage. Incrementally building my commits line-by-line (often with other working directory changes I don't want) feels invaluable. Work forced me to go git->hg and it frustrates me every day.
git is one of those things that are so popular and accepted as the true way that questioning its use makes you look like an idiot but, in reality, many devs would benefit from a simpler version control system, one not intended to handle arguably the world's most popular source code.
(comment deleted)
I used fossil in the past for my personal projects, it worked great but it had too many features for a solo developer, getting others on board of using it is hard, given git is mainstream.

  GIT - the stupid content tracker
  
  "git" can mean anything, depending on your mood.
  
   - random three-letter combination that is pronounceable, and not 
     actually used by any common UNIX command.  The fact that it is a
     mispronunciation of "get" may or may not be relevant.
   - stupid. contemptible and despicable. simple. Take your pick from the 
     dictionary of slang.
   - "global information tracker": you're in a good mood, and it actually
     works for you. Angels sing, and a light suddenly fills the room. 
   - "goddamn idiotic truckload of sh*t": when it breaks
  
  This is a stupid (but extremely fast) directory content manager.  It  
  doesn't do a whole lot, but what it _does_ do is track directory
  contents efficiently.
- README, Linus Torvalds, Git source code, April 7th 2005
I thought for a moment this would be why SQLite doesn't use Git to store its data structures, which I really wish it did. Still looking for a database that acts as a virtual file system, and automatically orders data into a file tree structure.
Create a table of inodes and link them together with some blob fields. There's your filesystem.
(comment deleted)
I HATE Git. It seems like every other over-complicated, over-engineered solution to problems that should be simple.

I used svn for a long time. New developers got it right away. Git is treacherous waters for 7/10 of the developers I've worked with.

That said, I LOVE GitHub and gitlab. Amazing tools for collaboration. But the Git part doesn't really do it for me. I'm waiting for something better to take its place.

> It seems like every other over-complicated

A DAG is one of the simplest data structure out there. What is complicated is doing merges in non-DAG CVS and let's not even talk about more "complex" operations like putting all of your commits on top of a branch, only committing a single line and, god forbids, creating branches without asking for permission.

> over-engineered solution to problems that should be simple

I get it that you're unfamiliar with how not nice databases schemas are. A git repository from 2005 will still work in 2021. AFAIK all other CVS will fail at this because they rely the overly complicated data representation. Git's internal representation is very simple. Filesystem snapshots referred to by content and these snapshots that can reference other snapshots to form a DAG. Just because you didn't take one hour to understand this doesn't mean it's "complicated".

> That said, I LOVE GitHub and gitlab.

These would not have existed if not for Git's internal representation that allows the necessary flexibility for other tools and extensions to integrate directly.

I don’t care about GIT. Perforce is my favorite. Takes an hour to understand everything to be productive.
does perforce still just allow one branch per repo?
It's been about 5 years since I used Perforce, but streams were a nightmare. Sharing files down 2 "levels" of streams was such a huge pain.
When a programmer in the games company I worked in started rallying to switch from p4 to git and got momentum, I thought it was going to be a mistake. No doubt it took a lot of learning, but eventually I came to see it was worth it.

One thing that’s not well appreciated even with most people who use git is how much safety net it can provide against losing changes accidentally. I know a lot of programmers who don’t care and will blow away and re-clone a repo before learning how to use git reflog. But, in git you can recover from almost anything if you know how.

P4 is pretty terrible when you want to try something multiple ways, or when you want a small team to prototype a feature without affecting everyone. I’m actively using both git and p4, and I can’t tell you how many p4 shelves I’ve got stacked up. They keep collecting because there’s nowhere else to put them, and it’s the only (crappy) way to test parallel ideas.

Using git for trying out things in different ways is so nice and so fast once you get fluent with it. Of course your stance is valid and perfectly fine, you don’t have to change away from p4, but I think you might be surprised how git changes your thinking about source control.

BTW I haven’t used Fossil or hg or plastic or other new source control systems, but I would assume you could replace any of them with git in my above text.

good for Sqlite to simplify on their tools. But:

Git has a lot of weird stuff and fluff, but that doesn't mean you have to use all of them.

For instance, I try to almost never branch and use deployment flags instead - then you can always rebase and maintain an extremely simple commit history.

Simple >> Complex.

I think that's fine for solo development but as soon as you have a real collaborative project -- which, supposedly, is why you need a peer-to-peer vcs, then there comes a time when dev A is working on some feature for the future, and dev B is debugging on an existing release, and now you really need branches because B's fix is going to need to be pushed out ASAP but dev A's feature is still being worked on.
But that's what I'm describing (I do work for one of the FAANG), all feature work are either ready, or gated by feature flags. With practice, it becomes easier to divide feature work while not cause any existing impact, it also forces you to make your code logic cleanly separated.

The biggest benefit of this approach imo is the drastically reduced chance of a bad feature going out because someone had worked on it for 5 months in isolation and it becomes virtually impossible to debug.

Yeah, I'm familiar with feature flags, but that doesn't really solve the problem of needing well-defined releases and that these releases themselves need to be patched and possibly supported for a long period of time as determined by contract or support commitments.

Also feature flags are not going to be able to cover all code changes. For example, it's hard to put code refactoring behind a feature flag.

Finally, wide-spread use of feature flags as a type of in-code branch certainly seems like code-smell to me. It's fine for a while, but after 20 years you're going to have a difficult time maintaining that repo unless it's done with sufficient discipline that those feature flags are quickly removed once the feature hits production. It will also screw with your automated static analysis tooling.

I think what's missing is the context. When you're a service oriented architecture you can afford these changes. If you're a monolithic block then it gets a lot harder.

Personally, I like smaller, well defined changes and CI/CD.

I'm far from convinced by this article.

It's starts by saying that it's not comparing git and fossil but just keeps trying to throw generalities at your face how fossil is so much better and smarter than git.

It sometimes compares git and all of a sudden compares github or gitlab, no reason given. So what is it about, comparing git, github or gitlab?

Apparently git is to complex for developers, sorry but I have yet to see a developer not managing to work with git. Either I've always worked with geniuses or this is a non-problem.

The author is comparing with github/gitlab as fossil offers both VCS features, like git, but also features a Web interface with issues, wiki and forums, which you can only get with those third party products.
Then the comparison would be fair if it would go through all the different options. Picking the one that is quite heavy to host like gitlab (but does way more than what fossil does by the way) for the purpose of saying that git sucks is misleading.

There's options like gitea that are lightweight and super easy to host.

>Apparently git is to complex for developers, sorry but I have yet to see a developer not managing to work with git. Either I've always worked with geniuses or this is a non-problem.

You must work with geniuses.

No one I know has never been at the place where you just accept the tree is fucked, delete .git and paste your changes back into a fresh checkout.

Granted now I understand things like git reflog so it's been many years since then, but git is as far from approachable as tooling gets...

Thanks then, it means I must be managing my team right :)

I've never seen a tree being broken, and needing this kind of action.

Don't get me wrong, the git cli could definitely be improved, but as long as you have a clear workflow and map it to git actions it works well.

You'd have to be a pretty bad manager to micromanage so hard that you're the reason someone's local repo is never broken...

This is a local issue that usually bites a new developer.

-

Sometimes you can search/ask for a fix, sometimes you realize in the time it took to find that fix you could have just made a new local copy.

I was a "productive developer" capable of solving real issues for a pretty long time before I was comfortable with "advanced Git", mostly from writing tooling with it.

And there are plenty of brilliant developers who never really get past the basics.

It seems pretty backwards that the tooling mainly meant for the background tasks like backing up and merging changes should be harder to master than the foreground tasks of actually building the stuff you put in Git...

You're talking about issues that I never witnessed anybody facing, that's all I have to say. You don't have to be an ass about it. You don't know me, and my managing style so you can keep your judgement for yourself.

Git is not hard, most developers, from junior to experienced do fine with it with really little learning on their own, no need to micromanage anybody.

Lol what? Don't project your insecurities onto me...

I literally said these are problems a manager will not witness unless they're micromanaging, where did I judge your management style?

-

Though to be blunt, this is starting to feel like the Dunning-Kruger effect in action. I mean how deeply familiar can you be with Git and still question how others find Git hard?

Even Linus has admitted that Git is hard, but argues it's gotten easier over time. Of course things live on the internet forever, so even fresh beginners end up not learning about the newer, easier ways to do things.

My impression was the author didn't like all the additional complexity git comes with (sure, you don't need to use it but it's still there)

I think the mentions of software like GitHub were more in terms of workflow since apparently Fossil bundles all that together in a static binary (you don't have to integrate the tool chain yourself)

fossil contains a lot more functionality than git by itself, so comparing it to git + gitlab or git + github kind of makes sense.
Then it needs to be compared with all the options. There's git hosting solution that are really light and as easy to install than fossil.

That's actually the thing that makes git hard to replace, there's a lot of tooling built around it.

> There's git hosting solution that are really light and as easy to install than fossil.

I'm not sure that is really the case. Almost everything in the git universe is git + webserver + cli tool + scripts + gui tool. It really isn't the same... you have to concatenate an awful lot of tools to add fossil's base features to git. That said, I end up using git on everything but personal projects... then I use fossil.

It’s 2021. How I wish we had moved past pointless git bashing by now.

We get it. Many people don’t like it. They prefer to use $TOOL instead.

It’s been 16 years. Can’t we resign this to emacs vs vi category of things we’ve largely accepted and stopped arguing about yet?

I’m not mad at the article. They have preference and wrote down why they don’t use the more popular tool for when people ask. That’s fine. But I’m guessing it was posted to have the “discussion” we’re having right now (and every time got comes up). People bashing (or defending) git.

And it’s exhausting.

We’re half way to the age of vim. Can we let this one go too please?

I agree that it's exhausting, however using git is even more exhausting... so the complaining and comparisons will continue.
If a tool attracts enough ire that such arguments arise frequently, then a non-zero number of people are dissatisfied and could be satisfied by other tools. That is worthy of discussion.

Additionally, it is cathartic (and occasionally even productive) to complain about the warts and sharp edges of a popular tool, especially when the tool is the overwhelming the tool of choice in its domain.

Your comment basically can be summarized as "Everybody stop discussing this topic that doesn't interest me!"

To which I can only reply: No.

"The mental model for Git is needlessly complex"

that's it, right there. Why are you bothering me about a detached head?

Agreed on this one. It should instead let you handle this when you commit, make you reckon with what to call this new gitref. That is when I care about whether I'm connected to HEAD or not

Yeah, it would make you `git branch` to give it a name, or an override option to commit it without a name

"Detached head" is Git's way of saying "I don't know how to find my children when you say something like 'git checkout abcd1234'". Fossil can do this, so you can point someone to a historical checkin and Fossil won't get lost should you later commit on top of it. Git's warning you that if you do that, you may end up with an orphaned commit.
More like "I don't know what gitref to move (*well, change) if you commit". `git checkout` isn't relative to the current ref is it?
I think it's actually the opposite. Git's model is really really simple and pushes all the complexity onto the tooling and the user.
That's exactly the parent's complaint: Git's tooling and user interface is (unnecessary) complex.
I dunno, git model always felt extremely intuitive to me... there are very few core concepts and ideas and all the complexity is layered on top of that and is easily decomposed. I feel like git concepts are very elegant while allowing a lot of complexity, like C/C++ pointers ;)
> Git does not provide good situational awareness > [...] > I can even do this from a phone. > [...] > GitHub and GitLab offer nothing comparable.

Seems like git=(gitlab|github) for the author. I don't agree this is right, as these both are totally different products comparing to git and made with different purposes and aims.

Phone access. Okay, probably we are in different culture contexts, but for me a need to use my phone to access source code (or tickets) always means things went very very wrong.

Maybe the wrong culture. I use GH to reference source code from my phone quite a lot. I spend half my time on the phone, and when I'm in a meeting, my phone is the obvious way to be in those meetings. Ensuring I have first class access to everything from my phone is a huge priority.

The author may have a point about having better views of the source from GH/GL, but they are absolutely providing a decent experience for it already.

dr hipp also uses his own editor so that might be a clue