Developer Tooling Lab

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.

bash
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.

bash
git clone <url>
git checkout -b feature/my-work origin/main

Edge 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.

bash
git status
git diff
git diff --staged

Edge 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.

bash
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).

bash
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.

bash
git reset --soft HEAD~1
git reset --mixed HEAD~1
git reset --hard HEAD~1

Edge 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).

bash
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.

bash
git branch feature/login
git switch feature/login
git branch -a

Edge 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.

bash
git switch main
git merge feature/login

Edge 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.

bash
git merge feature/x
# edit files: keep correct code between <<<<<<< ======= >>>>>>>
git add <file>
git commit

Edge 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.

bash
git switch feature/x
git rebase main

Edge 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.

bash
git rebase -i HEAD~4

Edge 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.

bash
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.

bash
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.

bash
git push -u origin feature/login
# open PR on GitHub/GitLab
git push

Edge 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.

bash
# edit files
git add .
git commit -m "address review: extract validation"
git push

Edge 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').

bash
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.

bash
git fetch origin
git log main..origin/main --oneline
git pull

Edge 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.

bash
git log --oneline --graph --all --decorate

Edge 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.

bash
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.

bash
git bisect start
git bisect bad
git bisect good <hash>
# test each checkout
git bisect reset

Edge 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.

bash
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.

bash
git tag -a v1.2.0 -m "release 1.2.0"
git push origin v1.2.0
git tag -d v1.2.0

Edge 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.

bash
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.

bash
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.