Version Control
Git looks like a pile of commands, but underneath them sits a very small model, and almost every interview question probes exactly that. A commit is an immutable object holding a snapshot of the whole file tree, pointers to its parent commits, the author, the committer and the message; the commit's identifier is a hash over all of that content. So changing the parent or the metadata yields a different commit with a different hash, not an "edited old one". A branch is not a container of commits but an ordinary ref — a file with a single hash inside; HEAD is a symbolic ref pointing at the current branch. Between the working tree and the repository sits the index — the draft of the next commit, where git add puts file contents.
Everything else follows from those three entities. merge appends a commit with two parents to the graph and touches nothing existing — the history stays truthful but branchy. rebase recreates your commits on top of someone else's tip — the history becomes linear at the price of new hashes, which makes the remote branch diverge from the local one so a plain push is rejected. cherry-pick copies one commit's change and leaves the original where it was. Hooks are executable files that Git runs at fixed points, listening to their exit code.
There is no Python inside Git, but there is Python in the consequences. Python has no compiler to catch a badly applied patch — after a dubious rebase or cherry-pick the module still imports and only blows up at runtime, on one particular code path. That is why the quality gate is pre-commit — a framework itself written in Python, by the way — running ruff, black and mypy before the commit is recorded. Three traps are worth naming upfront: rebasing a published branch, --force instead of --force-with-lease, and believing that a hook on your machine guarantees anything for the team.
Topic map
- Git Flow and the branching model — a branch as a movable ref and the five branch roles —
master,develop,feature,release,hotfix. - merge vs rebase —
mergeappends a commit with two parents to the graph,rebaserecreates your commits from scratch with new hashes. - rebase, interactive mode and force push — replaying commits, the
rebase -itodo list, and why--force-with-leaseis safer than--force. - cherry-pick — copying a change — moving a single commit across branches, the new hash, and the dependency and duplicate traps.
- Hooks and pre-commit — the order client-side hooks run in, the exit code as a veto, and why a hook does not replace CI.
Common mistakes and traps
| Mistake | Consequence |
|---|---|
| Treating a branch as a container of commits | It becomes a mystery why creating a branch is instant and why deleting one removes no commit at all |
| Rebasing a branch teammates have already pulled | They keep the old commits, you hold new copies of the same changes; the next merge duplicates the history |
Using git push --force instead of --force-with-lease | Commits a teammate pushed after your last fetch become unreachable on the remote and vanish silently |
Expecting cherry-pick to keep the hash or remove the commit from the source branch | A copy with a new hash appears, the original stays put — a later merge may produce duplicates and conflicts |
Branching a hotfix off develop rather than off master | Unreleased develop code ships to production alongside the fix |
Merging a release into master only, forgetting develop | Fixes made while stabilising the release are lost and come back as a regression in the next version |
Believing pre-commit is a server-side or GitHub feature | The check is switched off with --no-verify and does not run at all for whoever never installed the hook |
| Formatting files inside a hook without re-adding them to the index | The old content from the index goes into the commit while the fixed version stays only in the working tree |
What interviews check
At junior level the topic is touched briefly and the interviewer probes the mental picture, not the commands. On Git Flow they expect two long-lived trunks (master with releases, develop for integration) plus three short-lived branch types under the rule "merge back where you branched from", with release and hotfix going back into both. On cherry-pick they expect the word "copies", not "moves". On pre-commit they expect a client-side hook of Git itself that aborts the commit with a non-zero exit code — not a hosting feature.
From middle the main question of the topic begins: the difference between merge and rebase. A correct answer is built from the model — merge creates a commit with two parents and changes no existing hash, rebase creates new commits with the same diff but a different parent, hence different hashes; the ban on rebasing published branches then follows by itself. After that come interactive rebase (squash keeps both messages, fixup discards its own; deleting a line from the todo list drops the commit) and the senior question about force push — why a plain push is rejected, how --force-with-lease differs from --force, and how git reflog brings back what was lost. The mistake is always the same: the candidate remembers the recipe "rebase, then force push" but cannot say what the lease actually checks.