Git, Linux & Tooling
Technical assessments and project vivas now assume Git and the shell: 25 Git workflows with mistake recovery, the Linux survival kit, a 25-question terminal quiz, and Docker/CI-CD that actually gets asked.
1Start a new repository
Turn a folder into a repo (creates .git), stage everything, snapshot it.
git init
git add .
git commit -m "initial commit"Edge case: `git init` inside an existing repo creates a nested repo — usually a mistake.
Recovery: Delete the accidental .git folder in the subfolder.
2Clone and pick a branch
Clone copies the repo + history; start your own branch from the latest main.
git clone <url>
git checkout -b feature/my-work origin/mainEdge case: Older git used `checkout`; newer syntax: `git switch -c feature/my-work`.
3See what changed before committing
status = which files changed; diff = unstaged changes; --staged = what a commit would include.
git status
git diff
git diff --stagedEdge case: diff shows nothing for NEW untracked files — status is the source of truth for those.
4Stage only part of a file
Interactive staging: confirm/split/skip each hunk — ideal for separating a fix from a refactor in one file.
git add -p <file>Edge case: Splittable only at changed-line boundaries; edit hunks with 'e' for finer control.
5Write commits that review well
Subject ≤ 50 chars, imperative mood, say WHY not just WHAT. Amend rewrites the last commit (message or contents).
git commit -m "fix: prevent duplicate charge on retry"
git commit --amend -m "better message"Edge case: Never amend a commit that's already pushed and shared — it diverges history for teammates.
Recovery: If you amended a pushed commit by accident: `git reset --soft HEAD@{1}` then re-commit, or force-push only your own branch.
6Undo the last commit (keep the work)
soft = keep changes staged; mixed (default) = keep changes unstaged; hard = DISCARD everything. Choose deliberately.
git reset --soft HEAD~1
git reset --mixed HEAD~1
git reset --hard HEAD~1Edge case: --hard deletes uncommitted work permanently — the classic 'I lost my code' accident.
Recovery: `git reflog` shows HEAD history; `git reset --hard <old-hash>` restores even after a hard reset (for ~90 days).
7Unstage a file but keep edits
restore --staged unstages; restore (no flag) discards working-tree edits (destructive).
git restore --staged <file>
git restore <file>Edge case: Plain `git restore <file>` deletes your uncommitted edits — there is no undo for untracked work.
8Create, switch and list branches
branch creates; switch moves HEAD; -a lists local + remote branches.
git branch feature/login
git switch feature/login
git branch -aEdge case: Creating a branch does NOT switch to it — a classic beginner assumption.
9Merge a feature branch
Fast-forward if main hasn't diverged; otherwise a merge commit joins both histories.
git switch main
git merge feature/loginEdge case: Merge only works from the branch you're ON — 'merge main INTO feature' ≠ 'merge feature INTO main'.
10Resolve a merge conflict
Git marks both versions inline; you edit to the intended result, stage, and the merge completes.
git merge feature/x
# edit files: keep correct code between <<<<<<< ======= >>>>>>>
git add <file>
git commitEdge case: <<<<<<< HEAD is YOUR side; the other label is the incoming branch.
Recovery: `git merge --abort` returns to the pre-merge state cleanly.
11Rebase for linear history
Replays your commits on top of main — clean, linear history without merge commits.
git switch feature/x
git rebase mainEdge case: Never rebase a shared/pushed branch: it rewrites commits others base work on.
Recovery: `git reflog` + `git reset --hard ORIG_HEAD` restores the pre-rebase state.
12Clean up commits before a PR
Interactive rebase: squash typos into features, reorder, reword — your PR reads like one coherent change.
git rebase -i HEAD~4Edge case: Only for unpushed or exclusively-your branches.
13Cherry-pick one commit to another branch
Copy a single commit (e.g. a bug fix) onto a different branch without merging everything.
git switch hotfix
git cherry-pick <commit-hash>Edge case: Cherry-picked commit gets a NEW hash — the same change exists twice in history; don't merge both copies later.
14Stash work-in-progress
Temporarily shelves uncommitted changes to switch context; pop restores the latest.
git stash
git stash list
git stash pop
git stash apply stash@{2}Edge case: Untracked files need `git stash -u`. Popped conflicts keep the stash (use drop manually after).
15Open a pull request (PR/MR)
-u sets upstream tracking so later pushes are plain `git push`. The PR is where review, CI and discussion happen.
git push -u origin feature/login
# open PR on GitHub/GitLab
git pushEdge case: Force-push only your own PR branch when asked: `git push --force-with-lease` (safer than --force).
16Apply review feedback
New commits on the PR branch update the same PR. Squash into the feature commit if the team prefers.
# edit files
git add .
git commit -m "address review: extract validation"
git pushEdge case: Re-request review explicitly after pushing; reviewers aren't auto-notified on every push.
17Add/inspect remotes
Remotes are named URLs; 'origin' is convention for your main remote (fork workflow uses 'upstream').
git remote add origin <url>
git remote -v
git remote set-url origin <new-url>Edge case: HTTPS remotes prompt for credentials; SSH needs keys configured once.
18Fetch vs pull
fetch downloads remote commits WITHOUT touching your work — inspect first. pull = fetch + merge.
git fetch origin
git log main..origin/main --oneline
git pullEdge case: `git pull` on a dirty tree can create surprise merge conflicts; fetch-then-merge is the calm path.
19Read history like a graph
ASCII commit graph: see branches, merges and where HEAD sits — invaluable before rebasing.
git log --oneline --graph --all --decorateEdge case: --all includes remote-tracking branches; add --first-parent for a simpler main-only view.
20Find who changed a line and why
blame = last change per line; log -p = full diffs; -S (pickaxe) = commits that added/removed a string.
git blame <file>
git log -p <file>
git log -S "suspectFunction"Edge case: blame after a big reformat blames the reformatter — use `git blame -w` to ignore whitespace.
21Find the commit that broke the build
Binary search over history: ~10 steps find the culprit in 1000 commits.
git bisect start
git bisect bad
git bisect good <hash>
# test each checkout
git bisect resetEdge case: Runs can be automated: `git bisect run ./test.sh`.
22Recover 'lost' commits (reflog)
reflog records every HEAD move for ~90 days — reset, rebase and amend accidents are all recoverable from here.
git reflog
git reset --hard HEAD@{2}Edge case: Untracked files that were never committed are NOT recoverable. Commit (or stash) early, commit often.
23Tag a release
Annotated tags carry message/author/date — the record of what shipped when.
git tag -a v1.2.0 -m "release 1.2.0"
git push origin v1.2.0
git tag -d v1.2.0Edge case: Tags don't push with `git push` alone; push tags explicitly (or --tags).
24Stop tracking files (gitignore)
gitignore prevents future tracking; rm --cached untracks an already-committed file without deleting it locally.
echo 'node_modules/' >> .gitignore
git rm --cached <file>
git commit -m "ignore build output"Edge case: gitignore does NOT retroactively untrack committed files — that's why rm --cached is needed.
25reset --soft vs --mixed vs --hard (the interview favourite)
All three move the branch pointer. soft keeps index+worktree, mixed keeps only worktree, hard keeps nothing. revert creates a NEW undo commit and is safe for shared history.
git reset --soft <commit>
git reset --mixed <commit>
git reset --hard <commit>Edge case: On shared branches, prefer `git revert <hash>` — rewriting shared history forces everyone to recover.
Recovery: reflog recovers any reset.