Advertisement

Plenty of developers get by with three commands: add, commit, push. That works until the day something goes wrong — a bad merge, a change committed to the wrong branch, a file you did not mean to include. In those moments the difference between panic and a calm two-minute fix is knowing a slightly wider slice of Git.

None of these require deep internals. They are everyday tools that turn Git from a thing you fight into a safety net you trust.

Seeing where you are

Before changing anything, look. Status shows what is staged, modified and untracked. Diff shows the exact lines you are about to commit, which catches stray debug code and accidental edits before they enter history. Log, especially in its compact one-line form, shows the shape of recent history so you know which commit is which.

Understanding the current state is half of using Git well. Most destructive mistakes happen because someone acted on an assumption about what was staged or which branch they were on. A five-second look replaces the assumption with a fact.

Advertisement

Undoing safely

To discard uncommitted changes to a file, restore it. To unstage something you added by mistake without losing the work, restore it from the staging area. To keep changes but move them off the current branch, stash them, switch, and pop them back — invaluable when you started work on the wrong branch.

For commits, reset moves the branch pointer: a soft reset keeps your changes staged, a mixed reset keeps them in your working files, and a hard reset throws them away — powerful and the one to respect. When you have already shared a commit and want to undo it without rewriting shared history, revert creates a new commit that cancels it out, which is the polite choice on shared branches.

The recovery net most people miss

The command that saves careers is reflog. Git records almost every move of your branch pointers — commits, resets, checkouts — for weeks, even ones that seem lost. If a reset or rebase appears to have destroyed work, the reflog usually still lists the commit you were on, and you can return to it. Very little is ever truly gone in Git while the repository exists.

Knowing that safety net is there changes how you work: you experiment more freely, because you know how to get back. That confidence, more than any single command, is what separates people who tolerate Git from people who use it well.

Advertisement

`git reflog`: the safety net most developers never knew they had

The reflog records every place HEAD has pointed within a repository, including states that no longer have any branch or tag referencing them — an accidental hard reset, a botched rebase, a deleted branch — and `git reflog` followed by `git reset --hard` to a listed entry is the standard recovery move for exactly the kind of mistake that feels catastrophic in the moment but is, in the overwhelming majority of cases, fully recoverable because the reflog kept a record of where things stood before.

`git bisect`: automating a debugging process that used to be entirely manual

Finding which of hundreds of commits introduced a regression used to mean manually checking out candidate commits one at a time and testing each by hand — `git bisect` automates the entire process with a binary search, asking at each step whether the current commit is good or bad and converging on the exact culprit commit in a logarithmic number of steps rather than a linear one, which turns what could be an afternoon of manual checkout-and-test cycles into a few minutes of automated narrowing.

Advertisement

`git stash` with a message and `--include-untracked`, not just the bare command

A bare `git stash` is useful for quickly setting aside work, but two refinements make it considerably more useful in practice: naming a stash explicitly with `git stash save "description"` so a growing pile of stashed changes stays identifiable rather than an anonymous list of indistinguishable entries, and including untracked files with `--include-untracked` when a genuinely complete snapshot of in-progress work, not just already-tracked file changes, needs to be set aside.

`git worktree`: working on two branches at once without a second clone

Needing to quickly check something on a different branch while genuinely in-progress work sits on the current one traditionally meant either stashing that work or cloning the repository a second time — `git worktree add` instead creates a second working directory linked to the same underlying repository, letting two branches be checked out and worked on simultaneously without duplicating the object database or disturbing whatever is currently in progress on the original working directory.

`git cherry-pick`: moving one specific fix without merging an entire branch

A hotfix committed on one branch that also needs to land on a release branch does not require merging the entire branch it was committed on — `git cherry-pick <commit>` reapplies just that one commit's changes onto the current branch as a new commit, which is exactly the right narrower tool when only a single, specific change needs to travel between branches rather than an entire branch's worth of history.

`git rebase -i` for cleaning up local commit history before it is ever shared

An interactive rebase lets a sequence of local, not-yet-pushed commits be reordered, combined, or edited before they are shared with anyone else, which is precisely the tool underlying the squash-before-merge discipline discussed at more length in this library's commit-message articles — the critical caveat is that rewriting history this way is only safe on commits nobody else has already based work on, since rewriting shared history creates real, painful divergence for anyone who already has the original commits.

`git blame` combined with `-w` and `-M` for cutting through noise

A plain `git blame` attributes every line to whoever last touched it, which can point at a purely cosmetic reformatting commit rather than the actual author of the meaningful logic — passing `-w` ignores whitespace-only changes and `-M` detects moved or copied lines, both of which skip past noise commits and attribute a line to the commit that actually introduced its substantive content, which is considerably more useful than blaming whoever happened to reformat the file most recently.

`git log --graph --oneline --all` for actually seeing branch structure

A plain `git log` shows a linear list that hides how branches actually diverged and merged, while adding `--graph` draws the actual commit topology with ASCII branch lines, `--oneline` keeps each commit to a single readable line, and `--all` includes every branch rather than just the current one — together these turn an otherwise abstract mental model of branching into something directly visible on screen, which is often the fastest way to understand a confusing repository history at a glance.

`git add -p` for staging exactly the right changes, hunk by hunk

Staging an entire file at once with `git add` forces an all-or-nothing choice even when a file contains two unrelated changes that should really belong to separate commits — `git add -p` walks through each individual hunk of changes and asks whether to stage it, letting a single working-directory file be split cleanly across several atomic commits, which is precisely the discipline the commit-message articles elsewhere in this library argue is worth the small extra effort.

`git diff --stat` for a quick sense of a change's scope before diving in

Running `git diff --stat` before the full diff gives an immediate summary of which files changed and by roughly how much, which is a useful first orientation step before reading the actual line-by-line diff, especially for a large or unfamiliar change — knowing upfront that a change touches three files with a handful of lines each versus one file with hundreds of lines sets very different expectations for how the review that follows should actually proceed.

`git show` for inspecting a single commit without checking anything out

`git show <commit>` displays a specific commit's full diff and metadata without touching the working directory or moving HEAD at all, which is the quickest way to inspect what a particular commit actually changed when investigating history, rather than checking it out directly and risking disturbing whatever is currently in progress in the working directory.

Why these commands are worth learning before they are urgently needed, not during a crisis

Every command covered in this article is far easier to learn calmly, in a low-stakes moment, than to look up for the first time while already in the middle of a stressful situation it was meant to help resolve — deliberately practicing `reflog`, `bisect`, and the rest on a low-stakes personal repository before they are ever genuinely needed is what makes them actually usable under pressure rather than commands only vaguely remembered from having read about them once.

Why aliasing these commands to shorter names removes the last barrier to actually using them

Knowing a command exists is not the same as reaching for it reflexively under pressure, and a long, easy-to-mistype command name is a small but real barrier to that reflex forming — binding a short git alias to each of the commands covered in this article removes that last friction, turning knowledge into an actual habit considerably faster than leaving each one as a long command that has to be recalled and typed out in full every time.

Why keeping this list short and memorized beats a longer list only ever looked up

A cheat sheet of thirty git commands, consulted only when needed, provides far less practical value than a shorter list of the handful covered in this article genuinely committed to memory, since a command that has to be looked up mid-crisis adds exactly the delay and friction the command was meant to remove — depth of familiarity with a few essential commands beats shallow awareness of many.

Why practicing these on a disposable test repository removes the fear of trying them for the first time

Cloning a throwaway repository specifically to practice `reflog`, `bisect`, `rebase -i`, and the rest removes the understandable hesitation to experiment with commands that sound destructive on a repository that actually matters — a few minutes of deliberate practice somewhere consequence-free is what turns commands only read about into commands genuinely trusted under real pressure later.

Why a short internal doc listing these commands with real examples beats relying on memory alone

Even with deliberate practice, an exact flag or argument order can still slip from memory months later when a command is finally needed for real — a short, team-maintained internal reference with real, copy-pasteable examples for each command covered in this article bridges that gap, giving a faster path back to correct usage than searching general documentation from scratch under pressure.

Why this article's commands are worth revisiting whenever a new git version ships

Git itself continues to add new convenience commands and improve existing ones, and periodically checking release notes for genuinely new capability, rather than assuming the command set learned years ago remains complete, keeps a developer's toolkit current with a tool that is still actively evolving rather than frozen at whatever was current the last time it was seriously studied.