Git FAQ
Common questions about commits, branches, merging, rebasing, and how Git stores data. Each answer is short. Links go to the full explanation.
What happens when you run git commit?
git commit does four things in sequence:
- Reads the index (
.git/index) — the staging area containing blob hashes for every tracked file. - Creates a tree object from the index — a snapshot of the entire project directory structure.
- Creates a commit object pointing to that tree, with the current HEAD commit as its parent, plus author, timestamp, and message.
- Advances the current branch ref to the new commit.
The commit's SHA-1 hash is computed from all of this — tree, parent, author, timestamp, message. Any difference in any field produces a different hash.
See How Git Objects Work for the full object model.
How does git know a file changed?
Git uses a two-step check. First, it compares the file's filesystem metadata (modification time, file size) against the cached values in .git/index. If the metadata matches, Git assumes the file has not changed — no I/O needed.
If the metadata differs, Git reads the file, computes the SHA-1 hash of its contents, and compares it to the blob hash stored in the index. If the hashes differ, the file is modified.
This stat cache is why git status is fast even in large repositories — most files have not changed, and metadata comparison avoids reading file contents.
See How Git Internals Work for the index and stat cache details.
What is the difference between merge and rebase?
Merge creates a new commit with two parents, preserving the branch topology. The history shows exactly when the branch was created and when it was integrated. The three-way merge algorithm uses the merge base and both branch tips.
Rebase replays your commits onto a new base, creating new commit objects with different hashes. The history becomes linear — it looks like you wrote the commits on top of the latest main. The original commits are abandoned (but recoverable via reflog).
Use rebase for cleaning up local branches before merging. Use merge for integrating branches into shared branches.
See How Git Merging Works and How Git Rebase Works.
Can you recover a deleted branch?
Yes, almost always. Deleting a branch only removes the ref — the commits still exist in the object database. The reflog records every branch movement:
git reflog | grep "deleted-branch"
git checkout -b deleted-branch <commit-hash>
Reflog entries expire after 30 days (unreachable) or 90 days (reachable). After that, git gc may prune the orphaned commits. In practice, you have weeks to recover.
See How Git Internals Work for reflog and garbage collection.
Why do merge conflicts happen?
A conflict occurs when both branches modify the same lines in the same file, relative to their common ancestor (the merge base). Git computes two diffs — merge base to ours, merge base to theirs. If both diffs touch the same line range, Git cannot automatically choose one.
Conflicts are not errors — they are the correct behavior when two changes are ambiguous. Git marks them with <<<<<<<, =======, >>>>>>> markers for manual resolution.
The best prevention is short-lived branches and frequent merging. The longer branches diverge, the more likely they touch the same code.
See How Git Merging Works for the full conflict detection algorithm.
What is a detached HEAD?
Normally, HEAD contains a symbolic reference to a branch: ref: refs/heads/main. In detached HEAD state, HEAD contains a raw commit hash.
This happens when you check out a specific commit, a tag, or a remote-tracking branch directly. You can make commits, but they are not on any branch. When you switch to another branch, those commits become unreachable.
To save work from detached HEAD:
git checkout -b new-branch
See How Git Branching Works for the full explanation of HEAD and refs.
How does git bisect work?
git bisect performs a binary search through your commit history to find the commit that introduced a bug.
git bisect start
git bisect bad # current commit is broken
git bisect good v1.0 # this older commit was working
Git checks out the commit halfway between good and bad. You test and mark it:
git bisect good # or: git bisect bad
Git halves the range and checks out the next midpoint. In O(log n) steps (about 10 steps for 1000 commits), it identifies the exact commit that introduced the regression.
You can automate bisect with a test script:
git bisect run ./test.sh
What is the difference between git pull and git fetch?
git fetch downloads new objects and refs from the remote. It updates remote-tracking branches (origin/main) but does not touch your local branches or working tree. Fetch is always safe.
git pull is git fetch followed by git merge origin/<branch> (or git rebase if configured with pull.rebase = true). Pull modifies your local branch by integrating the fetched changes.
Prefer git fetch + explicit merge/rebase when you want to inspect remote changes before integrating. Use git pull as a shorthand when you are confident the integration will be clean.
Why does git rebase change commit hashes?
A commit's SHA-1 hash is computed from its tree, parent pointer(s), author, committer, timestamp, and message. Rebase replays commits onto a new base, which means the parent changes. Different parent means different input to the hash function means different output.
F1 and F1' (the rebased version) have the same diff and the same message, but they are different commit objects with different hashes because they have different parents.
This is why rebasing shared commits causes problems — other developers have the old hashes, and Git cannot reconcile the two histories automatically.
See How Git Rebase Works for the full mechanism.
How does git store file contents?
Git stores file contents as blob objects. A blob is the zlib-compressed result of blob <size>\0<content>, addressed by its SHA-1 hash. Blobs contain only raw file contents — no filename, no permissions, no timestamps.
Filenames are stored in tree objects, which map names to blob hashes. Two files with identical contents share the same blob, regardless of their name or location. Git deduplicates at the content level.
For storage efficiency, Git packs similar blobs into packfiles using delta compression — only the differences between similar objects are stored.
See How Git Objects Work for the complete object model.