Most developers use about eight Git commands and reach for Stack Overflow for everything else. These are the ones that repay the ten minutes it takes to learn them, roughly in order of how often they save an afternoon.
git checkout does two unrelated jobs, which is why it is so easy to destroy work with it. Git split them years ago: git switch feature-x changes branch, git switch -c new-branch creates one, and git restore --staged file.txt unstages while git restore file.txt discards changes. Use these and the "I meant to change branch but deleted my edits" failure mode disappears.
git worktree add ../hotfix main checks out a second working directory from the same repository. No stashing, no rebuilding node_modules in place, no half-finished refactor sitting in your stash for a week. Remove it with git worktree remove ../hotfix when the hotfix ships.
Manual bisecting is tedious enough that people skip it. Automate it: git bisect start HEAD v1.4.0 then git bisect run ./scripts/check.sh, where the script exits 0 for good and non-zero for bad. Git walks the history for you and prints the first bad commit. On a 500-commit range that is nine test runs, unattended.
git log -S"getUserToken" — the pickaxe: shows commits where the number of occurrences of that string changed. The fastest way to find when a function was introduced or deleted.git log -L :parseConfig:src/config.js — the full history of one function, following it through moves.git log --oneline --graph --first-parent main — the merge-level history without the noise of every feature commit.git blame -w -C — ignores whitespace changes and follows code moved between files, so blame stops pointing at whoever ran the formatter.git commit --fixup <sha> marks a commit as a fix to an earlier one; then git rebase --autosquash main folds them in automatically without you editing a todo list. Add git config --global rerere.enabled true and Git remembers how you resolved a conflict, replaying that resolution the next time the same conflict appears — which on a long-lived branch is every rebase.
git reflog is the answer to almost every "I have destroyed my work" question: it lists every position HEAD has held, including commits orphaned by a bad reset, and git reset --hard HEAD@{3} puts you back. When pushing rewritten history, use git push --force-with-lease rather than --force — it refuses if someone else has pushed since you last fetched, which is the difference between rewriting your branch and deleting a colleague's work.
git clone --filter=blob:none fetches history without file contents until you need them, which turns a multi-gigabyte clone into a fast one. git sparse-checkout set apps/web limits your working directory to the part of the monorepo you touch. git maintenance start registers background housekeeping so you stop noticing the repo getting slower.
Create a .git-blame-ignore-revs file listing the SHAs of pure formatting commits, then git config blame.ignoreRevsFile .git-blame-ignore-revs. Blame skips them permanently, for everyone who sets it, and the mass-reformat you have been avoiding stops being a reason not to adopt a formatter.