Two Commits and the User Experience of Git
redfin.engineering
redfin.engineering
Why call the maintainer out by name (and continually do so throughout the essay)? What purpose does that serve? To embarrass him for volunteering his time on an open source project that you've built your business on, just because you didn't like these two features he added? There was no personal behavior of his at play; he simply made some technical choices you disagree with.
Keep it technical, dude. This is ad-hominem and smug.
Naming the maintainer would make sense later on when the author purportedly tries to get into contact with Hamano but, spoiler alert, fails at it.
Elsewhere in codeland we usually say "this code is doing the wrong thing" not "Bob did the wrong thing."
It's not like someone as storied as Junio, who has maintained git for as long as its been a serious project with applications beyond the kernel, risks being fired because he made a handful of questionable decisions. He is, after all, only human. Only the insecure fret over every shed of blame.
It is, in fact, considered rude to circumvent/bypass/ignore the original author by saying "the code was wrong" without first giving the author a chance to explain the rationale.
Ultimately, the point at which "naming" transitions into "shaming" in a technical discussion is a matter of interpretation and balance, but I don't think we need to completely remove considerations of code parentage from technical discussions, which you seem to be advocating.
As counterpoint, I didn't interpret it that way. The tone wasn't shaming a programmer for accidentally screwing up (e.g. It was Michael who deleted everything with UNIX command "rm -rf /* ").
Instead, today's blog was extending the conversation of the message he sent 3 months ago[1] and he had already put Junio Hamano's name in that post.
If you're trying to trace the intellectual history and rationale for why things were done a certain way, attaching a name to it is very common and it does not mean malicious intent.
I didn't see any ad-hominem attacks in the post but I can only guess that the repetition of "Hamano" in the text rubs people the wrong way.
[1] https://public-inbox.org/git/EA993AC0-022C-423D-ABD7-4747FA0...
This was posted on Redfin's official blog by a "Principal Engineer", which is even worse and reflects poorly on Redfin. Does Redfin shame engineers by name when things do not work out? If a higher up is reading this you should rethink your engineering blog ASAP.
(sorry, it's a huge pet peeve of mine, every technical article has to be an ad as well)
i hope i have a commit so controversial someone blogs about it 13 years later. i'd be equally happy to respond with a defense or concession. :)
it struck me as an irrelevant fact- not an attack. so i can't help but wonder if you all aren't taking more offense than the guy who made the commit himself.
> Well, I posted a question on the Git mailing list to ask, but the Git mailing list is so noisy that I doubt that anybody will ever answer my question, least of all Hamano. But I can speculate as to why; if I were Hamano, I probably would have made the same mistake.
And no, posting to the mailing list, which the author himself admits is too noisy for the commiter to have likely noticed, is not a real effort to make contact given the severity and self-assured nature of the assertion, which suggests to me that the author is lazy in other ways that make his analysis suspect. Seriously, the author is so cocksure about the problem, and yet too timid to email Hamano, who is on Github and has a listed email address?
It's an appalling lack of basic courtesy, never mind intellectual curiousity.
Despite this, I'll respond to you with basic courtesy.
As a maintainer of open-source projects myself, I hate it when people email me directly with questions. I ask that everyone use only public channels of communication, if only because that way everyone can benefit from hearing the answers. In my opinion, I showed courtesy and not "timidity" by not spamming Hamano's personal inbox.
However, I recognize that not everyone feels this way, and so I have taken your point and I have emailed Hamano directly. (I hope he doesn't mind.) If he responds either on the git list or to me privately, I'll update the post.
Probably wasn't worth calling out the maintainer by name (or the hyperbole in the title, but clicks!) but at the end he explains that reading a interview with Junio how Git evolves and isn't really designed.
Even has a solution to the Git problems he sees "easy git" (which I had never heard of).
"Come work with us! We'll only be sure to publicly humiliate if you make a technical decision we disagree with!"
History is about people making decisions. It wouldn't make sense to write about the history of nations without naming any names, and I think it wouldn't make sense here, either.
Second, while I am critical of these historical decisions, I don't purport to be better than Hamano. There's a whole section of this post saying that "you or I might have done the same thing" for the same reasons.
I especially don't accept your charge that this is "ad hominem." I don't argue that you should agree with me because who Hamano is. I don't (and wouldn't) call Hamano any names, call doubt on his character, or even question his intelligence or competence.
Everyone should evaluate these historical decisions on their own merits. But anyone who wants to understand why git works the way it does must understand that these are Hamano's decisions, and decide for themselves whether these decisions were good or bad.
EDIT: A number of comments here have said that the complaint has to do with the number of times I mention Hamano's name, so I've updated the post to remedy this.
The issue, I think, is that the specific name doesn't really add anything to the discussion: you don't actually contact Hamano and get his perspective, and you don't use the name to link any additional relevant information. You could omit the name entirely without detracting from what you're trying to say.
Including the name makes the (public!) criticism needlessly personal. Not really cool.
> History is about people making decisions. It wouldn't make sense to write about the history of nations without naming any names, and I think it wouldn't make sense here, either.
Historians usually do quite a bit more research, including talking to participants. Much more context would be required before zeroing in on one person and saying it's his fault. Was there discussion beforehand? Why has no one changed it thus far? All you did was post to a noisy mailing list from which you expected no reply, then assumed that it was solely the committer's decision.
> I don't (and wouldn't) call Hamano any names, call doubt on his character, or even question his intelligence or competence.
But that's done implicitly when you tie his reputation up so thoroughly with choices that you wrote an entire essay disparaging. The damage is magnified when he's not given a real opportunity to explain himself. Although you stated in another comment you've now emailed him directly, which is a good call.
I think a separate command would have been convenient, too. ¯\_(ツ)_/¯
I didn't know that 'git reset' has a similar problem.
If git gained the 'checkout-tree' and 'checkout-file' (and other) commands mentioned, I'd personally use them instead of checkout.
Those 2 commands would be a great idea.
(Amusingly, the author begins by admitting he wrote a whole book on Git - and perhaps the most popular one - before strongly understanding this himself.)
It shouldn't be so complex to indicate you've copied files from Github, made a personal copy to work on, and have switched to that copy. But this involves finding where your Head is, having an Origin, a Master, and somewhere Remote, finding the right branch in the tree to hit with a fork, and going to a checkout counter.
I consider myself fairly good with Git, having used many (but nowhere near all) of it's more advanced features, some of them regularly - but this is a new one to me.
The double dash typically indicates all CLI flags/options have been provided, and the remainder should be treated as positional arguments. However, a single . isn't any standard CLI flag, so shouldn't need the --?
What am I missing? :)
Edit: I also googled it, as I thought up a reason why -- might be used. If I have a file called master, and want to unstage my changes to it, I would have to `git checkout master`. Given this command has multiple meanings, both of which could be appropriate, I'd need to disambiguate between them. The -- does exactly this, it prevents the tree-ish parsing.
Reminds me of one of my common complaints about that response. The difference is that 'rm' doesn't do anything but remove stuff---it removing things isn't surprising. If a command has multiple potential effect types, and only some of them are destructive, then good UI would offer a warning.
Again, never to prevent normal usage, but to focus on educating the various states of git, and really trying to make the commands very obvious for normal use cases.
I see so many of these.. I'm wondering if it's sort of a rite of passage. Maybe I should write my own? I'm sure I'd become more proficient at Git if I did.
edit: Since writing this, I think I decided on writing my own wrapper. Specifically, focused on a very small subset of straight forward commands with exceptionally obvious wording and step by step education.
I really like the way http://www.git-town.com documents their command usage, so I'll likely adopt that - but with the added feature of providing either inline or copy-paste commands to gain per-step documentation. Explaining the motive behind a command, and why it was used in that case. I also dislike how git-town layers their own UX, as I think an education wrapper's goal should be to improve education on normal git flows, not make new ones (automatic syncing, etc). Wish me luck lol.
P.S. - to those worried about what git wrappers are doing behind the scenes, in Magit you just press `$` to see the command log.
How? I use Magit too, and my go-to method for doing this would be an interactive rebase that only modifies the target commit. I'd love to know about a quicker way!
With that said, I definitely agree with you. This thing I'm discussing writing is a wrapper for the non-git users. I don't expect what I'm going to do to actually save normal/advanced users time, I expect those users to not even use a wrapper.
However, parsing the output of ls is generally a bad idea, as it's meant for human consumption, so ls breaks another tenet: It isn't very composable, as it is difficult to use it in a pipeline, even though it should be a prototypical source program.
last week i discovered the `-delete` flag. For years, i had been doing `find <stuff> | xargs -rm` instead.
I agree it's a bad idea (or if you do, at the very least make sure you're calling out to /bin/ls...), but it certainly happens.
Have a look at libxo, which tries to fix this exact issue. FreeBSD adopting it in the base system is encouraging. I hope Linux follows suit, as well.
The phrase "Unix Philosophy" is a concrete, functioning example of compositionality.
Git is a pretty heavyweight tool and many of its commands are not compositional or built up from many smaller functional units. Git repos also do not compose, which is a significant flaw.
One way to cast the ideological stance of the Unix philosophy is "simplicity of implementation at all costs"; the costs include memory unsafety, poor performance (of pipelines and shell scripts), code duplication, race conditions (look at the filesystem, a vast blob of global mutable state!). It's time we start fixing these problems and abandon the mistakes of Unix. Yes, composition is important, but you don't have to sacrifice so terribly much to get it.
Perhaps there is a better concrete example I haven't thought of. I'm curious to know what you think would be a better communication tool (this a serious question, I'm not baiting an argument).
As for "git checkout branch" and "git checkout -- branch" doing very different things, I find the "--" works well to bump my mental model into the right state, and so in practice I'm never confused about the distinction.
It also helps (a lot!) that "git status" teaches us about these modes for "git checkout --" and "git reset HEAD":
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: pom.xml
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes)
modified: src/main/java/com/bitbooster/FoxtrotHook.javaQuick quiz, what does: git checkout x/y do? At least:
* Reset a file called x/y
* Check out a branch y from a remote x
* Check out a local branch called x/y
This is news to me.
What a vacuous statement. If you use something incorrectly, it works incorrectly.
But what's nice is you can also (usually) revert your Git oopsie.
Still, I don't usually run into the problems described because I try to keep Git as simple as possible.
Git lasted almost a week. The last straw was when a junior developer accidentally deleted the main line repo. We switched to TFS and never had problems like that again.
But this problem continues to occur. Last year, working on an Ops team, team members started noticing their scripts were no longer present on production servers. It turns out a team member was modifying code and checking it in. The problem is that Git clobbers unchanged files, so he was unknowingly reverting changes.
After years of seeing numerous professional developers and engineers continuously have team-impacting, show-stopping issues using a tool, I must assume the tool is defective in some way.
Which, of course, is also potentially a problem with TFS, and a developer can similarly wipe out the repo if permissions allow them to.
I'll grant you that it's easier to go so with Git by doing something like push -f, so it's more important to have permissions right in that case.
> The problem is that Git clobbers unchanged files
Except it doesn't? I'm not sure what was broken in your case, but that's definitely not normal or expected Git behavior, and I can't think of any time I've seen anything like that. About the only case I can think of where Git insists on "modifying" random files is when line endings are mismatched, and the repo is not configured properly. But even then it's not lossy.
Git does this by design. There seems to be no concept of line-item uploads - either you have to push the whole fork or none of it. There seems to be no concept of "I haven't modified this file", and an assumption that a user will frequently be fetching and aware of the entire code base.
Some tools help with this awareness, by auto-fetching frequently, so you know when others have uploaded code and you need to merge the master back into your branch. (Err diff the mainline against your development copy, so you can integrate the upstream changes into yours.) Mandatory workflows like this should be automated as part of the tool, but here they are very clearly left manual.
If the developer is working directly in the main branch, then what you describe can happen - although even then, if someone else makes changes there, there would be a divergence, and push would simply fail, instead of overwriting those changes (unless you explicitly force it by using -f... but the whole point of having that switch is to be a safeguard against destructive operations).
So I'm still confused about the exact scenario here.
Whatever is confusing today will only be worse after more years of piling stuff on top.
Moreover, to mention the person's name ~10 times is extremely crass.
A "git checkout -- file" would revert your working tree copy to your staged copy, whereas a "git checkout HEAD -- file" would revert both your staged copy and your working tree copy to the unmodified copy.
There are other scenarios but this is by far the most common. The index (aka. staged files) can be thought of as a completely seperate copy of your working tree that can have arbitrary changes written to it independent of the working tree. It's just that in normal usage you're only ever copying to the index (via git add) FROM your working tree.
Is there anything truly destructive in git though? Unless there's a GC, you can still recover any unreferenced objects.