It feels like every couple days, I learn a new Git trick. (Sigh.)
I'm going to start a running thread indexing them, because (Git's defaults are so bad that) some of them are pretty big quality of life improvements!
A fun one I noticed recently is that they added `git switch <branch>` as a more intuitive replacement for checkout. Extra fun: `switch -m` moves your uncommitted changes (no more `stash/pop` dance!). Hoping this is a sign of more UI improvements to come!
Maybe my favorite: `git log --first-parent` shows history but *only merge commits*. Even if your repo doesn't squash-merge, this still gives a clean view of your history. A former coworker liked (our use of) this so much he wrote an explainer: …om.s3-website-us-east-1.amazonaws.com
(Caveat: this only works as long as you merge via `git checkout master && git merge --no-ff feature`)
As of git 2.29, `blame` also supports `--first-parent`. (Many of these improvements are recent--git is improving surprisingly quickly for 15yo software!)
If you do a codemod that touches many lines (e.g. introducing an auto-formatter) and you don't want to destroy your `git blame` info, the `blame.ignoreRevsFile` config var (or `--ignore-revs-file` option) lets you specify a list of commits to hide from blame.
If you want to work on two features at once--maybe because one of them has a long feedback cycle--then (a) try to shorten the cycle! but (b) if that fails, `git worktree` lets you maintain multiple checkouts of the same repository without having to do a full 2nd clone.
`git diff HEAD...main` shows the same diff as Github's pull request view. (Straight `git diff main` doesn't: if `main` has new commits, they show up in the diff too.)
Wave uses a monorepo, and I was trying to figure out if there's a way to hide certain parts of it on CI so that we could guarantee that the build only depends on a subset of files. Turns out there's a recently-added command, `sparse-checkout`, that can do that!
If you have files that you don't want to show up in Github's diffs, maybe because they're generated code, add them to your `.gitattributes` file with the attribute `linguist-generated=true`.
Git commands I use in helper scripts a lot:
• `rev-parse --show-toplevel`: get repo root dir
• `rev-parse <ref>`: show the commit id
• `merge-base <branch>`: show commit you branched off of
• `ls-files`: print all tracked files
• `rev-list`: print various sets of commits
Ooh, and I just learned that as of 2.29 `git bisect` understands `--first-parent` too! I think that might have been the last crucial command that was missing it?
Today I learned about `git restore`, which was released at the same time as `switch` and intended to replace the *other* use case for `checkout`. `restore FILE` discards unstaged changes, `restore -s SHA FILE` replaces FILE with the version from SHA.
PS: the coworker mentioned above is the excellent @dchudz who I forgot was on Twitter! Sorry for lack of credit! The post also exists as a prettier URL: davidchudzicki.com/posts/first-pa…
While I'm here, some more tips I remembered:
`git add -p` lets you interactively choose which parts of your file to stage/commit. If you e.g. fixed a bug in a file but also added a bunch of debug prints, with `add -p` you can commit only the fix & still keep the prints around.
I use `add -p` instead of `add .` so that I look at every change before committing, to make sure I don't accidentally commit changes intended to be temporary.
`git stash` also allows `-p` and lets you interactively select which changes to stash!
`git log -S search_term` gives you log entries whose diff contains `search_term`. If using `log --first-parent`, make sure to add `-m` so that git uses the right diff (this should be default, sigh). You prob also want `-p` to show the patch.
For many languages, Git has heuristics to try to figure out what function each line of a file is part of. You might remember these from the output of `git diff`.
Today I also learned a lesser-known fun fact: `git grep -p` will show you the function context of each matching line!
Happy @threadapalooza! 100 (tweet-sized chunks of) stories from trying to build mobile money in Ethiopia, Ghana, Nigeria, Senegal and Cote d’Ivoire.
(Minus the ones I’m not supposed to talk about :P)
It all starts in ~Sep 2015 with me pretending to be an accountant.
“Huh?” It turns out doing the accounting for an international money transfer business is hard. There is a normal way of doing this, but instead of trying to find out what that was, we were like, “this seems like it should be 100% automated! We’ll just do that.”
LOL
(This was part of our general take that hiring was for chumps, instead we’d scale ourselves by building internal tools)
So that’s how I ended up closing Wave’s 2015 books by spelunking through a homegrown database for 3mo with handwritten SQL and a half-baked Flask-Admin UI.
The advantages of pair programming are things like:
• Reducing risk of mistakes / doing things sub-optimally
• Sharing knowledge between the people who are pairing
• Making it easier to stay focused
None of these are programming-specific, except maybe that knowledge-sharing is unusually important (because benkuhn.net/blub/). I'd argue that the point about focus is *anti*-programming-specific: programming is much more conducive to flow states than most activities.
Today @Delta both:
(a) made me remove the p100 I was wearing underneath my valve-less cloth mask;
(b) let people around me wear masks under chins for hours 🤦♂️
So I was surrounded by maskless people + had a much less safe mask myself. 0/10 idiotic safety theater, fly elsewhere.
(Why try a p100? Based on a microcovid.org rec—it's easier to get a good seal with a P100 respirator than an N95, and they are better filters. The cloth mask protected others from outflow. But, silly me to do something that needed *thinking* to verify it was ok.)
Classic case of rules based on socially-approved talismans rather than effects on reality: 1. As I pointed out at the time, (their interpretation of) the policy was instructing me to *just remove* a layer of protection and this couldn't possibly make anyone safer.
When I was deciding on colleges, the top tier all seemed kinda the same, so I picked the picked the cheapest one.
In retrospect I think one of the biggest differences between them was actually housing policy
The details vary a lot and have a surprisingly big effect...
Harvard sophomores get randomly assigned to an upperclass dorm but can "block" with a group of up to 8. Dorms are small enough that blockmates will prob be your roommates for the next 3y. So after ~4mo on campus you basically guess at (+ audition for!) your "college friend group"
For some reason, while applying, this did not strike me as an obviously terrible idea, or at least not "could substantially affect outcomes" level terrible. It was though. A single decision, w/ limited info + lots of politics, basically determines your college friend group.
As a Kube noob who's been cut by a few sharp edges, this type of battle report was super useful to me :) Some stuff I learned:
Their backend is a monolith but they route different collections of endpoints to different nodepools—this is a clever way I'd never thought about to limit the blast radius of performance issues (not Kube specific either, and may be a common practice I'd just never heard of!)
GKE regional clusters incur big bandwidth charges for cross-AZ traffic; you can avoid by using multiple zonal clusters
TBH it doesn't look *that* awful from the chart—the egress it shows costs <=5k/mo and I'd guess Git storage is near-pathological for this—but useful warning