Skip to content
ExponaBLOG
GIT & GITHUB FOR PROFESSIONAL DEVELOPERS · DAY 081 / 100

Git interview questions: real-world lessons and examples

Questions that show real Git skill.

Expona Admin8 min read

Introduction

Git interviews aren't about reciting documentation—they're about demonstrating you've solved real problems in real codebases. The best Git interview questions: real-world lessons and examples expose how you think about version control under pressure, how you recover from mistakes, and how you keep a shared repository healthy. This guide walks through the questions that matter most and shows you how to answer them with the confidence of someone who's shipped production code.

Merge vs Rebase: Preserving History vs Linear Timelines

This question appears in nearly every Git interview, and the answer separates engineers who've thought deeply about workflow from those who treat it as binary choice.

The core difference: Merge creates a commit that ties two branches together, preserving the complete history of both paths. Rebase replays your commits on top of another branch, creating a linear history but rewriting commit hashes.

Let's walk through a real scenario. You're working on a feature branch feature/payment-retry while the main branch receives a critical bug fix:

bash

# Main receives a hotfix
main:  A -- B -- C (hotfix)

# Your feature branch was created from A
feature: A -- D -- E (your work)

With merge, you get:

bash

git checkout feature/payment-retry
git merge main
# Result:
# A -- B -- C
#  \       /
#   D -- E -- F (merge commit)

The history is complete. You can see exactly when feature work happened relative to the hotfix. If something breaks, git log --graph shows the full story.

With rebase, you get:

bash

git checkout feature/payment-retry
git rebase main
# Result:
# A -- B -- C -- D' -- E'

The timeline is linear, easier to follow, but D and E are now D' and E' (different hashes). Anyone else on your team working from the old D and E is in trouble.

When to use each: Use merge when integrating finished feature branches into shared branches (main, develop). It's safe for collaborative work. Use rebase for your own feature branch before it's pushed, or when you want to clean up local history before a PR. Never rebase commits that have already been pushed and shared—you'll corrupt your teammates' repos.

A strong answer acknowledges both trade-offs: "Merge is safer for shared branches because it preserves intent and prevents accidental history rewrites. Rebase is cleaner for local feature work where only you are affected. We use merge for PRs into main and allow rebase only within feature branches before pushing."

Undoing a Pushed Commit: Why Revert Wins

This is where theory meets panic. You pushed code to production. It broke something. What do you do?

Wrong answer: git push --force or git reset HEAD~1 && git push --force-with-lease. You've now rewritten history that other developers depend on. The next git pull will create a merge conflict nightmare. If someone else pushed on top of your commit, you've lost their work.

Right answer: git revert.

bash

# Someone pushed a bad commit
# Hash: abc123d - "Add payment discount logic"

git revert abc123d
# Creates a NEW commit that undoes the changes from abc123d
# Everyone pulls it normally, no history rewrite, no conflicts

git log --oneline
# Shows:
# def456e Revert "Add payment discount logic"
# abc123d Add payment discount logic
# 8f7a3c2 Previous work

Why is this superior? Everyone else can git pull and get the undo automatically. Shared history is intact. You can see why the commit was reverted in the log. If the revert itself causes issues, you can revert the revert.

Edge case: If the commit is so recent that no one has built on top of it—maybe it was pushed 30 seconds ago in a private branch—a hard reset and force-push might be acceptable in that narrow window. But as a rule, revert is the professional choice because it accounts for the fact that you don't fully control what others have done with your commit.

A strong interviewer answer: "I use git revert because it creates a new commit that undoes changes without rewriting shared history. If it was a private branch nobody has pulled, I might reset and force-push, but I default to revert because it's collaborative and safe."

The Reflog: Your Safety Net

Most developers don't learn the reflog until they've accidentally deleted a branch or reset away their work. Then they discover it's Git's most powerful recovery tool.

The reflog (reference log) is a local history of everywhere your HEAD and branch references have pointed. It's not the commit history—it's a record of your navigation through that history.

bash

git reflog
# Shows:
# abc123d HEAD@{0}: rebase: returning to refs/heads/feature/auth
# def456e HEAD@{1}: rebase: checkout refs/remotes/origin/main
# ghi789j HEAD@{2}: commit: Add OAuth token refresh
# klm012p HEAD@{3}: reset: moving to HEAD~3
# nop345q HEAD@{4}: merge: Fast-forward main

Each line is a time point. If you accidentally reset away commits, they're still in the reflog.

Real scenario: You were on feature/auth, did git reset --hard HEAD~5 to undo some work, then immediately realized you threw away commits you actually needed.

bash

# Before you panic, check reflog
git reflog

# Find the commit you want to recover (say it's ghi789j)
# Create a new branch from that point
git checkout -b feature/auth-recovered ghi789j

# Now your lost work is back in a branch you can inspect

You can also use reflog to go back even further:

bash

# See where you were 20 minutes ago
git reflog

# Checkout that state into a new branch to inspect it
git checkout -b checkpoint abc123d

# If it's the right state, merge it back or force-push it to your feature branch

Important limitation: Reflog is local only. If you delete your repo and clone fresh, reflog is gone. It's not synced to remote. That's why it's a safety net for recent mistakes, not a long-term history.

Finding a Bug-Introducing Commit: git bisect in Action

You know the bug exists in production. You know the feature worked two weeks ago. Somewhere in the 40 commits between then and now, someone introduced it. How do you find the culprit?

Manual review of 40 commits is painful. git bisect automates the search using binary search—it cuts the problem space in half with each test.

The manual workflow:

bash

# Start bisect
git bisect start

# Tell bisect where the bug is (current commit)
git bisect bad

# Tell bisect where the code was good (two weeks ago)
git bisect good v1.2.0

# Or use a commit hash:
git bisect good abc123d

# Git checks out the midpoint between good and bad
# Now you test: does the bug exist here?

You run your tests or manually check. If the bug exists, mark it bad. If the code works, mark it good.

bash

# Bug exists here
git bisect bad
# Git narrows further, checks out another commit

# No bug here
git bisect good
# Continues until it finds the exact commit that introduced the bug

# When done:
git bisect reset

The automated approach: This is where you win the interview. If you have automated tests, bisect can run them automatically:

bash

git bisect start
git bisect bad HEAD
git bisect good v1.2.0

# Run your test script on each bisect step
# Exit code 0 = good, non-zero = bad
git bisect run bash -c "npm test -- --testNamePattern='payment-flow'"

# Git automatically finds the bad commit

In a real e-commerce system, you might bisect using a health check script:

bash

git bisect run bash -c "npm run build && npm run test:integration && curl --fail http://localhost:3000/health"

This is invaluable when tracking down regressions in large teams. The commit that introduced the bug is identified in minutes instead of hours of manual code review.

Common Mistakes

  • Rebasing shared branches: Don't rebase commits that others have already pulled. You'll create a diverged history that causes conflicts for your entire team.
  • Force-pushing to main: Even with --force-with-lease, it's almost never the right answer when dealing with published history. Revert instead.
  • Ignoring reflog until it's too late: Learn git reflog before you need it. Once you've accidentally deleted a branch, it's too late—you're just hoping someone on the team has luck finding it.
  • Not automating bisect: Running git bisect manually for 10+ iterations is slow. If you have tests, use git bisect run and let it narrow the search automatically.
  • Confusing local reflog with remote history: Reflog is purely local. It doesn't sync with GitHub or your team's repo. It's a personal safety net, not a recovery mechanism for shared mistakes.

Key Takeaways

  • Use merge for integrating branches into shared mainlines; use rebase only for cleaning up local feature branches before they're shared.
  • Always use git revert to undo pushed commits. It preserves history and keeps your team in sync without the chaos of force-pushes.
  • The reflog is your personal safety net—it lets you recover lost commits within your local repo when you've accidentally reset or deleted branches.
  • Automate git bisect with test scripts whenever possible. Binary search finds the bug-introducing commit in minutes instead of hours.
  • Strong Git skills come from understanding why these commands exist, not just knowing the syntax. Ask yourself: how does this affect my teammates?
ShareXLinkedInReddit

Found this useful? Support the writing.

Buy me a coffee
Written by
Expona Admin
Site administrator

Comments

Loading comments…

Leave a comment

Comments are reviewed before they appear. Be kind and stay on topic.

Related articles