Git · Developer Interview Q&A

Git Interview Questions & Commands Every Developer Should Know

How Git actually stores your work, merge vs rebase with commit graphs, reset vs revert, cherry-pick and stash, branching strategies, and a recovery playbook for every mistake interviewers ask about.

✍️ Pranjal Jain, Ex-Microsoft · IIT Kanpur 📅 10 October 2026 ⏱ 18 min read
Illustration of a commit graph as a glowing tree with branches merging and being replayed
TL;DR
  • Git stores snapshots as content-addressed objects (blob, tree, commit, tag). Branches are just movable pointers to commits, and HEAD points at your current branch. Most "scary" commands only move pointers.
  • Merge preserves history with a merge commit; rebase rewrites your commits onto a new base for a linear history. Never rebase commits others already have.
  • reset moves a branch pointer (soft keeps staged, mixed keeps working changes, hard discards); revert adds an undo commit and is the safe option on shared branches.
  • reflog is your safety net: almost anything committed can be recovered for weeks.
  • Know one branching strategy deeply (trunk-based or GitHub Flow) and why teams moved away from heavyweight Git Flow.

Git questions appear in more interviews than people expect: as a warm-up in campus and fresher rounds, as practical "what would you do" questions in SDE-1 loops, and as part of DevOps and CI/CD discussions for experienced roles. They are also the easiest questions to fail with confidence, because many developers use Git daily through a handful of memorised commands. This guide explains the model underneath, then walks through the commands and scenarios interviewers actually ask, with commit-graph diagrams showing what each command does.

How Git Works: The Mental Model Behind Every Answer

Q1. What is Git, and how is it different from SVN?

Git is a distributed version control system: every clone has the full history, so commits, branching, log and diff work offline and fast. SVN is centralised: history lives on a server and many operations need it. Git also stores snapshots of the whole project per commit (deduplicated), not a chain of per-file diffs, which is why branching and switching are cheap.

Q2. What are Git's object types?

ObjectStoresPoints to
blobFile contents (no name)Nothing
treeA directory listing: names, modes, hashesBlobs and subtrees
commitAuthor, committer, message, timestampOne root tree and zero or more parent commits
tag (annotated)Tagger, message, optional signatureUsually a commit

Each object is identified by the hash of its content (SHA-1 by default; SHA-256 repositories are supported but less common). Identical files share one blob. Changing one byte of history changes every descendant commit hash, which is what makes history tamper-evident and why rebasing creates "new" commits.

Q3. What are the three areas (working tree, index, repository)?

Working tree ──git add──► Index (staging) ──git commit──► Repository (your files) ◄─git restore─ (next commit) ◄─git restore --staged─ (.git)

The index is the proposed next commit. Staging lets you commit part of your changes: git add -p stages individual hunks, which is how you split a messy afternoon of work into clean, reviewable commits.

Q4. What are branches and HEAD, really?

A branch is a file containing a commit hash (.git/refs/heads/main). Committing on a branch creates a new commit whose parent is the current tip and moves the pointer forward. HEAD normally points to a branch name (ref: refs/heads/main), which is how Git knows which branch to advance. Creating a branch costs a few bytes, which is why Git encourages branching freely.

Q5. What is a detached HEAD?

HEAD points straight at a commit, not a branch: after git checkout a1b2c3d, checking out a tag, or during a rebase. Commits made here belong to no branch; switch away and they are only reachable through the reflog. To keep them: git switch -c fix-from-tag.

Everyday Git Commands Interviewers Expect You to Know

Q6. Walk through a typical feature workflow.

Shell
git switch main
git pull --rebase                  # update main
git switch -c feat/upi-autopay     # new branch
# ... edit files ...
git status                         # what changed?
git diff                           # unstaged changes
git add -p                         # stage selected hunks
git diff --staged                  # review what will be committed
git commit -m "Add UPI autopay mandate creation"
git push -u origin feat/upi-autopay   # -u sets upstream tracking
# open a pull request, address review, merge

Q7. git fetch vs git pull?

fetch downloads new objects and updates remote-tracking refs (origin/main) without touching your branch. pull = fetch + merge (or + rebase with --rebase or pull.rebase=true). Many teams set git config --global pull.rebase true to avoid noisy "Merge branch 'main' of origin" commits on feature branches.

Q8. checkout vs switch vs restore?

git checkout historically did two unrelated things: switch branches and restore files. Since Git 2.23, git switch changes branches and git restore restores files. Using them in an interview shows current knowledge; checkout still works.

Q9. How do you see history usefully?

git log --oneline --graph --decorate --all   # visual branch graph
git log -p -- src/payments/Refund.java        # patches touching a file
git log -S "retryCount" --oneline             # commits that added/removed a string
git log --author="Asha" --since="2 weeks ago"
git blame -L 40,60 src/payments/Refund.java   # who last changed lines 40-60
git show a1b2c3d                              # one commit's details and diff

Q10. What is .gitignore, and why is my ignored file still tracked?

.gitignore only affects untracked files. If a file was committed before being ignored, Git keeps tracking it. Fix: git rm --cached config/local.env, commit, and keep the ignore rule. If that file contained secrets, removing it does not remove it from history; see Q31.

Q11. What does git commit --amend do?

Replaces the last commit with a new one that includes currently staged changes and/or a new message. It is a history rewrite (new hash), so amend only commits you have not pushed, or be prepared to force-push your own feature branch.

Git Merge vs Rebase: The Most Asked Git Interview Question

Start with this situation: you branched feature from main at commit B. Since then you made D and E, and teammates merged C into main.

Before: D---E feature / A---B---C main

Q12. What does merge do here?

git switch main && git merge feature creates a merge commit M with two parents (C and E):

After merge: D---E / \ A---B---C---M main

History is preserved exactly as it happened. Nothing is rewritten, so it is always safe on shared branches. The cost: on busy repositories, the graph becomes a tangle of merge commits.

Q13. What does rebase do here?

git switch feature && git rebase main takes the changes of D and E and replays them on top of C as new commits D' and E':

After rebase: D'--E' feature / A---B---C main Then a fast-forward merge: A---B---C---D'--E' main, feature

The history is linear and easy to read and bisect. But D' and E' have new hashes. Anyone who based work on the old D and E now has diverged history.

Q14. When should you use each?

SituationUseWhy
Updating your private feature branch with latest mainrebaseClean history, conflicts resolved commit by commit
Integrating a finished feature into mainmerge (or squash merge via PR)Never rewrites shared history
A branch others have pulled or built onmergeRebasing would force everyone to recover
Cleaning up messy WIP commits before reviewinteractive rebaseSquash, reorder, reword

The rule to state, verbatim if you like: do not rebase commits that exist outside your repository and that people may have based work on. This is the "golden rule" from the official Pro Git book.

Q15. What is a fast-forward merge?

If the target branch has no new commits since you branched, merging simply moves its pointer forward to your tip: no merge commit. git merge --no-ff forces a merge commit anyway (to record that a feature existed); git merge --ff-only refuses unless a fast-forward is possible.

Q16. Merge commit vs squash merge vs rebase merge in pull requests?

GitHub and GitLab offer three buttons. Merge commit keeps every commit plus a merge commit. Squash and merge collapses the PR into one commit on main: clean history, one revertable unit per feature, but the individual commits are gone from main. Rebase and merge replays each commit linearly. Many product teams default to squash merges for small PRs.

Q17. How do you resolve a merge conflict?

  1. See what conflicts. git status lists "both modified" files.
  2. Edit the markers. Between <<<<<<<, ======= and >>>>>>> are both versions. Produce the correct combined code, which is often neither side verbatim. git config merge.conflictstyle diff3 (or zdiff3) also shows the common ancestor, which makes intent much clearer.
  3. Mark resolved. git add file.
  4. Continue. git commit for a merge, git rebase --continue during a rebase. Bail out with git merge --abort or git rebase --abort.
  5. Run the tests. A textually clean merge can still be semantically broken (one side renamed a function the other side started calling).

Q18. What is interactive rebase?

git rebase -i HEAD~4

Opens a todo list of the last four commits where you can pick, reword, edit, squash (combine, keep messages), fixup (combine, discard message), drop or reorder. A neat workflow: commit small fixes with git commit --fixup=<hash>, then git rebase -i --autosquash main folds them into the right commits automatically.

Git Reset vs Revert vs Restore

Q19. Explain git reset --soft, --mixed and --hard.

All three move the current branch pointer to the target commit. They differ in what happens to the index and working tree:

ModeBranch pointerIndex (staged)Working treeTypical use
--softMovesKept (changes from undone commits appear staged)KeptSquash last 3 commits into one: reset --soft HEAD~3 then commit
--mixed (default)MovesReset to targetKept (changes appear unstaged)Undo a commit but keep the edits to re-split them
--hardMovesResetReset: uncommitted changes are destroyedThrow away local work entirely

--hard is the only one that can lose data you never committed; Git cannot recover uncommitted working-tree changes, though commits stay recoverable via the reflog.

Q20. git reset vs git revert?

reset --hard B (rewrites): revert C (adds): A---B---C main A---B---C---C' main becomes C' = inverse of C A---B main (C orphaned)

reset rewrites the branch, so it is only safe for commits that have not been pushed or shared. revert adds a new commit that undoes a previous one; history stays intact, teammates pull it normally, and there is a record of the rollback. On main, always revert.

Q21. How do you revert a merge commit?

A merge commit has two parents, so you must say which side is the mainline: git revert -m 1 <merge-hash> keeps parent 1 (usually main) and undoes what the merged branch introduced. Follow-up worth knowing: if you later want to re-merge that branch, Git considers its commits already merged, so you must first revert the revert.

Q22. How do you discard changes to a file?

git restore src/app.js              # discard unstaged changes in working tree
git restore --staged src/app.js     # unstage, keep the edits
git restore --source=HEAD~2 src/app.js   # get the file as it was two commits ago
git clean -fd                       # delete untracked files and dirs (preview with -n!)

Git Cherry-Pick and Stash Interview Questions

Q23. What is cherry-pick and when do you use it?

git cherry-pick <hash> applies the change introduced by an existing commit onto your current branch as a new commit. The classic case: a payment bug fix merged to main must also go to release/2026.10, which is in production.

git switch release/2026.10
git cherry-pick -x 7f3e9a1        # -x appends "(cherry picked from commit 7f3e9a1)"
git cherry-pick a1b2c3d..f4e5d6c  # a range (excludes a1b2c3d itself)

Downsides to mention: duplicate commits with different hashes can confuse later merges, and if the fix depends on earlier commits not on the release branch, you get conflicts or broken builds. Heavy cherry-picking is a sign the branching model needs work.

Q24. What is git stash?

Stash saves your uncommitted changes onto a stack and cleans the working tree, so you can switch context (an urgent production fix) and come back later.

git stash push -m "wip: refund retries"   # save tracked changes
git stash push -u -m "wip incl. new files" # -u also stashes untracked files
git stash list                             # stash@{0}, stash@{1}, ...
git stash show -p stash@{0}                # inspect
git stash pop                              # apply most recent and drop it
git stash apply stash@{1}                  # apply, keep it in the stack
git stash branch wip-refunds stash@{0}     # new branch from the stash's base, apply it

By default stash does not include untracked or ignored files, a frequent surprise. And pop that hits a conflict does not drop the stash, so nothing is lost.

Q25. Stash vs a WIP commit?

Stashes are local, unnamed by default and easy to forget. For anything longer than a quick context switch, a WIP commit on a branch (later amended or squashed) is more robust and can be pushed as backup. git worktree add ../hotfix main is a third option: a second working directory on another branch, so you never have to stash at all.

Recovering From Git Mistakes: The Scenario Questions

This is where interviews for experienced developers focus. Each scenario has a precise, low-risk fix.

Q26. I ran git reset --hard and lost my commits. Can I recover?

Yes, if they were committed. The reflog records every position HEAD and branches have had.

git reflog
# 4c1d2e3 HEAD@{0}: reset: moving to HEAD~3
# 9a8b7c6 HEAD@{1}: commit: Add settlement report export
# ...
git reset --hard 9a8b7c6        # or: git branch rescue 9a8b7c6

Reflog entries expire after 90 days by default (30 for unreachable commits), and only then can garbage collection remove the objects. The reflog is local: it does not exist on the remote or in a fresh clone.

Q27. I deleted a branch with unmerged work.

git branch -D prints the tip hash ("Deleted branch x (was 9a8b7c6)"). Recreate it with git branch x 9a8b7c6. If you no longer have that output, search git reflog for the last commit on the branch.

Q28. I committed to main instead of a feature branch (not pushed).

git branch feat/coupon-cap        # new branch pointing at your commits
git reset --hard origin/main      # move main back to the remote state
git switch feat/coupon-cap

Q29. I pushed a bad commit to main and others have pulled it.

Do not reset and force-push a shared branch. git revert <hash>, push, and let the normal flow carry the fix. If production is broken, revert first and investigate after.

Q30. A rebase went wrong halfway through.

git rebase --abort returns to the pre-rebase state. If you already finished it and the result is bad, git reset --hard ORIG_HEAD (Git sets ORIG_HEAD before rebases, merges and resets) or find the pre-rebase tip in the reflog.

Q31. I committed an API key and pushed it.

  1. Rotate the secret immediately. Assume it is compromised the moment it reached a remote; bots scan public repositories continuously. Rewriting history does not un-leak it.
  2. Remove it from the current code and load it from a secret manager or environment.
  3. Purge history if required with git filter-repo (recommended by the Git project over the older filter-branch) or BFG, then force-push and have collaborators re-clone. Cached forks and PR refs on the hosting platform may still hold it.
  4. Prevent recurrence with pre-commit secret scanning (gitleaks, GitHub push protection).

Q32. I need to undo a pushed commit on my own feature branch.

On a branch only you use, rewriting is fine: reset or interactive rebase, then git push --force-with-lease. Unlike --force, the lease refuses to overwrite if the remote moved since your last fetch, protecting a teammate's push you have not seen.

Git Branching Strategies Asked in Interviews

Q33. Compare Git Flow, GitHub Flow and trunk-based development.

Git FlowGitHub FlowTrunk-based
Long-lived branchesmain, develop, plus release and hotfix branchesmain onlymain (trunk) only
Feature branchesLong-ish, off developShort, off main, merged via PRVery short (hours to a day or two), or direct commits
Release modelScheduled versionsDeploy main continuouslyContinuous; unfinished work hidden behind feature flags
FitsVersioned products: mobile apps, on-prem software, SDKsWeb services with CI/CDHigh-velocity teams with strong test automation
Main costMerge overhead, slow integrationNeeds good CINeeds feature flags and discipline

A mature answer: most product companies deploying web services several times a day use GitHub Flow or trunk-based development, because long-lived branches delay integration and create painful merges. Git Flow still makes sense when you must maintain multiple released versions at once. Release branches cut from trunk plus cherry-picked fixes are common for mobile apps with app store review cycles. How this ties into pipelines is covered in CI/CD interview questions.

Q34. How do you hotfix production under each strategy?

Git Flow: branch hotfix/x from main, fix, merge into both main and develop, tag. Trunk-based: fix on trunk via a fast PR and deploy; if a release branch is in production, cherry-pick the fix onto it. Either way: tests, review (even an expedited one), and a revert plan.

Q35. What makes a good commit and a good commit message?

One logical change per commit, passing tests, so each is revertable and bisectable. Messages: a short imperative subject ("Fix double refund on retry"), a blank line, then the why. Many teams use Conventional Commits (fix:, feat:) to automate changelogs and semantic versioning.

Advanced Git Interview Questions for Experienced Developers

Q36. How does git bisect find a bug?

Binary search over history. Mark a known bad and a known good commit; Git checks out the midpoint, you test and mark it, and it halves the range each time. 1,000 commits take about 10 steps (log2 1000 ≈ 10). Automate it with a script that exits 0 for good and non-zero for bad:

git bisect start
git bisect bad HEAD
git bisect good v2.14.0
git bisect run ./scripts/check_refund_total.sh
git bisect reset

Q37. Lightweight vs annotated tags?

A lightweight tag is just a named pointer. An annotated tag (git tag -a v2.15.0 -m "...") is a full object with tagger, date and message, and can be signed. Use annotated tags for releases. Tags are not pushed by default: git push origin v2.15.0 or --follow-tags.

Q38. What are Git hooks?

Scripts in .git/hooks run at events: pre-commit (lint, format, secret scan), commit-msg (enforce message format), pre-push (run tests), and server-side hooks like pre-receive. Client-side hooks are not shared through the repository by default, so teams use tools such as Husky or the pre-commit framework, and enforce the important checks in CI anyway, since hooks can be bypassed with --no-verify.

Q39. Submodules vs subtrees vs a monorepo?

A submodule pins another repository at a specific commit inside yours; precise but notoriously easy to get wrong (forgetting --recurse-submodules, detached HEADs inside). A subtree copies another repo's content into a subdirectory with history; simpler for consumers. Many companies avoid both with a monorepo or published package versions.

Q40. How do you handle large binary files?

Git stores every version of every file forever, so committing a 500 MB dataset bloats every clone permanently. Use Git LFS, which stores pointers in the repository and the content on a separate server, or keep artefacts in object storage and reference them by version.

Q41. What does git gc do, and what is a packfile?

Loose objects are individually compressed files. git gc packs them into packfiles using delta compression against similar objects, and prunes unreachable objects older than the expiry windows. It runs automatically from time to time; you rarely call it manually.

Q42. How would you find which commit deleted a function?

git log -S "calculateGst(" --oneline (the "pickaxe") lists commits where the number of occurrences of that string changed; the latest one is usually the deletion. -G takes a regex instead. Combined with git show, this answers most "who changed this and why" questions faster than blame.

Q43. Origin vs upstream in an open-source fork workflow?

By convention, origin is your fork and upstream is the original project. Sync with git fetch upstream && git rebase upstream/main, push to origin, and open a PR to upstream. If you are preparing for GSoC or open-source contributions, practise exactly this loop; see open-source contributions for Indian engineers.

Git Commands Cheat Sheet for Interviews

GoalCommandSafe on shared branches?
Undo last commit, keep changes stagedgit reset --soft HEAD~1No (rewrite)
Undo last commit, keep changes unstagedgit reset HEAD~1No
Throw away last commit and its changesgit reset --hard HEAD~1No
Undo a pushed commitgit revert <hash>Yes
Fix last commit message (unpushed)git commit --amendNo
Update branch with maingit rebase main or git merge mainMerge yes; rebase only for private branches
Bring one commit to another branchgit cherry-pick -x <hash>Yes
Park work temporarilygit stash push -u -m "msg"Local only
Find lost commitsgit reflogLocal only
Find the commit that broke somethinggit bisect run ./test.shRead-only
Force-push your own branch safelygit push --force-with-leaseOnly your own branch
Stop tracking a committed filegit rm --cached pathYes
💡
How to answer any Git scenario questionAsk two things first: "Has this been pushed?" and "Has anyone else pulled it?" If no, rewriting history (reset, amend, rebase) is fine. If yes, use additive fixes (revert, new commits). Interviewers are mostly testing whether you protect your teammates' history. Then name the exact command and mention reflog as the safety net.

Git fluency also shows in how you talk about your projects: clean commit history, small reviewable PRs and a sensible branching model are exactly what reviewers notice in your first weeks at a new job (see the first 90 days guide). Since most Git work happens in a terminal, the Linux and shell interview questions are a natural next read.

Frequently Asked Questions

What is the difference between git merge and git rebase?▾
git merge combines two branches by creating a merge commit with two parents, preserving the exact history of both. git rebase replays your commits on top of another branch, creating new commits with new hashes and a linear history. Merge is safe on shared branches; rebase rewrites history, so only rebase commits that nobody else has based work on.
What is the difference between git reset and git revert?▾
git reset moves the current branch pointer to an earlier commit, effectively removing later commits from the branch, and with --hard also discards working changes. git revert creates a new commit that undoes the changes of an earlier commit, leaving history intact. Use revert on shared branches such as main and reset only on local, unpushed work.
How do I recover a deleted branch or commits after git reset --hard?▾
Run git reflog to list where HEAD has pointed recently, find the hash of the commit you lost, and create a branch at it with git branch recovered <hash> or reset back to it. Reflog entries are kept for 90 days by default for reachable entries and 30 days for unreachable ones, so recovery is possible for weeks as long as garbage collection has not pruned them.
What is the difference between git fetch and git pull?▾
git fetch downloads new commits and updates remote-tracking branches such as origin/main without touching your working branch. git pull runs a fetch followed by a merge (or a rebase if configured with pull.rebase or --rebase) into your current branch. Fetching first lets you inspect incoming changes before integrating them.
What does git cherry-pick do?▾
git cherry-pick applies the changes introduced by one or more existing commits onto your current branch as new commits. It is commonly used to backport a bug fix from main to a release branch. The new commit has a different hash; adding -x records the original hash in the message for traceability.
What is a detached HEAD in Git?▾
Detached HEAD means HEAD points directly to a commit instead of to a branch, which happens when you check out a commit hash, a tag or a remote-tracking branch. You can look around and even commit, but new commits belong to no branch and can be lost when you switch away. Create a branch with git switch -c name to keep them.
Why use git push --force-with-lease instead of --force?▾
--force overwrites the remote branch unconditionally, which can silently destroy commits a teammate pushed. --force-with-lease only overwrites if the remote branch still points where your last fetch saw it, so it refuses when someone else has pushed in the meantime.

Prepare for Every Round, Not Just DSA

Prepflix's interview program covers the engineering fundamentals interviewers probe, from Git and CI/CD to system design, alongside structured DSA and mock interviews.

Explore the Prepflix Course →
Pranjal Jain
Pranjal Jain

Ex-Microsoft SDE · IIT Kanpur · Founder of Prepflix. Helps engineers crack startup and product company interviews across India.