Version Control
Git fundamentals — merge vs rebase, fetch vs pull, fork/pull-request workflow, and branching models.
9 questions
JuniorTheoryVery commonWhat is Git, and what core problem does a version control system solve?
What is Git, and what core problem does a version control system solve?
Git is a distributed version control system: it records snapshots of a project's files as commits, each with a parent, forming a history you can inspect, revert, and branch. It lets many people work in parallel on isolated branches and merge their changes, while keeping a full local copy of the repository so most operations need no server.
Common mistakes
- ✗Calling Git centralized — it is distributed, each clone holds the full history
- ✗Confusing Git with GitHub, the hosting service built on top of it
- ✗Thinking a commit stores only a diff rather than a full snapshot with a parent
Follow-up questions
- →What does a commit's SHA hash actually identify in Git?
- →Why can most Git operations run without any network connection?
MiddleTheoryCommonHow does git merge differ from git rebase, and when should you avoid rebase?
How does git merge differ from git rebase, and when should you avoid rebase?
merge joins two branches with a new merge commit, preserving the real history as a non-linear graph. rebase replays your commits onto a new base, rewriting them with new hashes to produce a linear history. Avoid rebasing commits already pushed and shared — rewriting published history forces everyone else to recover, since their copies now disagree with yours.
Common mistakes
- ✗Believing rebase preserves the original commit hashes
- ✗Rebasing a branch others have already pulled and built on
- ✗Thinking merge and rebase produce the same history shape
Follow-up questions
- →What does
git rebase --ontolet you do that a plain rebase cannot? - →How does a fast-forward merge differ from a merge that creates a commit?
MiddleTheoryCommonWhat do git reset --soft, --mixed, and --hard each do to HEAD, the index, and the working tree?
What do git reset --soft, --mixed, and --hard each do to HEAD, the index, and the working tree?
All three move the branch HEAD to the target commit; they differ only in reach. --soft moves HEAD alone, so changes stay staged. --mixed (default) also resets the index, leaving changes unstaged. --hard resets HEAD, index, and working tree, dropping uncommitted work. Reset rewrites the branch pointer — a local history edit, never for shared commits.
Common mistakes
- ✗Thinking
--softdiscards changes when it actually keeps them staged - ✗Believing reset adds an inverse commit the way
revertdoes - ✗Running
reset --hardon commits already pushed to a shared branch
Follow-up questions
- →How do you recover the commits a
reset --hardseemed to throw away? - →Why is
git revertpreferred overresetto undo a commit onmain?
JuniorCodeOccasionalFix the last commit's message and add a forgotten file with git commit --amend
Fix the last commit's message and add a forgotten file with git commit --amend
Stage the missed file, then git commit --amend -m 'fixed message'. Amend replaces the last commit, folding in the staged config.yml and the fixed message — it does not add a second commit. But amend rewrites that commit with a new hash, so once pushed and shared it forces a push --force that breaks others; only amend unpublished commits.
Common mistakes
- ✗Amending a commit that has already been pushed and shared
- ✗Thinking amend adds a new commit rather than replacing the last one
- ✗Believing amend can only change the message, not the staged files
Follow-up questions
- →Why does amending an already-pushed commit force a
push --force? - →How is
git commit --amend --no-edituseful when you only add a file?
MiddleTheoryOccasionalWhat is a Git branching model like git-flow, and what problem does it solve?
What is a Git branching model like git-flow, and what problem does it solve?
A branching model is an agreed convention for which branches exist and how changes flow between them. git-flow uses long-lived main and develop plus short-lived feature, release, and hotfix branches. It solves coordination: the team knows where work starts, how it stabilizes for a release, and how urgent fixes reach production without disrupting in-progress development.
Common mistakes
- ✗Treating git-flow as a Git feature rather than a team convention
- ✗Forgetting that hotfix branches go to production and back into develop
- ✗Assuming every project needs git-flow rather than a simpler trunk-based model
Follow-up questions
- →How does trunk-based development differ from git-flow, and when is it preferable?
- →Why does a hotfix branch in git-flow merge into both
mainanddevelop?
MiddleTheoryOccasionalWhat does git cherry-pick do, and when would you use it?
What does git cherry-pick do, and when would you use it?
git cherry-pick <commit> applies one specific commit's changes onto your current branch as a new commit with a new hash. Use it to port a fix between branches without merging the whole source branch — e.g. backporting a hotfix. Conflicts can occur; -x appends the original hash for traceability.
Common mistakes
- ✗Thinking cherry-pick reuses the original commit's hash
- ✗Believing it merges the whole source branch, not one commit
- ✗Expecting it to remove the commit from the source branch
Follow-up questions
- →How does
git cherry-pickdiffer from agit mergeof the same branch? - →What does the
-xflag add to a cherry-picked commit's message?
MiddleTheoryOccasionalHow does git fetch differ from git pull, and what is a submodule?
How does git fetch differ from git pull, and what is a submodule?
fetch downloads new commits from the remote into your remote-tracking branches but leaves your working branch untouched, so you can review before integrating. pull is fetch followed by a merge (or rebase) into the current branch, updating it in one step. A submodule is a nested repository pinned to a specific commit, letting one repo embed another at a fixed version.
Common mistakes
- ✗Thinking fetch modifies the working branch — it only updates tracking refs
- ✗Not realizing pull is fetch plus an automatic merge or rebase
- ✗Believing a submodule tracks the latest commit instead of a pinned one
Follow-up questions
- →How do you make
git pullrebase instead of merge by default? - →Why must you run
git submodule updateafter cloning a repo with submodules?
MiddleTheoryOccasionalWhat does git rebase do, and what does interactive rebase add?
What does git rebase do, and what does interactive rebase add?
git rebase <base> replays your commits onto a new base one-by-one, giving each a new hash and a linear history without a merge commit. Conflicts resolve per replayed commit. Interactive rebase (-i) lets you reorder, squash, edit, drop, or reword commits before replay, cleaning up a messy branch.
Common mistakes
- ✗Thinking rebase keeps the original commit hashes intact
- ✗Believing rebase creates a merge commit like
mergedoes - ✗Rebasing commits already pushed to a shared branch
Follow-up questions
- →Why must you avoid rebasing commits that have been pushed and shared?
- →How does
git rebase --ontomove a commit range onto an unrelated base?
MiddleCodeOccasionalYou pushed a broken commit to shared main — undo it safely without rewriting history
You pushed a broken commit to shared main — undo it safely without rewriting history
Add an inverse commit with git revert a1b2c3d, then git push. revert records the reverse diff of the bad commit as a new commit, so the broken change is undone while published commits stay in place. You add history, not rewrite it, so teammates just git pull — no force-push. Use reset or push --force only on local commits.
Common mistakes
- ✗Reaching for
reset --hardpluspush --forceon a shared branch - ✗Thinking
revertdeletes the commit instead of adding an inverse one - ✗Using
commit --amendto fix an already-pushed commit
Follow-up questions
- →How does reverting a merge commit differ, and why does it need
-m? - →When is rewriting history with
resetactually acceptable?