cswork / libraryOpen practice workspace

Articles

Git Interview Questions for Software Engineers: Rebase, Merge, Recovery, and Collaboration

Practice Git interview questions on commit graphs, merge versus rebase, conflict resolution, reflog recovery, bisect, performance, and team workflows.

Git interview questions for software engineers test whether you can reason about a changing commit graph without losing work or surprising collaborators. Strong answers identify the current refs, index, worktree, and remote state before choosing a command.

Do not begin with “I always rebase” or a memorized command. Explain what history should look like, whether commits are already shared, how you will recover, and which team rule makes the operation safe.

The goal here is practical repository operations: merge, rebase, conflict resolution, bisect, reflog recovery, large histories, and collaborative branch policies.

Quick answer: use Graph, Intent, Blast Radius, Recovery, Team Contract

For any Git interview scenario, make five passes:

  1. Graph: Name the relevant commits, parents, branches, tags, remote-tracking refs, index, and worktree.
  2. Intent: Decide whether you need to integrate, replay, undo, diagnose, publish, or clean up.
  3. Blast radius: Separate local unpublished work from shared or protected history.
  4. Recovery: Create a checkpoint and name the abort, reflog, ORIG_HEAD, revert, or backup-ref path.
  5. Team contract: Respect review, CI, signing, force-push, and merge-strategy policy.

This structure turns command recall into an auditable engineering answer.

Git object model and commit graph questions

What is a commit, branch, and HEAD?

A commit records a project snapshot through a tree, plus parent commit references, author and committer data, and a message. Blobs hold file content; trees associate names and modes with blobs or subtrees. The official Git Objects chapter shows why history is a directed acyclic graph rather than a sequence of mutable folders.

A branch is a movable ref to a commit. HEAD normally points symbolically to the checked-out branch, while a detached HEAD points directly to a commit. The index is the proposed next snapshot; it is distinct from both HEAD and the worktree. Before changing history, inspect all three with git status, git diff, and git diff --cached.

How would you explain a fast-forward?

If the current branch tip is an ancestor of the other tip, Git can move the current ref forward without creating a merge commit. A true merge instead creates a commit with two parents. git log --graph --oneline --decorate --all makes that distinction visible.

The choice is not “clean versus messy.” Fast-forward keeps no explicit integration node; --no-ff preserves one. A team may require a linear history or an auditable merge boundary. State which property matters.

Merge versus rebase interview questions

When should you merge, rebase, or squash?

Use merge when preserving the actual branch topology and an explicit integration point is valuable. Rebase replays changes onto a new base, creating new commits with new identities; it is useful for updating an unpublished topic branch or preparing a coherent patch series. Squash condenses a branch into one integration commit when intermediate commits have little long-term value.

StrategyResulting historyGood fitMain risk
Merge commitPreserves both lines and adds a two-parent commitShared branches, audit trail, grouped featureNoisy graph if branches are long-lived and unmanaged
RebaseReplays commits onto a new basePrivate branch cleanup, patch-series reviewRewrites identities and disrupts collaborators
Squash mergeOne commit for the integrated changeSmall feature with disposable intermediate stepsLoses individual-commit boundaries

The git-merge documentation and git-rebase documentation describe mechanisms. The interview answer should add the collaboration boundary: do not rewrite commits others may have based work on without explicit coordination.

What actually happens during a rebase?

Git finds commits reachable from the current branch but not the chosen upstream, resets the branch to the new base, then reapplies the changes commit by commit. Because the parent, tree, author metadata, or committer timestamp may differ, the resulting commit IDs differ.

Interactive rebase can reorder, edit, squash, or drop commits. Before running it, fetch, inspect the range, ensure the worktree is clean, and create a temporary branch or tag if recovery cost matters. Afterward, review the series with tests and git range-diff old-base..old-tip new-base..new-tip rather than trusting a visually linear graph.

Conflict resolution interview questions

How do you resolve a merge or rebase conflict safely?

First inspect git status and the conflicting paths. Understand the base, ours, and theirs versions; the labels can be counterintuitive during rebase because commits are being replayed. Resolve the intended combined behavior, stage each resolution, then continue with git merge --continue or git rebase --continue.

Run focused tests before broader checks. If the premise is wrong, use git merge --abort or git rebase --abort while the operation state still exists. Avoid entering a complex integration with unrelated uncommitted changes because an abort may not reconstruct every worktree edit perfectly.

What is rerere, and when would you enable it?

rerere means reuse recorded resolution. Git records a conflicted shape and the human resolution, then can reuse it when the same conflict recurs during repeated rebases or test merges. It reduces mechanical work but does not prove semantic correctness. Review the applied resolution and rerun tests. It is most useful for long-running integrations or patch series that are repeatedly rebased.

Recovery questions: reset, revert, and reflog

Revert or reset after a bad commit?

Use git revert on shared history: it creates a new commit that applies the inverse change, preserving the existing graph and giving CI and reviewers a visible recovery event. Reverting a merge requires selecting the mainline parent and has consequences for later attempts to merge the same topic.

Use git reset mainly for local, unpublished correction. --soft moves the branch ref but keeps index and worktree changes; the default --mixed also resets the index; --hard makes index and worktree match the target and can discard tracked work. Never present reset --hard as a universal fix.

How do you recover a commit after an accidental reset or rebase?

Stop creating more state changes. Inspect git reflog --date=iso to find the previous tip, verify it with git show, then create a recovery branch such as git branch rescue <commit>. A reflog records local ref updates, so it can expose commits no longer reachable from a branch.

Recovery is not guaranteed forever: reflogs are local and entries can expire; unreachable objects can eventually be pruned. ORIG_HEAD may preserve the pre-operation tip for commands such as merge or reset, but reflog plus a named rescue ref is the more explainable workflow. If commits were never created, reflog cannot recover uncommitted work.

Debugging with bisect and history inspection

How would you find the commit that introduced a regression?

Use git bisect when you have a known good commit, a known bad commit, and a reliable pass/fail test. Git checks out a midpoint; each classification eliminates roughly half the remaining candidates. Automate with git bisect run only when the test exits consistently, and use skip for commits that cannot be evaluated.

The hard part is experimental design: define the symptom, control dependencies, select valid endpoints, and verify the identified commit. End with git bisect reset. For line history use git log -S, git log -G, or git blame as leads, not proof of causation.

How do you compare a rewritten patch series?

A normal range diff shows final snapshots, but a rebase review also needs to know how individual commits changed. git range-diff compares two commit ranges as patch series, helping reviewers see reordered, amended, added, or dropped patches. Pair it with the final tree diff and tests; equivalent patches can still behave differently when their base changes.

Collaboration and safe push questions

Why is --force-with-lease safer than --force?

A normal push rejects a non-fast-forward branch update. Plain --force can overwrite remote work that arrived after your last observation. --force-with-lease updates only if the remote ref still matches the expected value, providing a concurrency check.

It is safer, not automatically safe. Fetch first, inspect the remote-tracking ref, announce a shared-branch rewrite, and follow repository policy. Protected branches should usually reject force pushes entirely. If a lease fails, investigate rather than immediately overriding it.

What branch protections would you propose?

Protect the default and release branches with required reviews, passing status checks, resolved conversations, and restricted deletion or force pushes. Add signed commits or a linear-history rule only when the organization can support the operational cost. A merge queue is useful when many individually passing pull requests may fail when combined; it tests changes against an updated integration state before landing.

Client-side hooks improve feedback but are not cloned automatically and can be bypassed. Enforce critical rules in CI or server-side controls. Use local hooks for fast formatting or secret checks, then make the authoritative gate reproducible remotely.

Large repositories and parallel work

How do you keep Git usable in a large history?

Measure the slow operation before changing workflow. Git's commit-graph stores graph structure and generation data that accelerates reachability walks; changed-path Bloom filters can help some path-history queries. Scheduled maintenance can update derived data and repack objects without changing source history.

Also reduce the question scope: fetch only what the task needs when supported, avoid pathological ref growth, and choose path-limited commands carefully. Performance answers should distinguish object transfer, checkout size, graph traversal, and working-tree scanning instead of prescribing shallow clone for every repository.

When would you use git worktree?

Linked worktrees let one repository have multiple checked-out branches in separate directories. They are useful for reviewing a pull request while preserving an active task, running a hotfix beside a long build, or comparing releases without repeated stash-and-switch cycles.

Each worktree has its own HEAD, index, and worktree state while sharing most repository data. Prune stale administrative records deliberately, and do not treat a worktree as an independent clone with unrelated refs.

A seven-day Git interview plan

Day 1: draw commits, parents, refs, HEAD, index, and worktree. Day 2: compare merge, rebase, and squash on the same graph. Day 3: create and abort conflicts. Day 4: recover staged scenarios with reflog and rescue branches. Day 5: run bisect and range-diff. Day 6: design branch protection, CI, and force-push policy. Day 7: answer five unfamiliar scenarios with the five-pass framework.

Frequently asked questions

Should I always rebase before opening a pull request?

No. Rebase can create a clean unpublished series, but a team may prefer merge commits, squash merging, or server-managed updates. Follow the repository contract. If others use your branch, coordinate before rewriting it.

Is a merge commit bad history?

No. A merge commit records an integration event and preserves both parent lines. It becomes unhelpful when branch boundaries carry no meaning or unmanaged merges obscure the story. History quality depends on useful commits and consistent policy, not linearity alone.

Can reflog recover anything I delete?

No. Reflog records local ref movements, not arbitrary uncommitted edits. Entries expire, object cleanup can remove unreachable data, and another clone has different reflogs. Create commits or named backup refs before risky changes.

Should I mention Git commands from memory in an interview?

Use commands to support reasoning, not replace it. State what the command changes, inspect the current state, name the safe boundary, and give a recovery path. It is better to verify an option than confidently propose a destructive one.

How do I answer a Git scenario I have never seen?

Draw the graph and inventory refs, index, worktree, and remote state. Clarify the desired history, identify who shares the commits, checkpoint recoverable state, then choose the smallest operation. Finish with tests and the team policy that prevents recurrence.

Final takeaway

The best Git interview answers make repository state visible before changing it. Use Graph → Intent → Blast Radius → Recovery → Team Contract to reason about merge, rebase, conflicts, reset, revert, reflog, bisect, pushes, and protected branches.

The goal is not command speed; it is preserving work, producing reviewable history, and collaborating without surprises.

Sources and Further Reading

Research note: This guide was checked on September 1, 2026. Core Git semantics are stable, but command versions and hosted repository policies can change; verify the current documentation for the interview scenario.