things i just don't like about git
a short and incomplete list, of no use to anyone.
look, the modern git maintainers are doing god's work, and have shaved off so, so many rough edges. i don't have to --ff-only or set up precomposeunicode, and for all the other painful moments there's often a command flag to make it less awful.
at the same time, git sucks in ways small and large, and many of the faults are now foundational. let me explain:
----------------------------------------
sha1 was a bad choice back then, too
yes, sha1 was already considered deprecated by the crypto community before git began using it, and yes, it was known that any cryptographic primitive has a lifespan, and any software relying on it should prepare for the worst
git chose to just use the worst option from day one, and that's not the problem. the problem is that git's use of sha1 is very hard to change, as certain details are baked in to the on disk formats.
the moral here is "treat your identifiers as opaque strings" along with "sometimes a sha1: prefix doesn't hurt anyone"
anyway, where we we? ah. on disk formats
every single data format in git is unique
every single data structure serialized to disk has been crafted by the finest code artisans known to man, which is why one of the git extensions involves "sneaking things in after a filename that ends with a \0 null" because "just use json" is a bit too much to bear
i understand the distaste for xml and even json sucks at timestamps, but well, there's no good reason why git couldn't use one format for almost everything, except that git's written in C and so therefore we can't have nice things.
don't change your email, or your name
i guess when you read lkml, the notion of spam isn't too worrying, but putting names and emails into every commit means any time someone changes name, or changes email, they might as well be a whole different person to the repo.
sure enough, when you store names in the files, you have to rewrite history when someone changes email address, but in another world, you'd use a uuid and a file called .gitauthors that maps one to the other—and you wouldn't even have to put email addresses in the file, you could just put github urls or similar.
on a similar note, it would be nice to be able to have multiple authors in a commit message. it's one of the few times in git that there's only one of a thing allowed.
there's two different mechanisms for almost every feature
not that there's many features, but it's worth noting that submodules and lfs work in entirely different ways.
submodules? they're a file in the repo with a special type inside the trees, git knows when checking out that the file is special, and could run other commands. it then does not run those commands and the person using submodules begins crying.
anyway.
lfs? handled by a filter program defined in .gitattributes. unlike git attributes, this way allows users to actually specify behaviour, rather than hidden inside files hidden in the object store or .git directory.
the reason lfs and submodules work differently is that they're implemented at different levels of git. submodules are inside git, lfs is written atop the C tools, and only one of the mechanisms is designed for other programs to use.
there's a similar story with git commit headers and git commit trailer headers. trailers are user editable, and the built in headers are not easy to edit, change, or add to. so no-one bothers with it.
there's two ways to use git, and both of them suck too
take micro vs monorepos, it's a false choice. what you're really asking is "how do we work around git not supporting subtree checkouts" or "how do we work around submodules being painful"
in a better world, git would have subtree checkouts. it would make a lot of problems moot. in an even better world, git subtrees would work, but for now we settle with using another package manager atop and praying for death.
on a similar note, take rebases vs merges.
git forces you to make a choice. use merge and get a noisy, but representative history. use rebases and lose some of the work, but the log is a lot easier to navigate.
the truth is we could have our cake and eat it. git for windows does "merge rebase" commits that preserve history during rebases: it creates a merge commit with the latest version, replays the existing commits atop
we could also have a version of git log that didn't make merges look like shit, but that's another problem altogtether.
the unix philosophy is about building toolkits, not applications
look, the idea behind the unix philosophy is simple: your tool is probably making an output file. you can use grep, diff, less, cut, and a bunch of other tools to make things go. this is pretty cool actually.
git is somewhat a poster child for the unix philosophy. it's not one big command, but lots of smaller C programs held together with bash. if you want paged output, you run less, if you want to find things, you use grep, and if you want to build a feature: just hack it up out of bash. it eschews binary formats for text, abhors captive user interfaces, and dumps almost everything in the filesystem.
it's a great way to build a toolbox, but a terrible way to build tools: the error messages are weird, the problems are hard to recover from, and god help you if you run the wrong command in the wrong place.
when it comes to adding features, you are limited: you cannot add cross cutting features. you can't have modes where some commands are valid, and some aren't. a good tool should make these things impossible. git is not a good tool, and git's architecture means that these sorts of ux decisions are near impossible to realise.
in other words: have you ever accidentally committed inside a rebase? or accidentally committed a conflict? tough shit, fucko.
in another world, your vcs system would know "i'm in the rebasing mode" and wouldn't let you shit all over the repository, but we are not in the good universe.
before we drop the unix philosophy, there's two other points to nail to the door. firstly: git commands are named after implementation, not use, and there's absolutely no excuse for it.
secondly: flat files kinda suck if your state gets corrupted.
i've been spoiled by sqlite.
did you hit control-c? bad news buddy, your repository is fucked.
git, despite being labeled a database, isn't really interested in transactions or atomicity or durability as much as you'd hope. the closest you get to a write ahead log is a reflog for branches.
i'm not saying git needs to be as good as sqlite is, but it would be nice to not live in fear of accidentally corrupting my repository every time i cancel a command. at least if i do the wrong command, i have a chance of undoing my work
on a similar note: undo and redo would go a long, long way. even if it was just git commit --undo and it only worked 80% of the time, it would be a vast improvement on the current situation.
which is bad, btw.
git is made from papercuts
there's bits where you can't check in an empty directory, or how you can set files to ignore but not files to include. the ignore settings should come with defaults, but don't, and an awful lot of modern git workflow is turning on a bunch of settings and flags that should have been there from the outset
i didn't want to mention the unix philosophy again but when you build your software as a toolkit for automation, it's a lot harder to make breaking changes to things. users are usually a lot better at handing differences than bash scripts.
usually.
either way, one of the biggest reasons we can't just fix git is that we've built a small empire of bash atop of it, which falls apart if you look at it funny. there's just so much suck that's never going to go away.
----------------------------------------
this is by no means a complete list, but i'm done writing it for now.
git may suck, but the alternative is the "you never make a mistake" source control, which is even more awful unix brain than git, so i guess i'll live with it for now.