We like to think that there is a lot about technology that is objective, but I can't count the number of times that I thought that particular design choices made no sense until I understood why they were made. Before I understand, design choices often look awful. After I understand, my annoyance is often transformed into the realization that I'm probably getting more than I expected.
When I read My Problem with Git: No Abstraction this morning, I felt like it had the first part down. The author bemoaned many of the design choices in git. He's not alone. On any random day, I complain about 3-5 times about the git CLI. The thing that I do appreciate, though, is exactly the thing that the post was complaining about - the fact that, to use git effectively you have to understand its internal model.
Let me backtrack for a minute.
A few years ago, I was at a conference and I heard a keynote by Simon Peyton-Jones of Haskell fame. It was an odd keynote. Often keynotes at technical conferences try to skate into light topics. You rarely see code, and you are rarely asked to think very hard. That's often reserved for the sessions. Peyton-Jones' keynote, however, took no prisoners. He started with the notion of classes in OO and then proceeded to show us how type classes were implemented in the GHC implementation of Haskell (which Simon does extensive work in). What we had at the end of the keynote was a good operational understanding of type classes. It was nice, concise, and a far more effective approach to the subject than what I've ever seen in Haskell books. Haskell books often try to give you the semantics of the constructs, helping you build the mental model you need as a programmer in order to be able to use them. But, that definitely isn't a very complete picture.
At the conference, I turned to a friend of mine and said "you know, more people should explain languages this way.. in terms of an idealized implementation. The understanding is much deeper."
Perhaps it's me. When I learned C, I learned it from a book which explained memory and showed how pointer manipulation affected memory using little drawings of grids and arrows. When I learned C++, I was glad to learn about vtables. Understanding them and how they operated in single and multiple inheritance made it much easier to develop an intuitive sense of whether something was or was not possible in the language, or in other languages.
I feel that git has the same quality. Linus could have chosen to hide the implementation model more deeply. It could have been opaque like other version control systems, but I think it is nice that he didn't. After all, we are programmers. We don't need models that protect us from internal technology. On the contrary, we gain leverage when our tools have consistent implementation models and they are transparent to us. They help us reason.
So, I don't think it is the case that git and the Unix commands mentioned in the post have leaky abstractions. You're expected to know the model. The model is the primary way of understanding the system.