1. 69
    1. 19

      As phk so eloquently put it: Git Is Not Revision Control. His full take posted here:


      1. 5

        Git is a tool which allows people and projects to manage, modify, fork and merge the many different views, instances, variations and modifications of a work in progress across barriers of distrust.

        The crucial word there was “many different”, which is the exact opposite of what a VCS strives for.

        Uh. Yeah, all DVCSes allow users to have their own view of the repo, that’s the point. In the DVCS world, the official remote’s admin is responsible for maintaining the definitive timeline, that is, not allowing force pushes. I don’t see how that’s any different from an SVN admin not allowing anyone to manually overwrite SVN files on the server to screw up the history!

        you just have to augment it with an out-of-band definition of which tree is the ‘definitive’, and settle who gets to define what ‘a version’ means.

        neither SVN nor Git will ever be able to do both [collaboration and version control], because the requirements are fundamentally different and in conflict with each other

        What exactly is the conflict? You “out-of-band” “define” the official git remote’s history as “definitive” (i.e. state an incredibly obvious fact), boom, done, no conflict, it’s a perfectly adequate revision control system.

        1. 4

          One of my biggest gripes with Git is that it doesn’t track renames. Linus doesn’t think they matter. Much of the world disagrees, but here’s his take on it:

          –follow is a total hack, meant to just satisfy ex-SVN users who never knew anything about things like parenthood or nice revision graphs anyway.

          It’s not totally fundamental, but the current implementation of “–follow” is really a quick preprocessing thing bolted onto the revision walking logic, rather than being anything really integral.

          It literally was designed as a “SVN noob” pleaser, not as a “real git functionality” thing. The idea was that you’d get away from the (broken) mindset of thinking that renames matter in the big picture.

          So by not tracking renames, history is broken, and I fail to see how Git is a real VCS.

          1. 1

            I don’t see how storing “old file deleted, new file added” instead of explicitly tracking renames might break history o_0

            1. 3

              Because sometimes you want to see the entire changelog that has ever happened to that file, including before the rename happened.

              1. 14

                You make it sounds like was an easily solved problem and git just messed up, but that is not the case.

                Linus is absolutely right about the fact that, in general, tracking and merging renames is hard.

                You have a potentially large number of permutations of tree changes, and edits of file content, which people can commit with any given recorded change.

                Tree changes include: add, delete, copy, move. These can happen at any level in the tree, and as often as needed to achieve some particular new tree configuation in the new commit.

                File content edits matter as well because they conflict with some structual changes. E.g. if one side edits content which the other side deletes, there is no obviously correct answer to the question of what the merge result should be.

                And users expect a revision control implementation to be able to run useful merges after committing several such permutations (read: refactorings) even when each of these is entirely different.

                In SVN’s model the “address” of every node in this tree is a path, so tracking moves becomes a horror of a path-segment matching problem: http://svn.apache.org/repos/asf/subversion/trunk/notes/resolve-moves (this covers some ground but leaves several more complicated situations open for future design and development).

                In Git’s model we face the same fundamental issue, expect a path segment becomes a (hash, name) tuple in a tree object; where the tree objects form the chain which, when folowed, results in a path. To detect a move, we have to guess which ‘name’ in a tree object on one side corresponds to which other ‘name’ in any of the tree objects on the other side of the merge. Git can take some shortcuts because its model also includes hashes of contents, so comparing files or even entire subtrees can sometimes be solved with a simple string comparison, whereas SVN always needs to diff content.

                I am not aware of any version control system which gets this 100% right for all conceivable cases.

                1. 1

                  Everything you listed sounds like an edge case. I don’t care about edge cases, I only want git history to work across renames when there are never any merges between a rename.

                  --follow mostly does that. It would be even better if all invocations of git mv resulted in the rename being recorded in a file in the repo. Again, I don’t care if that “rename history” file gets invalidated and deleted in edge cases such as hairy merges.

                  1. 1

                    I don’t think rename + merge is an edge case. I know for a fact (from years of consulting) that git’s support for this was a major factor for several companies to migrate away from svn to git.

                    But yes not everyone needs it. Depends on your workflow.

    2. 16

      As someone who worked on one of the prior/better DVCS (bazaar), I’m really sympathetic to this curmudgeon argument. However, I think the battle has been lost since at least 2009, and it would be more productive to write tooling for git than keep complaining from the sidelines.

      1. 30

        They aren’t complaining, they wrote fossil instead of complaining. The complaints come from other people complaining to them for not using git.

      2. 38

        As one of the most used libraries in existence, I think SQLite has license to do whatever the hell they want. Their workflow obviously works for them.

        And this isn’t really complaining, it’s about things fossil does better than git from their point of view. To me it reads like the author set out to write an objective post highlighting the differences, but got annoyed along the way, corrupting their tone for some bits. I imagine this post only exists because they’ve been asked this question enough times to just document it.

      3. 4

        and it would be more productive to write tooling for git than keep complaining from the sidelines.

        IMO, it’s worth keeping the other things alive. At least with hg there is hg-git so us hg users can live inside the git world, but I also use FreeBSD as my main OS so I’m willing to put up with some pain to avoid a monoculture.

      4. 3

        I still use bazaar for my personal projects :-)

      5. 3

        While (sadly) Bzr did not make it, Hg does seem to be hanging in there. Both Facebook & Google use it internally, for instance.

      6. 2

        I think for the branch stuff in particular you would need to get stuff into git’s core to make the kind of improvements needed. But those improvements might go against the entire current mental model of branches for git!

        Might be pretty tricky.

    3. 7

      Can someone explain a reason you’d want to see the descendants of a commit?

      1. 8

        Following history. Code archeology.

        Many people use the VCS history as a form of documentation for the project.

        1. 4

          But history is the past… you can always see the past in git…

          1. 17

            Suppose I’ve isolated an issue to this bug fix commit. In what version of gRPC did that commit release?

            Github tells you it’s on the v1.8.x branch, so if you head over to the, v1.8.x branch, you can see it landed after v1.8.5, so it must have released in v1.8.6. Easy enough right?

            Well that’s not the whole story. That commit was also cherry-picked over to the v1.9.x branch here, because v1.9.x was branched before the bug was fixed.

            Besides, that was silly to begin with. Why did you go to the v1.8.x branch and then manually search for it. Why couldn’t it just tell you when it got merged? That would have been nice.

            Many projects maintain many release branches. Some just backport bug fixes to older releases, some have more significant changes. Sometimes a bug fix only applies to a range of older releases. Do you want to track all that with no notion of descendants? It’s not fun.

            Even just looking at pull requests, it would be nice to see whether a pull request eventually got merged in or not, what release it got merged into, and so on. That’s all history too.

            So no, you can’t always see the past in git. You can only see the direct lineage of your current branch.

            1. 3

              I used to find this hella handy at Fog Creek, especially for quickly answering which bug fixes were in which custom branch for some particular client. We actually made a little GUI out of it, it was so helpful.

              (Interestingly, while Kiln supports that in Git too, it at least used to do so by cheating: it looked up the Mercurial SHAs in the Harmony conversion table, asked Mercurial for the descendants, and then converted those commits back to their Git equivalents. Because Harmony is now turned off, I assume either they’ve changed how this works, or no longer ship the Electric DAG, but it was cool at the time.)

            2. 2

              Why couldn’t it just tell you when it got merged?

              I don’t know why GitHub doesn’t, but Git can:

              $ git tag --contains b15024d6a1537c69fc446601559a89dc8b84cf6f

              That doesn’t address the cherry-picking case though. I’m not aware of any built-in tooling for that. Generally Git avoids relying on metadata for things that can be inferred from the data (with file renames being the poster child of the principle), so I’m not surprised that cherry-picks like this aren’t tracked directly. Theoretically they could be inferred (i.e. it’s “just” a matter of someone building the tooling), but I’m not sure that’s doable with a practical amount of computation. (There are other operations Git elects not to try to be fast at (the poster child being blame), but many of them still end up not being impractically slow to use.)

            3. 1

              Does Fossil track cherry-picks like this though? So that they’d show up as descendants? In git the cherry-picked commit technically has nothing to do with the original, but maybe Fossil does this better. (It’s always bothered me that git doesn’t track stuff like this - Mercurial has Changeset Evolution which has always looked suuuuper nice to me.)

              1. 4

                According to the fossil merge docs, cherry pick is just a flag on merge, so I imagine it does. I was just highlighting the utility of viewing commit descendants.

                1. 7

                  Mercurial also tracks grafts (what git calls a cherry-pick) in the commit metadata.

                  1. 5

                    This is actually illustrative of the main reason I dislike mercurial. In git there are a gajillion low level commands to manipulate commits. But that’s all it is, commits. Give me a desired end state, and I can get there one way or another. But with mercurial there’s all this different stuff, and you need python plugins and config files for python plugins in order to do what you need to do. I feel like git rewards me for understanding the system and mercurial rewards me for understanding the plugin ecosystem.

                    Maybe I’m off base, but “you need this plugin” has always turned me away from tools. To me it sounds like “this tool isn’t flexible enough to do what you want to do.”

                    1. 8

                      Huh? What did I say that needs a plugin? The graft metadata is part of the commit, in the so-called “extras” field.

                      I can find all the commits that are origins for grafts in the repo with the following command:

                      $ hg log -r "origin()"

                      And all the commits that are destinations for grafts:

                      $ hg log -r "destination()"

                      This uses a core mercurial feature called “revsets” to expose this normally hidden metadata to the user.

                      1. 2

                        Right but how much manipulation of grafts can you do without a plugin? I assume you can do all the basic things like create them, list them, but what if I wanted to restructure them in some way? Can you do arbitrary restructuring without plugins?

                        Like this “extras” field, how much stuff goes in that? And how much of it do I have to know about if I want to restructure my repository without breaking it? Is it enough that I need a plugin to make sure I don’t break anything?

                        In fairness, I haven’t looked at mercurial much since 2015. Back then the answer was either “we don’t rewrite history” or “you can do that with this plugin.”

                        But I want to rewrite history. I want to mix and blend stuff I have in my local repo however I want before I ultimately squash away the mess I’ve created into the commit I’ll actually push. That’s crazy useful to me. Apparently you can do it with mercurial—with an extension called queues.

                        I’m okay with limited behavior on the upstream server, that’s fine. I just want to treat my working copy as my working copy and not a perfect clone of the central authority. For example, I don’t mind using svn at all, because with git-svn I can do all the stuff I would normally do and push it up to svn when I’m done. No problem.

                        And I admit that I’m not exactly the common case. Which is why I doubt mercurial will ever support me: mercurial is a version control system, not a repository editor.

                        1. 13

                          For the past several years, as well as in the current release, you still have to enable an extension (or up to two) to edit history. To get the equivalent of Git, you would need the following two lines in ~/.hgrc or %APPDATA%\Mercurial.ini:


                          These correspond to turning on rebase and rebase -i, respectively. But that’s it; nothing to install, just two features to enable. I believe this was the same back in 2015, but I’d have to double-check; certainly these two extensions are all you’ve wanted for a long time, and have shipped with Hg for a long time.

                          That said, that’s genuinely, truly it. Grafts aren’t something different from other commits; they’re just commits with some data. Git actually does the same thing, IIRC, and also stores them in the extra fields of a commit. I’m not near a computer, but git show —raw <commit sha> should show a field called something like Cherry-Pick for a cherry-picked commit, for example, and will also explicitly expose and show you the author versus committer in its raw form. That’s the same thing going on here in Mercurial.

                          And having taught people Git since 2008, oh boy am I glad those two extra settings are required. I have as recently as two months ago had to ask everyone to please let me sit in silence while I tried to undo the result of someone new to Git doing a rebase that picked up some commits twice and others that shouldn’t have gone out, and then pushing to production. In Mercurial, the default commands do not allow you to shoot your foot off; that situation couldn’t have happened. And for experienced users, who I’ve noticed tend to already have elaborate .gitconfigs anyway, asking you to add two lines to a config file before using the danger tools really oughtn’t be that onerous. (And I know you’re up for that, because you mention using git-svn later in this thread, which is definitely not something that Just Works in two seconds with your average Subversion repository.)

                          It’s fine if you want to rewrite history. Mercurial does and has let you do that for a very long time. It does not let you do so without adding up to three lines to one configuration file one time. You and I can disagree on whether it should require you to do that, but the idea that these three lines are somehow The Reason Not to Use Mercurial has always struck me as genuinely bizarre.

                        2. 5

                          Right but how much manipulation of grafts can you do without a plugin?

                          A graft isn’t a separate type of object in Mercurial. It’s a built-in command (not a extension or plugin), which creates a regular commit annotated with some meta-data recording whence it came from. After the commit was created it can be dealt with like any other commit.

                          And how much of it do I have to know about if I want to restructure my repository without breaking it?

                          Nothing. Mercurial isn’t Git. You don’t need to know the implementation inside-out before you’re able to use it effectively. Should you need to accomplish low level tasks you can use Mercurial’s API, which like in most properly designed software hides implementation details.

                          But I want to rewrite history. (…) Apparently you can do it with mercurial—with an extension called queues.

                          The Mercurial Queues extension is for managing patches on top a repository. For history editing you should use the histedit and rebase extensions instead.

                          I just want to treat my working copy as my working copy and not a perfect clone of the central authority.

                          Mercurial is a DVCS. It lets you do exactly that. Have you run into any issues where Mercurial prevented you from doing things to your local copy?

                          For example, I don’t mind using svn at all, because with git-svn I can do all the stuff I would normally do and push it up to svn when I’m done.

                          Mercurial also has several ways to interact with Subversion repositories.

                          mercurial is a version control system, not a repository editor.

                          Indeed it is. And the former is what most users (maybe not you) actually want. Not the latter.

                        3. 2

                          Mercurial’s “Phases” and “Changeset Evolution” may be of interest to you, then.

                          1. 7

                            It’s also worth noting that mercurial’s extension system is there for advanced, built-in features like history editing. Out of the box, git exposes rebase, which is fine, but that does expose a huge potential footgun to an inexperienced user.

                            The Mercurial developers decided to make advanced features like history editing opt-in. However, these features are still part of core mercurial and are developed and tested as such. This includes commands like “hg rebase” and “hg histedit” (which is similar to git’s “rebase -i”).

                            The expectation is that you will want to customize mercurial a bit for your needs and desires. And as a tool that manages text files, it expects you to be ok with managing text files for configuration and customization. You might think that needing to customize a tool you use every day to get the most out of it to be onerous, but the reward mercurial gets with this approach is that new and inexperienced users avoid confusion and breakage from possibly dangerous operations like history editing.

                            Some experimental features (like changeset evolution, narrow clones and sparse clones) are only available as externally developed extensions. Some, like changset evolution, are pretty commonly used, however I think the mercurial devs have done a good job recently of trying to upstream as much useful stuff that’s out there in the ecosystem into core mercurial itself. Changset evolution is being integrated right now and will be a built-in feature in a few releases (hopefully).

    4. 7

      The ability to show descendents of a check-in.

      Both Git and Fossil can easily find the ancestors of a check-in. But only Fossil shows the descendents. (It is possible to find the descendents of a check-in in Git using the log, but that is sufficiently difficult that nobody ever actually does it.)

      I use commit ranges to diff everything I’ve done since a commit, or browse its descendants.

      git log release-v3.8..
      1. 20

        That doesn’t work though. It will show you the descendant commits found between release-v3.8 and HEAD but not descendants on other branches.

    5. 7

      I use Fossil for all of my personal projects anymore. I don’t like that Github has a near-monopoly, and @ work we use mercurial not git, so I never learned the insanity that is the git model. I understand there are reasons for the insanity, but still.

      1. 6

        Last year I switched our studio’s VCS from git to mercurial because of how Hg manages “changeset evolution”. It seems to me that Hg has the upper hand in terms of innovation and advancing the conceptual model for VCS. One year later I’m quite happy: Hg feels easier to use, especially in unusual situations. The only thing I miss from git is automatic merge+commit on pull, while Hg still asks you to review and commit the merge.

      2. 2

        How big is your team at work?

        We’re only about 10 at mine, and we used to use Mercurial, but little by little hg usage eroded until it’s just me now yelling at (Amazon) clouds.

        1. 4

          Facebook uses it and Google is starting to as well. Both orgs have thousands of engineers.

        2. 1

          Only 2 of us now :( Government budgets hurt. We still love it tho.

          I keep thinking about moving to fossil @ work too, but HG works so well for us, no sense in messing with it.

      3. 2

        cgit + bugseverywhere + moinmoin would get you there too if you did prefer git.

        1. 3

          Yes, there are loads of options available, none of which is as easy as fossil ui

          1. 0

            That’s an extremely subjective statement. Also good luck using anything more robust with fossil, you’re locked in.

            1. 3

              Locked in? Import and export from git: http://fossil-scm.org/index.html/doc/trunk/www/inout.wiki

              Plus it’s BSD-2 clause licensed, which is the exact opposite of lock-in.

              Subjective? Maybe….. But this is why. think no:

              • Having to learn 3(+?) different tools, vs. 1 tool.
              • 3+ different processes and configuration to get right, and to make it all interoperate well together.
              • The internal structures are well documented.
              • Fossil is a statically linked executable, available compiled for mac,win,linux from their site.

              Installation of git + friends will be at best an apt-get or yum install away, but Windows is probably a mess to install all of it (granted git itself isn’t so bad anymore on windows)

              That said, We can just agree to disagree and call it a day. I recognize Git + friends is perfectly fine if you want to live that way.

              1. 1

                I mean if you want to run fossil with a different web client, or a different issue tracker.

    6. 1

      There’s a lot of conflation between ‘git’ and ‘github’ here.

      Point 3 is utterly bogus. If your needs are so specific, use git, not github.

      ‘Setting up a website for a project to use Git requires a lot more software, and a lot more work, than setting up a similar site with an integrated package like Fossil.’

      I run a git server at home. All I need is ssh. What’s ‘a lot of software’ about that?

      1. 4

        The part you quoted talks about providing a whole website for the project, not just repository access.

        Fossil seems to have a built-in web server, which provides access to the repository, tickets and wiki. The closest thing distributed with Git is GitWeb, which requires Perl and a web server speaking CGI. It only allows you to browse the repository. For anything else you need even more third-party software like Gitea for example.

        So setting up a whole website for a project using Git indeed…

        requires a lot more software, and a lot more work, than setting up a similar site with an integrated package like Fossil.

        1. 1

          Fair enough, but adding JIRA or something is simple enough. What the author is saying is: ‘I want fossil’, which is fine, but isn’t a good reason not to use git.

        2. 1

          cgit works fine. Often things aren’t packaged together on purpose within linux. This doesn’t mean you can only use gitweb. Also you can send patches over email if you choose. It’s not really fair to call it third party software since literally all of it including git is third party software.

      2. 1

        I agree with you about the conflation between git and Github. Github doesn’t play very well with cmd line git. you can’t send/receive patches for example. For lots of people git == Github, they are interchangeable, you and I know differently.

        like @seschwar said, you seem to have missed the first part of the sentence, “website for a project”. This requires more than ssh and git. Fossil is a statically linked binary that includes it all. And with the fossil ui command you get the entire website and all functionality locally as well, and it will all seamlessly sync with as many other copies of the repo as you want, the server is not special in any way, except that it exists at a safe, well-known address and becomes the main published repo.