Getting better at git once the basics are covered
April 11, 2021•1,144 words
git learning curve is weird
One can understand the benefits of using a Version Control System (VCS) in minutes, be familiar with the main commands in a few hours, but it can take years before confidently running a command with --force
.
Worse, sometimes you just don't know that a command exists, one that could save you hours!
I had an ahah! moment three months ago when discovering git bisect, it helps you find a faulty commit in O(log(N)) steps, where N is the number of commits to inspect. Instead of checking-out every commit, binary search helps you reduce the number of commits to check. With a build time of 7mins on a c++ project, each rebuild I could avoid was worth it.
Sometimes the surprise is even bigger as you discover not a command, but an argument of a command you use everyday. Yeah, I'm looking at you git log -S. I discovered the git pickaxe a few weeks ago, after 3+ years of using git. This gem saved me 15+ mins at its first use. Philip Potter has a great intro for the git pickaxe command in his blog post
Understanding the git learning curve
We can break down git's learning curve in three steps:
- The initial learning curve
- A plateau once you master the basics
- A stairway-like shape where each bump means mastering an advanced concept
Let's break this down
During the initial learning curve, you're interested in becoming operational with git promptly. You learn the basics for creating a branch, adding changes, committing, push/pull and that's usually good enough to get working on a project within a team.
Once you're familiar with those 101 skills, you enter a plateau. Indeed, the commands above address 80% of your needs with a little time investment. Following the 80/20 principle, mastering the remaining 20% would be a lot of efforts with little substantial gain. This is especially true if you're lucky enough to have a git guru in your team. You know, this person you can come to and ask for help when your repo is in a terrible state and you seek redemption, we've all been there (:
Eventually, you'll want to fix your repo state by yourself instead of asking the local git guru. That's your first step in the stairway to git mastery. You'll put the energy required to understand once and for all how git reset works and what's the difference between
git reset --soft
andgit reset --hard
. Each of those little victories is a step forward in your path towards git mastery.
Progress in git comes from the willingness to confront yourself with a repo state you'd rather avoid. The more challenging repo states you encounter, the more likely you are to understand git internals.
How to encounter bumps more often?
Problem: when you're working on a feature and must ship asap, you are not incentivized to learn all the internals of how git works when a corrupted repo state arises. You're more interested in solving the issue at hand.
So we go to Stack Overflow, copy/paste the most relevant one liner, and give a +1 to its author. Problem solved. Or is it? Next time a similar bump arise we're likely to go for that one-liner copy/paste once again. We can do better.
I found two tricks to make room for learning advanced git techniques:
- Practice on a toy repo where I don't care about breaking things.
Use the amazing Learning Git Branching tutorial to develop visual intuition over what a command does.
As git is mostly trees and pointer to nodes, a graph visualisation is super helpful to demystify an obscure command you'd be afraid to run otherwise.
Also, I found that the Atlassian doc on advanced git usage is amazingly well written and easy to digest. It's not exhaustive but it does a better job at conveying the intuition behind a command compared to the official git doc IMO.
Practice makes perfect
At each corrupted repo state or complex branching, rebasing, etc. operation you encounter: give it a solid 10 mins of thinking and make sure you leave the situation with a clear understanding of what the problem was, how you solved it and how you'd solve it if it appeared again.
You can take notes of it, blog about it, or answer a related SO questions to help you commit to this learning ritual.
Closing thoughts
Think at what Rousseau said in his Discours sur l’origine et les fondements de l’inégalité parmi les hommes, 1755:
"Laissez à l’homme civilisé le temps de rassembler toutes ses machines autour de lui, on ne peut douter qu’il ne surmonte facilement l’homme sauvage ; mais si vous voulez voir un combat plus inégal encore, mettez-les nus et désarmés vis-à-vis l’un de l’autre, et vous reconnaîtrez bientôt quel est l’avantage d’avoir sans cesse toutes ses forces à sa disposition, d’être toujours prêt à tout événement, et de se porter, pour ainsi dire, toujours tout entier avec soi."
An approximate english translation:
"Allow the civilized man time to gather all his machines around him, there can be no doubt that he easily overcomes the savage man; but if you want to see an even more unequal fight, put them naked and disarmed vis-à-vis each other, and you will soon recognize what is the advantage of having all your strength constantly at your disposal, to be always ready for any event, and to carry oneself, so to speak, always completely with oneself. "
The "civilized man" would be the you using an IDE with a nice git GUI. The "savage man", would be the you using git commands in the terminal.
For mundane tasks, the IDE enhanced approach can help you gain time. But be wary that when things get complicated, like in case of merge conflicts or for investigating the root cause of a bug, using the git CLI will be a powerful tool.
As scary as they look at first, it's by taking the time to decipher new git commands you encounter that you become more proficient with the tool.
Protips
- Setting an
alias
for long git commands can remove the friction preventing you from using them regularly in the terminal. My personal favorite is an alias forgit log
with nice formatting:
alias glola="git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --all"
As an illustration, let's say I'd like to see the commits I made over the past two days on a repo: I'd type glola --since="two days"
.
The OhMyzsh
framework has a git plugin with tons of aliases. I just use a subset of them but it's already a huge gain in time. Here is a list of useful git aliases.