All writing
Software EngineeringApr 26, 2026·12 min read

Git Is Not Your Enemy (You Just Never Learned It)

Most of us learned four git commands by panic and have been bluffing ever since. Here's the mental model that makes it click.

Be honest. Your git knowledge is add, commit, push, pull, and a deep, primal fear of anything else. When something goes wrong you either delete the folder and re-clone, or you paste a Stack Overflow incantation you don't understand and whisper a prayer to the merge gods.

It doesn't have to be like this. Git isn't hard — it's just badly introduced. Nobody tells you the model; they just hand you commands and wish you luck. Let's fix the model.

01

Git is a graph, not a folder of saves

Here's the whole secret: a git repo is a graph of *commits*. Each commit is a snapshot of your project plus a pointer to its parent. That's it. Strung together, commits form a chain — history. Branches and tags are just sticky notes pointing at specific commits.

A branch is not a copy of your code. It's a sticky note on one commit in the graph. That single reframe fixes half your git anxiety.

When you commit, git makes a new snapshot and moves your branch's sticky note forward to it. When you switch branches, you're just moving HEAD — a sticky note that points at *which sticky note you're currently on*. Once you see the pointers, the commands stop being spells.

02

The cast of characters

  • Commit — an immutable snapshot + a pointer to its parent. The atom of git.
  • Branch — a movable pointer to a commit. Cheap. Make them constantly.
  • HEAD — a pointer to the branch (or commit) you're currently on.
  • The index (staging area) — the waiting room where changes sit before they become a commit.
03

Merge vs rebase, finally

Both combine work from two branches. They just tell different stories. Merge ties the two histories together with a merge commit — honest, preserves exactly what happened, slightly messy graph. Rebase replays your commits on top of the other branch — clean, linear history, but you're rewriting commits, so never do it to shared/public branches unless you enjoy ruining a colleague's afternoon.

merge-vs-rebase.sh
# merge: keeps both histories, adds a merge commit (truthful, can get tangled)
git checkout feature
git merge main

# rebase: replays feature's commits on top of main (clean, linear, rewrites history)
git checkout feature
git rebase main   # never rebase a branch others have pulled

Note

Rule of thumb: rebase your *local, private* work to keep it tidy before sharing. Merge when combining *shared* branches. 'Rebase locally, merge publicly' will keep you out of trouble.

04

Almost nothing is ever lost

The thing that makes git scary is the feeling that one wrong command nukes your work. It almost never does. Git keeps a log of everywhere HEAD has been — the reflog — so even 'lost' commits are usually sitting right there, waiting to be recovered.

undo.sh
# 'I think I deleted my work' — you probably didn't
git reflog                 # every place HEAD has been, with hashes
git checkout -b rescue abc123   # resurrect that commit onto a new branch

# 'I committed to the wrong branch'
git reset --soft HEAD~1    # undo the commit, keep the changes staged

# 'I need to undo a pushed commit safely'
git revert <hash>          # new commit that reverses it (doesn't rewrite history)

Heads up

reset --hard and force-push are the two commands that can actually lose work. Respect them, double-check the branch you're on, and you'll be fine. Everything else is recoverable.

05

Commit like you're leaving notes for a friend

Small, focused commits with messages that say *why*, not *what* (git diff already shows the what). Future-you reading git log during an incident will either thank or curse past-you, and it costs the same effort to be kind.

06

Aliases that pay rent

Once the model clicks, a few aliases make the day-to-day frictionless. These four live in my config and I'd genuinely miss a finger more than them:

~/.gitconfig
[alias]
  s = status -sb              # compact status
  lg = log --oneline --graph --decorate --all   # see the actual graph
  last = log -1 HEAD          # what did I just commit?
  undo = reset --soft HEAD~1 # take back the last commit, keep changes

git lg especially — it draws the commit graph right in your terminal, and once you *see* the branches and merges as a shape, every earlier paragraph in this post turns from theory into something you can point at.

07

Stash is your panic button

Mid-change and suddenly need to switch branches for a hotfix? Don't commit half-baked work. git stash pockets your changes, leaves you clean, and git stash pop hands them back when you return. It's the 'hold this for a sec' of version control.

Learn the model and git transforms from a minefield into what it actually is: a time machine with excellent undo. You stop fearing it and start using it as the safety net it was built to be.

Key takeaways

  • 01Git is a graph of commits; branches and HEAD are just movable pointers.
  • 02Rebase locally to keep history clean; merge publicly to avoid rewriting shared work.
  • 03Almost nothing is truly lost — the reflog can recover 'deleted' commits.

FAQ

EngineeringGitWorkflowVersion Control

Related reading