Skip to content
Search lessons, topics, tests…
Esc

    ↑ ↓ moveEnter openEsc close
    Cheat sheets: all cheat sheets

    Git for Interviews Cheat Sheet: Merge, Rebase, Reset, Revert and Reflog

    Git's data model, merge vs rebase, reset soft/mixed/hard vs revert, reflog recovery, force-with-lease and team workflows, with a runnable script that proves each undo command.

    Learning outcome

    By the end of this cheat sheet you should be able to explain Git's data model in one minute, choose between merge and rebase, undo mistakes safely (reset, revert, restore, reflog), and describe a team branching workflow. These questions show up in .NET interviews because they reveal whether you can work on a shared codebase without losing anyone's work.

    Intuition

    Git is a content-addressed graph of snapshots:

    • A commit is a snapshot (a tree of blobs) plus metadata plus parent pointer(s), named by its hash.
    • A branch is just a movable pointer to a commit. HEAD points to the branch you are on (or directly to a commit: detached HEAD).
    • There are three places your changes live: the working tree, the index (staging area), and the repository (commits).

    Most commands either move a pointer (reset, switch, merge --ff) or create new commits (commit, merge, revert, rebase, cherry-pick). "Rewriting history" means creating new commits and moving a branch pointer to them. The old commits still exist until garbage-collected, which is why reflog can save you.

    Quick reference: everyday commands

    TaskCommand
    Start a branch from the current commitgit switch -c feature/x
    See what changed (unstaged / staged)git diff / git diff --staged
    Stage part of a filegit add -p
    Amend the last (unpushed) commitgit commit --amend
    Update from remote without touching your branchgit fetch
    Fetch + integrategit pull --no-rebase (merge) or git pull --rebase; plain git pull follows configuration and version defaults
    Shelve work in progressgit stash push -m "wip" → git stash pop
    Show history as a graphgit log --oneline --graph --decorate --all
    Who changed this linegit blame -L 10,20 path
    Find the commit that introduced a buggit bisect start, git bisect bad, git bisect good <sha>
    Copy one commit onto the current branchgit cherry-pick <sha>
    Tag a releasegit tag -a v1.2.0 -m "v1.2.0" + git push origin v1.2.0

    Merge vs rebase

    git merge featuregit rebase main (on the feature branch)
    HistoryKeeps the true history; adds a merge commit (unless fast-forward)Linear; replays your commits as new commits on top of main
    Commit hashesUnchangedChanged for every replayed commit
    ConflictsResolved once, in the merge commitPossibly once per replayed commit
    Safe on shared branches?YesNo: never rebase commits others have based work on
    Typical useIntegrating into main (often via PR)Tidying a private branch before review; git rebase -i to squash or reword
    • Fast-forward: if main hasn't moved, merge just moves the pointer. --no-ff forces a merge commit.
    • Squash merge (common PR option): one new commit on main. The branch's individual commits are not part of main's history.

    Undoing things

    SituationCommandRewrites history?
    Discard unstaged edits to a filegit restore pathNo
    Unstage a file (keep the edits)git restore --staged pathNo
    Undo the last commit, keep the changes stagedgit reset --soft HEAD~1Yes (local)
    Undo the last commit, keep the changes unstaged (default)git reset HEAD~1 (--mixed)Yes (local)
    Undo the last commit and discard the changesgit reset --hard HEAD~1Yes, destructive
    Undo a commit that is already pushed or sharedgit revert <sha> (a merge needs -m <parent-number>; use 1 only when parent 1 is the intended mainline)No: adds an inverse commit
    Recover a "lost" commit or branchgit reflog → git switch -c rescue <sha> or git reset --hard HEAD@{1}n/a
    Abort a merge or rebase in progressgit merge --abort / git rebase --abortn/a
    Push after rewriting your own branchgit push --force-with-leaseYes, on the remote

    --force-with-lease refuses to overwrite the remote branch if it moved since your last fetch. Plain --force silently discards a teammate's pushed commits.

    Workflows interviewers ask about

    WorkflowShapeFits
    Trunk-based developmentShort-lived branches (hours to a day or two) merged to main often; feature flags for unfinished workCI/CD, frequent deploys
    GitHub flowBranch → PR → review + CI → merge to main → deployMost SaaS teams
    Git flowdevelop, release/*, hotfix/*, mainVersioned products with scheduled releases; heavier

    Good PR hygiene: small focused changes, a meaningful commit message (imperative subject line, explanation of why), CI green, protected main with required reviews and checks.

    .NET-specific notes

    • Start every repo with dotnet new gitignore (excludes bin/, obj/, .vs/, user files).
    • Never commit secrets (appsettings.*.json with keys). Use dotnet user-secrets locally and a vault in production. If a secret was pushed, rotate it. Rewriting history does not un-leak it.
    • Line endings: add a .gitattributes (for example * text=auto) so Windows and Linux contributors don't produce whole-file diffs.

    Failure modes

    • git reset --hard with uncommitted work: that work is gone. Only committed (or stashed) work is in the reflog.
    • Rebasing or force-pushing a shared branch: teammates' history diverges, and their commits can be lost.
    • git pull creating noisy merge commits on a feature branch. Use git pull --rebase (or git config pull.rebase true) for your private branches.
    • Long-lived feature branches: large, risky merges. Integrate small and often.
    • Committing generated files (bin/, obj/) or secrets.

    Interview drill

    1. What is a branch, physically?
    2. Merge vs rebase: when would you refuse to rebase?
    3. You pushed a bad commit to main. What do you do, and why not reset?
    4. Explain reset --soft, --mixed and --hard in one line each.
    5. You ran reset --hard by mistake on a committed branch. How do you get the work back?
    6. fetch vs pull?
    7. How would you find which commit introduced a regression among 200 commits? (git bisect: about log₂ 200 ≈ 8 steps.)

    Revision checklist

    • Can I explain working tree, index and repository?
    • Can I draw merge vs rebase on a whiteboard?
    • Do I know which undo commands rewrite history and which don't?
    • Do I default to --force-with-lease and revert on shared branches?
    • Can I describe trunk-based development vs Git flow?

    Worked executable example

    This Bash script builds a throwaway repository and proves the undo semantics: reset --soft keeps changes staged, --mixed unstages them, --hard drops the commit, reflog recovers it, revert adds an inverse commit, and rebase replays a feature commit on top of main.

    Run this example

    Requires Git 2.28+ (for git init -b, as well as git switch) and Bash. Save the script as git-demo.sh and run bash git-demo.sh. It works in a new temporary directory and touches nothing else.

    Shell
    #!/usr/bin/env bash
    set -euo pipefail
    cd "$(mktemp -d)"
    git init -q -b main
    git config user.email demo@example.com
    git config user.name demo
    log() { git log --format=%s | tr '\n' ' '; }
    
    for n in 1 2 3; do echo "$n" >> f.txt; git add f.txt; git commit -qm "c$n"; done
    
    git reset -q --soft HEAD~1
    echo "soft:   staged=[$(git diff --cached --name-only)] log=$(log)"
    git commit -qm c3
    
    git reset -q --mixed HEAD~1
    echo "mixed:  staged=[$(git diff --cached --name-only)] unstaged=[$(git diff --name-only)] log=$(log)"
    git commit -qam c3
    
    git reset -q --hard HEAD~1
    echo "hard:   file=$(tr '\n' ' ' < f.txt)log=$(log)"
    
    git reset -q --hard 'HEAD@{1}'
    echo "reflog: log=$(log)"
    
    git revert --no-edit HEAD > /dev/null
    echo "revert: log=$(log)"
    
    git switch -q -c feature HEAD~2
    echo x > g.txt; git add g.txt; git commit -qm feat
    git rebase -q main
    echo "rebase: log=$(log)"

    Expected output

    Text
    soft:   staged=[f.txt] log=c2 c1 
    mixed:  staged=[] unstaged=[f.txt] log=c2 c1 
    hard:   file=1 2 log=c2 c1 
    reflog: log=c3 c2 c1 
    revert: log=Revert "c3" c3 c2 c1 
    rebase: log=feat Revert "c3" c3 c2 c1 

    The feature branch started from c2. After the rebase, its commit feat sits on top of main's latest commit as a new commit with a new hash.