Remember first: almost everything is recoverable
Git commits rarely disappear: after a reset, a rebase or a deleted branch, the commit objects remain in the object database until garbage collection. reflog records every move HEAD made and is the first place to look — run git reflog, find the hash, then git checkout <hash> to inspect or git reset --hard <hash> to return.
Everyday commands
| Scenario | Command | Notes |
|---|---|---|
| Status | git status -sb | Compact branch and change view |
| Stage part of a change | git add -p | Hunk by hunk, avoids committing debug code |
| Park work temporarily | git stash push -m "msg" | Stash before switching; pop on return |
| Fix the last commit | git commit --amend | Only for commits not yet pushed |
| Find a line's origin | git blame -L 10,20 file | Locate where a problem entered |
| Bisect a bad commit | git bisect start | Automatic binary search between good and bad |
Four common accidents and their fixes
- Committed to the wrong branch: git reset --soft HEAD~1 keeps the changes, un-commits them, then switch and commit;
- A bad commit already pushed: never force push a shared branch — use git revert <commit> to add an inverse commit;
- Deleted a branch: find its last commit in git reflog and recreate it with git branch <name> <hash>;
- Work overwritten: git fsck --lost-found surfaces dangling objects; confirm with git show <hash> before restoring.
Three rules for teams
- No rebase or force push on shared branches: it rewrites history others already built on;
- Write the "why" in commit messages: the diff shows what, only the message explains why;
- Split large changes into small commits: easier rollback, review and bisecting.
A workable branching rhythm
- Branch off trunk with a short-lived branch, one branch per deliverable change;
- Tidy commits locally (squash / fixup) before pushing;
- Sync with trunk before merging and resolve conflicts locally, not in the web UI;
- Delete the branch after merging to keep the repository tidy.
Common questions
reset, revert or checkout? reset moves the branch pointer (rewrites history, for unpushed commits), revert adds an inverse commit (history preserved, for pushed commits), checkout merely moves you to look around. pull vs fetch? pull is fetch plus merge; when you want to inspect the difference first, fetch and merge manually. How do I unstage something? git restore --staged <file> keeps your working-tree changes.
Branching and collaboration conventions
What affects daily collaboration is not command fluency but clear conventions for branches and commits.
- One rollback unit per commit: each commit should complete one coherent change; mixing formatting with functional edits makes rollback a dilemma — take unrelated changes with you or lose what you want to keep.
- Explain the why: the subject says what changed, the body says why and what trade-offs were made. When you look back in six months, the reasoning matters more than the diff.
- Commit small, merge often: long-lived branches accumulate conflicts, and the further they diverge the riskier the merge. Merge daily, not weekly or monthly.
- Protect the trunk: no direct pushes, review and automated checks required. Force-pushing and rewriting shared history should be explicitly banned — it breaks everyone else's clone.
- Agree on synchronisation: pick rebase or merge for syncing with the trunk and stay consistent; mixing them produces unreadable history and duplicate commits.
Limits of history rewriting
Rewrite only unshared local commits. Never rewrite a branch that others have pulled — correct mistakes with a revert commit so everyone can still sync.
Repository size and history hygiene
Long-lived repositories need size monitoring, especially if large files or binaries were once committed. Review pack size and large objects periodically and slim history with dedicated tooling when needed. Keeping build output and dependencies out of version control day to day saves a lot of later cleanup.