Git is a distributed version control system created by Linus Torvalds in 2005, in approximately two weeks, because the previous version control system used by the Linux kernel had a licensing dispute and Linus decided that writing a new version control system from scratch was easier than resolving a licensing dispute, which tells you everything you need to know about Linus Torvalds and nothing you didn’t already suspect.
Git is the most important piece of infrastructure in modern software development that nobody understands. Every developer uses git. Every developer uses approximately five git commands. The five commands are: clone, add, commit, push, and pull. Everything else — rebase, cherry-pick, bisect, reflog, the entire object model of blobs, trees, and commits stored as a content-addressable filesystem — exists in a layer of git that most developers have heard of, some have used, and twelve people worldwide actually understand.
This is fine. You do not need to understand the combustion engine to drive a car. You do not need to understand git’s directed acyclic graph to write software. You need clone, add, commit, push, pull, and the phone number of someone who understands reflog for when you inevitably run something you found on Stack Overflow and your repository enters a state that git describes as “detached HEAD” and you describe as “oh no.”
“Git is a tool I use as much as I need and learn as few ways to shoot myself in the foot with as I can.”
— riclib, who has 200+ repositories and five git commands
The Five Commands
The honest git tutorial:
git clone — Download a repository. You will do this once per project. It works. Move on.
git add — Stage files for commit. git add . stages everything, which is fine until you accidentally stage .env with your API keys. Then it is not fine. Then you learn about .gitignore, which should have been the first thing you learned.
git commit — Save a snapshot. Write a message. The message should describe what you did. “fix” is not a message. “fix the thing” is barely a message. “Fix null pointer in user authentication when session expires during OAuth callback” is a message. Most commits say “fix.”
git push — Send your commits to the remote. This is the moment your code becomes other people’s problem. If you push to main and the tests fail, you will hear about it. If you push --force to main, you will hear about it louder and from more people.
git pull — Download other people’s commits. Sometimes this works cleanly. Sometimes this produces a merge conflict, which is git’s way of saying “two people changed the same line and I am not going to guess which one is correct, because the last time a version control system guessed, someone lost a week of work.”
These five commands are sufficient for a solo developer, which is what most developers are most of the time — even developers on teams, because the team uses branches, and branches are solo development with a merge at the end.
The Other Commands
The commands that exist for the twelve people who understand git’s object model, and for the rest of us when something goes wrong:
git branch / git checkout / git switch — Create and move between branches. The fact that there are three commands for related operations, and that checkout does seven different things depending on the arguments, is a design decision that Linus made in two weeks and the rest of us have lived with for twenty years.
git merge — Combine two branches. Works perfectly when nobody has touched the same files. Works imperfectly when everyone has touched the same files. The merge conflict is not git’s fault. The merge conflict is the natural consequence of two humans disagreeing about line 47.
git rebase — Take a branch, detach it from where it started, and reattach it somewhere else. Makes the history look cleaner. Also rewrites history, which means push --force, which means you are now the person mentioned in the warning labels.
git stash — Hide your uncommitted changes temporarily. The drawer where half-finished work goes. The drawer has no bottom. Work goes in and is forgotten. git stash list shows you things you hid six months ago and no longer remember.
git reflog — The flight recorder. Every HEAD movement is logged. When you have destroyed your branch, rebased into oblivion, or force-pushed your way into regret, reflog is the command that can get you back. It is the command you google at 11 PM with the search query “git undo everything.”
git bisect — Binary search through commits to find which one introduced a bug. Brilliant in theory. Requires that each commit compiles and passes tests. Most repositories do not have this property. git bisect is the sports car parked in a city with no roads.
The Model
Git stores everything as objects in a content-addressable filesystem. A commit points to a tree. A tree points to blobs (files) and other trees (directories). A blob is the content of a file, addressed by its SHA-1 hash. Branches are just pointers to commits. Tags are just named pointers. HEAD is a pointer to the current branch, which is a pointer to a commit, which points to a tree, which points to blobs.
If you understood that paragraph, you are one of the twelve. If you did not, you are one of the millions, and you are in excellent company, and your software is no worse for it.
The model is elegant. The model is also the reason that git’s interface is confusing — the commands are operations on a graph of content-addressed objects, and the names of those commands (checkout, reset, revert) were chosen by a person who understood the graph and assumed everyone else would too. They did not. Twenty years later, git added switch and restore as friendlier alternatives to checkout, which is an admission that the original names were wrong, delivered two decades late, in the git tradition.
The Foot-Guns
Git’s most dangerous commands, ranked by the frequency with which they destroy someone’s afternoon:
-
git push --force— Overwrites the remote history with your local history. If anyone else has pulled since your last push, their work is now in conflict with a history that no longer exists. The--force-with-leasevariant is slightly safer. Neither should be used onmain. -
git reset --hard— Discards all uncommitted changes. There is no confirmation. There is no undo. The changes are gone.reflogcan recover committed work, but uncommitted changes that were never staged are gone forever, in the way that things are gone when they were never recorded. -
git rebaseon a shared branch — Rewrites history that other people are building on. Their next pull will produce conflicts that are not merge conflicts but reality conflicts — the history they are working against no longer exists. -
git checkout .— Discards all unstaged changes in the working directory. Looks innocent. Is a delete command wearing a version control hat.
The pattern: git’s dangerous commands are the ones that destroy information. Git is excellent at preserving information — that is its job. The commands that destroy information are the exceptions, and they are the ones that bite.
“Git has two modes: boring and terrifying. The boring mode is five commands and it works. The terrifying mode is everything else. Stay in boring mode.”
— The Lizard, who versions nothing and remembers everything
Measured Characteristics
Creator: Linus Torvalds (2005, two weeks, out of spite)
Commands in git: 150+
Commands you need: 5
Commands you'll use in a crisis: 1 (reflog)
People who understand the object model: 12 (worldwide, estimated)
Repositories on GitHub: 400+ million
Average commit message quality: "fix"
Force pushes to main (per day): thousands (each one a small tragedy)
Time to learn git: five commands: 30 minutes
Time to understand git: the rest of your career
.gitignore files longer than the code: common
Detached HEAD incidents (per year): millions
Developers who know what HEAD is: fewer than you'd think
See Also
- GitHub — The platform that made git social. The remote that 90% of developers push to. The company that Microsoft bought for $7.5 billion, which is a lot of money for a website that hosts text files.
- Git Worktrees — The most useful git feature nobody knows exists. Multiple working directories from a single repository. The reason your four AI agents don’t need to stampede the same checkout.
- Linux — The project git was built to manage. The kernel that started git’s existence. The reason Linus was angry enough to write a version control system in two weeks.
