4 ms·
Git is the poster child for "leaky abstraction"
by vidanay 9y ago
Git is the poster child for "leaky abstraction"
- klodolph 9y agoI don't think leaky abstraction correctly describes the problem here, because the leaky thing (the fact that history is not linear, and multiple people edit the same files, and that everything is distributed) is not actually an abstraction. In my mind, Git forces you to deal with the fact that history is inherently nonlinear, and then you can choose to create a linear history by the way you use Git. Git's main abstraction is the fact that everything is a content-addressable blob. This "leaks" but it's not a major contributor to the problems people have using Git, at least from what I've seen.
- masklinn 9y ago> In my mind, Git forces you to deal with the fact that history is inherently nonlinear, and then you can choose to create a linear history by the way you use Git. That is not the problem with Git. Mercurial or Darcs also force you to deal with it all the same yet are not anywhere near the UI clusterfuck that Git is. > This "leaks" but it's not a major contributor to the problems people have using Git, at least from what I've seen. It absolutely is, because it leads to commands having unintuitive and incoherent behaviours and thus to the porcelain being impossible to model top-down.
- stouset 9y agoI disagree that this is the case. I see it more as git is a DAG, and git's toolchain is simply a set of tools for manipulating the DAG. It's not so much that git is a leaky abstraction as it is that git isn't an abstraction. If you don't know what a DAG is or how commits, files (e.g., blobs), trees, etc. are mapped into the DAG, of course you're going to have a hard time!
- aero142 9y agoI could be able to write the git internals code from memory and it wouldn't help me know what `git checkout` was going to do.
- stouset 9y agoThat's almost patently false, since `git checkout` is pretty much just a tool that takes a commit (or a name that points to a commit, like a branch or tag name) and updates the working tree, index, and the HEAD pointer to match the contents of the commit, with some extra safeguards to make sure uncommitted data isn't lost. Three examples (that cover 95%+ of use-cases): $ git checkout some-branch > Updates the index and working tree to reflect the contents of `some-branch`, and updates the HEAD pointer to indicate we're on the `some-branch` branch. $ git checkout -b some-branch > Updates the index and working tree to reflect the contents of `some-branch`, with the "convenience" of creating it first through wrapping `git branch`. This is identical to calling `git branch some-branch; git checkout somebranch`. $ git checkout <optional-commit> -- path/to/a/file > Updates the index and working tree to reflect the contents of the named file on the current or named branch/commit/tag/whatever. TL;DR, `git checkout` has a very clear and well-defined responsibility: update the filesystem and index to reflect the contents of some commit. Various flags and options cause it to perform reasonable variations of this core responsibility (create a branch that doesn't exist first, or update individual files rather than the working tree as a whole). If the commit-name provide is a branch (and you're not checkout out individual files), it also updates the HEAD pointer to point to the named branch, so git "knows what branch you're on". I would be absolutely astonished if you could write the git internals (or even just knew how they worked) and the idea of a tool to make the filesystem look like the internal contents of the repo wasn't immediately apparent. You might not have realized that that's all that `git checkout` does, but once you understand that, it's extremely straightforward.
- markrages 9y agoYour comment would be at home on https://git-man-page-generator.lokaltog.net/ https://git-man-page-generator.lokaltog.net/
- lozenge 9y agoSo it always updates the HEAD pointer, except when it doesn't, and you give it the name of an existing branch that represents the commit to change your working tree into, except when you specify -bf to use the HEAD commit, and except when you specify -b and a branch name that doesn't exist. You can also specify start_point to use instead of HEAD. So, the checked out commit is the second ref specified, or HEAD, unless the flags are such that you can only specify one ref. Git checkout also "merges" uncommitted changes with your new HEAD, which you didn't mention and makes me wonder why the command isn't called "git merge".