skip to content

questions

26

In Git, what does creating a branch with git branch feature actually do?

level: juniorimportance: must knowfreq 82%

answer

  1. Think about how much data is written
  2. Measure it in bytes, not megabytes
  3. It stores one commit hash
  4. HEAD does not move

basics

~20 s

It writes one new ref holding the hash of the commit you branched from. No files are copied and no history is duplicated, which is why branching is instant in a repository of any size.

solid answer

~40 s

`git branch feature` creates a single reference: a name under `refs/heads/` whose value is the commit hash that `HEAD` currently resolves to. In a fresh repository that is literally a file, `.git/refs/heads/feature`, containing the hash plus a newline — roughly 41 bytes. Nothing else changes: no objects are written, no working-tree files are touched, and `HEAD` still points at the branch you were on, so `git branch feature` does **not** switch you to it. Use `git switch -c feature` (or the older `git checkout -b feature`) to create and switch in one step. Committing on a branch moves that one ref forward to the new commit; the commit itself records its parent, so the branch name is just a movable label on the commit graph, not a container of commits.

code

bash · 6 lines
bash
git branch feature
cat .git/refs/heads/feature
# 9f2b6c1a... (one commit hash plus a newline)
git rev-parse feature HEAD
# both print the same hash: creating a branch did not move HEAD
git switch -c feature2   # create AND switch in one step

go deeper

for a junior

Be able to say a branch is a pointer to a commit, and that git branch <name> creates it without switching. Know git switch -c <name> as the create-and-switch command.

for a middle

Explain what is written on disk — one ref under refs/heads/ containing a commit hash — and how committing rewrites that ref to the new commit while HEAD stays attached to the branch.

for a senior

Show that you reason about refs when things go wrong: compare git rev-parse output across names, know that commits are reachable from many branches or none, and that branch names carry no ownership of history.

for a principal

Frame cheap branching as the property that makes short-lived branches, per-task isolation, and disposable experiments affordable, and be ready to say where branch proliferation stops being free — in review load and integration lag, not in Git.

## The one-sentence model A Git branch is a **named pointer to a single commit**. It is not a copy of the code, not a directory of changes, and not a container that "holds" commits. The commit graph exists independently in the object database; a branch is one mutable name attached to one node in that graph. ## What the command writes When you run `git branch feature`, Git resolves the start point (by default whatever `HEAD` currently points to), verifies it is a commit, and records that commit's hash under the name `refs/heads/feature`. In a repository whose refs are unpacked, this is a plain text file at `.git/refs/heads/feature` containing the 40 hex characters of the hash and a trailing newline. Git may also store refs in a packed form or in an alternative ref backend; either way the logical content is the same — one name, one hash. You can create a branch pointing anywhere, not just at `HEAD`: - `git branch feature <commit>` — start from an explicit commit, tag, or another branch name. - `git branch -f feature <commit>` — move an existing branch to a different commit (dangerous if someone is standing on it). Because the operation writes one small ref, it is O(1). This is the concrete reason "branching is cheap in Git" — a claim interviewers like to hear justified rather than repeated. ## What the command does not do `git branch feature` does not change `HEAD`, does not touch the index, and does not modify a single file in your working tree. Candidates who create a branch, keep committing, and then find their commits on the old branch have usually missed exactly this. The switching commands are separate: - `git switch feature` — move `HEAD` to point at the existing branch and update the working tree to match. - `git switch -c feature` / `git checkout -b feature` — create it and switch in one step. ## How committing moves it When `HEAD` points at `refs/heads/feature` and you commit, Git writes a new commit object whose parent is the old tip, then rewrites `refs/heads/feature` to the new commit's hash. That is the whole of "the branch advanced". The previous commit is untouched and still reachable through the new commit's parent link. Because `HEAD` is normally a symbolic reference to a branch, the phrase "the current branch" simply means "the branch `HEAD` names". ## Consequences worth stating in an interview **Deleting a branch does not delete commits.** It removes one name. The commits stay in the object database until they become unreachable and are eventually pruned by garbage collection. **Two branches at the same commit are indistinguishable in content.** `main` and `feature` pointing at the same hash means both names describe the same snapshot and the same history; nothing is duplicated on disk. **"Which branch is a commit on?" is the wrong question.** A commit is reachable from zero or many branches. `git branch --contains <commit>` answers the reachable-from question, which is what people usually mean. **Cheap branching drives Git workflow.** Because a branch costs a ref, creating one per task, per experiment, or per bug reproduction is normal, and throwing branches away is equally cheap. ## Inspecting it `git rev-parse feature` prints the commit a branch resolves to. `git branch -v` lists branches with their tip commit and subject. `git branch --show-current` prints the name `HEAD` is attached to. These are the checks to run when someone insists their branch "lost" work: compare the hashes, and you almost always find the commits are still there under a different name or in the reflog. ## Common confusion: branches versus tags A lightweight tag is also a name pointing at a commit, but tags are meant to stay put while branches are meant to move. Committing while on a branch advances the branch; nothing advances a tag. If you remember "branch = moving label, tag = pinned label", most of the surface behavior follows.

  • If a branch is just a pointer, what makes the history under it?
    Each commit object records its own parent (or parents). The branch names one tip commit; walking parent links from there produces the history. Git reconstructs "the commits on this branch" by traversal at read time — nothing is stored per branch.
  • What happens to the commits when you delete a branch?
    Nothing immediately. Removing `refs/heads/feature` removes one name; the commit objects remain in the object database and can still be recovered through the reflog while their entries survive. They are only discarded once they are unreachable and garbage collection runs.
  • Why does git branch feature not switch you to the new branch?
    `git branch` only writes refs; it never touches `HEAD` or the working tree. Switching is a separate operation because it has to update the index and files on disk. `git switch -c feature` combines both, which is why it is the usual command.

A branch is a sticky note with a commit's address on it, not a photocopy of the building. Moving the note is instant; the building never moves.

saying these in an interview costs you the question

  • Says a branch stores a copy of the files
  • Thinks git branch also switches to the new branch
  • Claims deleting a branch deletes its commits
  • Believes each commit belongs to exactly one branch
  • Says branching a large repository is slow or expensive

context

open as a page

In Git, what do the <<<<<<<, =======, and >>>>>>> markers in a conflicted file mean?

level: juniorimportance: must knowfreq 85%

basics

~20 s

Git writes both versions of a region it could not merge into the file. Text between <<<<<<< and ======= is the side you are on; text between ======= and >>>>>>> is the incoming side. You edit the file to the final content, delete the markers, and stage it.

open as a page

In Git, what is a fast-forward merge and when can Git perform one?

level: juniorimportance: must knowfreq 80%

basics

~20 s

A fast-forward merge happens when the current branch's commit is already an ancestor of the commit being merged. Git records no merge commit; it simply moves the branch pointer forward and updates the index and working tree.

open as a page

In Git, what is a three-way merge and which three commits does it use?

level: juniorimportance: must knowfreq 68%

basics

~20 s

A three-way merge combines two branch tips using their best common ancestor, the merge base, as a reference point. Comparing each tip against that base tells Git which side changed what, so it can combine changes instead of guessing.

open as a page

In Git, what is a detached HEAD and how do you rescue commits made in one?

level: middleimportance: must knowfreq 68%

basics

~20 s

HEAD is detached when it names a commit directly instead of a branch, so commits you make advance nothing. Rescue them by creating a branch at that commit — git switch -c <name> before leaving, or git branch <name> <hash> from the reflog afterwards.

open as a page

During a git rebase conflict, which side is "ours" and which is "theirs", and why?

level: middleimportance: must knowfreq 60%

basics

~20 s

They are inverted relative to a merge. During a rebase, ours is the branch you are replaying onto — the new base plus commits already applied — and theirs is the commit from your own branch currently being replayed.

open as a page

In Git, how do --no-ff, --ff-only and merge.ff change what git merge produces?

level: middleimportance: must knowfreq 65%

basics

~20 s

--no-ff always records a merge commit, even when a fast-forward was possible. --ff-only refuses to merge unless the merge is a fast-forward, changing nothing otherwise. The merge.ff config sets the default: true, false (like --no-ff), or only (like --ff-only).

open as a page

In Git, what does git merge --squash do and what history does it leave behind?

level: middleimportance: must knowfreq 60%

basics

~20 s

git merge --squash stages the other branch's combined changes but makes no commit, does not move HEAD and records no MERGE_HEAD. The commit you make afterwards has a single parent, so the branch's individual commits and the merge link never enter history.

open as a page

In a Git merge, when is a change applied automatically and when does it become a conflict?

level: middleimportance: must knowfreq 70%

basics

~20 s

Git compares both sides against the merge base region by region. A region changed on only one side, or changed identically on both, is applied automatically; a region both sides changed differently is a conflict Git leaves for you.

open as a page

In Git, what is the difference between a merge strategy (-s) and a strategy option (-X)?

level: middleimportance: must knowfreq 50%

basics

~20 s

-s selects the algorithm that combines the branches, such as ort, ours, octopus or subtree. -X passes an option to that algorithm, such as ours, theirs, ignore-space-change or diff-algorithm, tuning how it resolves particular details.

open as a page

In Git, what does merging with -X ours do, and how is that different from -s ours?

level: seniorimportance: must knowfreq 50%

basics

~20 s

-X ours runs a normal three-way merge and silently resolves only conflicting hunks in favour of the current branch, still taking every non-conflicting change from the other side. -s ours discards the other branch's content entirely, recording a merge whose tree equals ours.

open as a page

In Git, what is the difference between git branch -d and git branch -D?

level: juniorimportance: should knowfreq 58%

basics

~20 s

git branch -d refuses to delete a branch whose commits are not already merged into its upstream or into HEAD; git branch -D is the forced form that deletes regardless. Both only remove the ref, never the commits.

open as a page

In Git, how does git switch differ from git checkout for changing branches?

level: middleimportance: should knowfreq 50%

basics

~20 s

git switch only moves HEAD between branches or commits; git checkout does that plus restoring files from a commit into the index or working tree. Switch was added with git restore to split one overloaded command into two focused ones.

open as a page

In a conflicted Git merge, what does git checkout --ours path/to/file actually do?

level: middleimportance: should knowfreq 40%

basics

~20 s

It replaces the whole working-tree file with the version from your side of the merge, taken from the index. It is file-level, not hunk-level: every change the other side made to that file is discarded, and you still have to stage the file.

open as a page

What does setting Git's merge.conflictStyle to diff3 or zdiff3 add to conflict markers?

level: middleimportance: should knowfreq 45%

basics

~20 s

Both styles add a third section, opened by |||||||, showing the merge-base version of the conflicting region, so you can see what each side changed rather than only the two results. zdiff3 additionally moves lines common to both sides out of the conflict block.

open as a page

What does git merge-base --is-ancestor report, and how do scripts use its exit code?

level: middleimportance: should knowfreq 35%

basics

~20 s

git merge-base --is-ancestor A B prints nothing and exits 0 when commit A is reachable from commit B, and exits 1 when it is not. Scripts branch on that status to test containment without parsing any output.

open as a page

What is Git's ort merge strategy, and how does it differ from the older recursive strategy?

level: middleimportance: should knowfreq 45%

basics

~20 s

ort is a rewrite of the classic three-way merge strategy and the default for two-branch merges in modern Git. It works on tree objects in memory instead of through the index and working tree, making it faster and better at directory renames, with clearer conflict reporting.

open as a page

In Git, how do you list which branches are already merged into main before deleting them?

level: seniorimportance: should knowfreq 34%

basics

~20 s

Use git branch --merged main to list branches whose tips main can reach, and --no-merged main for the rest. The test is pure reachability, so squashed or rebased work shows as unmerged; git cherry compares by patch instead.

open as a page

How do you back out of a conflicted Git merge, and what does git merge --abort restore?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Run git merge --abort. It discards the in-progress merge and restores the working tree and index to their pre-merge state. It can fail to restore changes that were already uncommitted before the merge started, so commit or stash first.

open as a page

After squash-merging a Git branch into main, why do later merges of that branch conflict?

level: seniorimportance: should knowfreq 45%

basics

~20 s

The squash commit has no parent link to the branch, so the merge base stays at the original fork point. Git therefore replays changes that main already contains in squashed form, and those re-applied hunks collide with the existing result.

open as a page

What is a criss-cross history in Git, and how does a merge choose a base then?

level: seniorimportance: should knowfreq 30%

basics

~20 s

A criss-cross history arises when two branches merge into each other in both directions, leaving several equally good common ancestors. Git merges those bases together into a single virtual merge base and runs the ordinary three-way merge against it.

open as a page

How does Git detect renames during a merge, and where does that detection break down?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Commits store no rename records, so Git infers renames at merge time by matching content: identical blobs are exact renames, and remaining files are paired by similarity. Detection fails when a file changed too much, was split, or when the rename limit is exceeded.

open as a page

How would you decide between fast-forward, --no-ff merge commits, and squash merges for a shared Git branch?

level: principalimportance: should knowfreq 40%

basics

~20 s

Decide by what you need history to support. Fast-forward and squash give a linear, easy-to-bisect log; --no-ff keeps each branch as a visible, revertible unit and makes git log --first-parent a changelog. Consistency across the repository matters more than the choice.

open as a page

What does git rerere do, and when does it actually save you work?

level: seniorimportance: nice to knowfreq 28%

basics

~20 s

Git rerere records how you resolved a conflict and replays that resolution automatically the next time the identical conflict appears. It pays off when the same conflict recurs — repeated rebases of a long-lived branch, or an integration branch rebuilt from scratch.

open as a page

What does git merge-base --fork-point do that a plain git merge-base does not?

level: seniorimportance: nice to knowfreq 24%

basics

~20 s

It consults the reflog of the reference branch to find where your branch actually forked, even if that commit is no longer reachable from the branch's current tip. Plain git merge-base only looks at commits still in the graph.

open as a page

When would you deliberately record a merge with git merge -s ours instead of taking the branch's changes?

level: principalimportance: nice to knowfreq 25%

basics

~20 s

Use it to declare a branch superseded: the merge records ancestry while keeping the current tree, so the branch stops appearing as unmerged and future merges only bring commits made after that point. The risk is silently discarding real work.

open as a page