gitGood.dev
Tools

Git Essentials

ToolsFREELast updated: June 2026 · By gitGood Editorial

The everyday commands, every undo scenario mapped to its fix, rebase vs merge with a side to pick, interactive rebase, bisect, the reflog safety net, stash, and the flags worth aliasing.

Why this matters

Git fluency gets probed two ways: directly ("what's the difference between rebase and merge," a near-universal screen question) and indirectly - pairing sessions and take-homes where the reviewer watches you drive. The mental model that makes all of it click: a commit is an immutable snapshot, a branch is just a movable pointer to a commit, and HEAD is a pointer to the branch you're on. Almost nothing in git is destructive once committed - the reflog keeps everything reachable for ~90 days.

Everyday commands

CommandWhat it doesCommon flagsExample
git statusWorking tree vs index vs HEAD. Your home screen.-s (short), -sb (short + branch)git status -sb
git logCommit history of the current branch.--oneline, --graph, --all, -p (patches), -n 5, --author, -S 'string' (pickaxe: commits that add/remove the string)git log --oneline --graph --all -n 20
git diffUnstaged changes by default.--staged (index vs HEAD), main...HEAD (what your branch adds), --stat (summary), -w (ignore whitespace)git diff --staged
git addStage changes into the index.-p (interactive hunks - stage partial files), -A (everything), -u (tracked only)git add -p src/lib/auth.ts
git commitSnapshot the index.-m 'msg', -v (show diff in editor), --amend (rewrite last commit), --amend --no-edit (add staged files, keep message)git commit -v
git branch / switchList / create / delete branches; switch moves HEAD. switch replaces the branch-related half of checkout.branch -d (delete merged), -D (force), -vv (show upstreams). switch -c (create + switch), switch - (previous branch)git switch -c fix/login-redirect
git restoreDiscard working-tree changes or unstage. Replaces the file-related half of checkout.--staged (unstage), --source=<commit> (restore from a commit)git restore --staged src/app/page.tsx
git fetch / pullfetch downloads remote refs without touching your work; pull = fetch + merge (or rebase) into the current branch.fetch --prune (drop deleted remote branches), pull --rebase (rebase instead of merge)git pull --rebase origin main
git pushUpload commits to the remote.-u origin <branch> (set upstream on first push), --force-with-lease (safe force - fails if remote moved), --tagsgit push --force-with-lease
git mergeJoin another branch into the current one.--no-ff (always create a merge commit), --squash (stage as one commit), --abort (bail out of conflicts)git merge --no-ff feature/comp-calculator
git rebaseReplay your commits on top of another base.-i (interactive), --onto, --abort, --continue, --autostashgit rebase -i origin/main
git cherry-pickApply specific commits onto the current branch.-x (record source hash), -n (apply without committing), --abortgit cherry-pick abc1234

Undo scenarios

Match the situation to the fix. Rule of thumb: revert for pushed/shared history, reset for local-only history, restore for the working tree.

Committed to the wrong branch
git switch correct-branch && git cherry-pick <hash>, then back on the wrong branch: git reset --hard HEAD~1. If the right branch doesn't exist yet: git branch new-branch first, then reset the wrong one back.
Typo in the last commit message
git commit --amend -m 'fixed message'. Only if not pushed - amending rewrites the hash.
Forgot a file in the last commit
git add the-file && git commit --amend --no-edit.
Undo last commit, keep the changes
git reset --soft HEAD~1 (changes stay staged) or git reset HEAD~1 (mixed - changes back in working tree, unstaged).
Undo last commit, discard the changes
git reset --hard HEAD~1. Destructive to uncommitted work - check git status first. The commit itself is still recoverable via reflog.
Undo a commit that's already pushed
git revert <hash> - creates a new commit that inverses the old one. Never reset shared history; revert is the only polite option on main.
Unstage a file (keep edits)
git restore --staged path/to/file.
Throw away local edits to a file
git restore path/to/file. Gone for real (it was never committed) - the one genuinely destructive everyday command.
Mid-merge or mid-rebase and regretting it
git merge --abort / git rebase --abort returns you to the pre-operation state.
Deleted a branch / lost commits after a bad reset
git reflog, find the hash where life was good, then git branch rescue <hash> or git reset --hard <hash>. See the reflog section.

Integrating changes

Rebase vs merge

Merge

Join histories with a merge commit. Preserves what actually happened, never rewrites commits, safe on shared branches. Cost: a history graph full of merge bubbles that makes git log --graph noisy.

Rebase

Replay your commits onto the new base, producing a straight line. Clean linear history, easy bisecting. Cost: rewrites commit hashes - anyone who pulled your old commits now has divergent history.

Squash merge

Collapse the whole branch into one commit on main. Tidy main, easy reverts of whole features; loses the individual-commit narrative.

When to choose each

The golden rule decides most of it: never rebase commits that others may have pulled. Standard workflow: rebase your private feature branch onto main to stay current (git pull --rebase), then merge or squash-merge into main. Pick squash when the team treats PRs as the atomic unit; pick true merge when individual commits in a feature matter (e.g. separated refactor + behavior change). In the interview, naming the golden rule is the pass/fail line.

Interactive rebase (git rebase -i)

Edit the last N commits before sharing them: git rebase -i HEAD~5 opens a script of your commits, oldest first. Change the verb per line.

pick
Keep the commit as-is. The default.
reword
Keep the change, stop to edit the message.
edit
Stop at the commit to amend its contents (split it, fix a file). Continue with git rebase --continue.
squash
Meld into the previous commit; combine both messages in the editor.
fixup
Meld into the previous commit, discard this message. With git commit --fixup <hash> + git rebase -i --autosquash, git arranges these lines for you.
drop
Delete the commit (or just remove the line).
Reordering
Move lines to reorder commits. Conflicts can appear if commits touch the same lines - resolve, then --continue.
When to bother
Before opening a PR: squash the "fix typo" and "oops" commits into their parents so reviewers see a coherent story. Never on already-pushed shared branches.

Bisect - binary search your history

Something broke between v1.0 and now, across 400 commits. Bisect finds the culprit in log2(400) = ~9 checkouts.

git bisect start
Begin a bisect session.
git bisect bad
Mark the current (broken) commit bad.
git bisect good v1.0
Mark a known-good commit. Git checks out the midpoint; test it, then mark good/bad. Repeat until git names the first bad commit.
git bisect run ./test.sh
Full automation: the script's exit code (0 = good, non-zero = bad) drives the whole search hands-free. The flex answer in an interview.
git bisect reset
End the session, return to where you started.

Reflog - the safety net

git reflog records every position HEAD has had - commits, resets, rebases, checkouts - for roughly 90 days, even for commits no branch points to anymore. This is why "I lost my work" is almost never true once something was committed: find the entry before the disaster (each shows as HEAD@{n} with the action that caused it), then git reset --hard HEAD@{n} or git branch rescue HEAD@{n}. A botched rebase, an over-eager reset --hard, a deleted branch - all recoverable. The only things reflog cannot save are changes that were never committed (a discarded working tree) and repos where the reflog was expired or never local (a fresh clone has no reflog history). Interview line that lands: "reset --hard isn't scary; uncommitted changes are."

Stash - shelve work in progress

git stash push -m 'wip: auth refactor'
Shelve tracked changes and clean the working tree. Always use -m - 'WIP on main: 4f2a...' tells you nothing a week later.
git stash -u
Include untracked files (new files are skipped by default - the classic surprise).
git stash list
Show the stack: stash@{0} is the newest.
git stash pop vs apply
pop applies + drops the entry; apply keeps it (safer when conflicts are possible - a conflicted pop does not drop, but apply is easier to reason about). Target old entries: git stash apply stash@{2}.
git stash show -p
Diff a stash before applying it.
git stash branch <name>
Create a branch from the commit the stash was made on and apply it there - the escape hatch when the stash no longer applies cleanly to a moved branch.
When NOT to stash
Long-term storage. A stash is invisible to git log and easy to forget; if the work matters, commit it to a WIP branch instead.

Flags and aliases worth keeping

  • ·git config --global alias.lg "log --oneline --graph --all --decorate" - the history view you actually want.
  • ·git push --force-with-lease, never --force. It refuses to clobber commits someone else pushed since your last fetch.
  • ·git pull --rebase as default: git config --global pull.rebase true. No more accidental merge commits from pulling.
  • ·git add -p - stage hunk by hunk. The single best habit for clean, reviewable commits.
  • ·git commit -v - shows the diff inside the commit-message editor, so you describe what you actually changed.
  • ·git diff main...HEAD (three dots) - exactly what your branch adds since it diverged, ignoring what main did meanwhile.
  • ·git blame -w -C - ignore whitespace and follow code moved between files, so blame points at the real author, not the reformatter.
  • ·git config --global rerere.enabled true - git remembers conflict resolutions and replays them; a lifesaver on long rebases.
  • ·git log -S 'functionName' - find the commits that added or removed a string (the pickaxe). Faster than any archaeology by hand.
  • ·git switch - / git checkout - - bounce to the previous branch, like cd -.
  • ·git config --global fetch.prune true - deleted remote branches disappear locally on fetch instead of accumulating forever.

Other cheat sheets

Big-O Reference

Algorithms

Time and space complexity for the data structures, sorting algorithms, and search routines that show up in coding interviews. Skim the row, remember the row, defend the row in an interview.

Interview Patterns

Patterns

The recurring shapes - sliding window, two pointers, fast/slow, BFS/DFS, backtracking, DP, divide & conquer, binary search variants, union-find, topological sort. Each entry: when to reach for it, the template, complexity, and which classic problems use it.

Design Tradeoffs

Systems

The recurring forks in system design interviews. CAP, PACELC, sync vs async, push vs pull, SQL vs NoSQL, sharding shapes, consistency models, cache strategies, idempotency, and rate limiting. For each, the options and when to choose each.

Unix Essentials

Tools

Filesystem layout, the commands you actually use (find / grep / awk / sed / xargs), processes and signals, networking, permissions, basic shell scripting, and a vi survival kit.

SQL Essentials

Tools

Query clause order, every JOIN type and when to use it, aggregates vs window functions, what indexes actually buy you, transaction isolation levels, and the NULL / WHERE-vs-HAVING / EXISTS-vs-IN gotchas interviewers fish for.

Docker & K8s

Tools

The docker and kubectl commands you reach for daily, Dockerfile best practices, how layer caching actually works, the core k8s objects in one screen, requests vs limits, liveness vs readiness, and a step-by-step CrashLoopBackOff debug flow.

REST API Design

Systems

Method semantics and idempotency, the ~15 status codes that matter, resource naming rules, offset vs cursor pagination, versioning and auth tradeoffs, error body conventions, rate-limit headers, and the smells reviewers flag.

STAR Method

Patterns

The STAR structure with timing, what interviewers actually grade, eight question archetypes and how to frame each, the anti-patterns that sink answers (rambling, "we" instead of "I", no metrics), and a 30-second answer skeleton.

Practice the patterns

Reading is the floor. The signal in interviews comes from working problems out loud and defending your tradeoffs. Spin up an AI mock interview or run a coding challenge to put these to work.