DevOps
Part 1 of 6 · GitGit — Everyday Commands, Rebase vs Merge & Safe History
Git is a content-addressed DAG of commits plus movable refs and a staging index. This hub is the decision matrix for rebase, merge, and squash, and the map to objects, history surgery, recovery, and pull-request hygiene.
- 1Gist
- 2Maps
- 3Q&A
- 4Sandbox
Voice readout needs Web Speech Synthesis in this browser.
Question ladder
L1
What lives in .git/objects versus refs?
Answer
Objects are immutable blobs, trees, commits, and annotated tags, named by content hash. Refs are mutable pointers such as branches, tags, and HEAD.
L2
Why not commit the working tree directly?
Answer
The index lets you stage a coherent snapshot from a messy working tree, including hunks, without recording every untracked or debug edit.
L3
When is rebase the wrong way to update from main, and when is merge?
Answer
Rebase is wrong on a branch other people have pulled, because it creates new commit ids. Merge-from-main is the noisy choice on a short private pull request.
L4
What makes interactive rebase dangerous on a shared branch?
Answer
Squash, fixup, and reword rewrite commit ids. Teammates who already pulled the old tip diverge, and a later merge can duplicate changes.
L5
How do soft, mixed, and hard reset differ in data risk?
Answer
Soft moves HEAD and keeps the index and working tree. Mixed also resets the index. Hard also makes the working tree match, which destroys uncommitted work.
L6
How does reflog save you after a bad rebase?
Answer
It records the previous tip locally. You find the old commit id and create a branch or reset back to it before the entry expires.
L7
How do trunk-based development and pull-request hygiene make bisect work?
Answer
Short branches and buildable commits, or one buildable squash per pull request, keep main linear enough that bisect lands on a real regression.
Failure modes
Force-push to main
A rewritten main tip breaks everyone who based work on the old commit ids.
Uncoordinated rebase of a shared branch
New commit ids diverge from teammates who already pulled the old tip.
Hard reset of uncommitted work
reset --hard throws away working-tree edits that were never a commit, so reflog cannot restore them.
Amend after others pulled the tip
Amend creates a new commit id. Pushing it needs --force-with-lease, and only when you own the tip.
Empty merge that hides conflicts
A merge commit can record a bad resolution. The join looks clean and the bug is in the tree.
Skipping hooks in a regulated repo
--no-verify bypasses local checks. Server-side policy and CI still have to be the source of truth.
Misconceptions
Rebase deletes commits.
Rebase creates new commits. The old ids can remain reachable from the reflog until they expire.
Merge is always dirty history.
A merge commit is an intentional record of two parents. It is the right record on a shared branch.
Squash loses blame forever.
A forge squash still maps to the pull request when the message keeps the link. Fine-grained revert of one hunk inside the squash is what you lose.
Detached HEAD means the repository is corrupt.
HEAD points at a commit instead of a branch. New commits stay reachable only if you attach a branch before you leave.
Interviewer traps
Recommending reset --hard and a force-push to undo a commit already on main.
On shared main, revert. Reset and force-with-lease stay on private tips.
Explaining pipeline stages, digests, or OIDC when the question was history.
Name the CI/CD cluster as the consumer of the commit id. Stay on refs, rebase, and recovery.
Design scenario
Same prompt for every reader.
Requirements
Linear history on main via squash-merge or rebase-and-merge. Required reviews. No force-push to main. Private branches may be rewritten with --force-with-lease.
Traffic / scale
A team of 12 landing several pull requests a day. Feature branches live less than two days.
Latency
A pull request should be reviewable the same day. History cleanup happens before review, not after the commit is on main.
Consistency
main stays releasable and linear. Each landed squash or rebased commit is buildable so bisect can name a regression.
Availability
A botched rebase on a private branch is recoverable from the local reflog without rewriting main.
Failure assumptions
- Someone force-pushes a shared feature branch without telling the other author.
- A hard reset wipes uncommitted work that was never committed.
- A regression reaches main and must be found with bisect.
Constraints
- Protect main. No force-push.
- Feature branches live less than two days.
- Recover a bad interactive rebase without rewriting main.
Prompt
A team of 12 uses trunk-based development. Feature branches live less than two days. main must stay linear. Engineers must recover a botched interactive rebase and bisect a production regression.
API
What does the pull request merge button do, and which local commands match squash versus rebase versus merge?
Data
Which objects change when you rebase, and where does the old tip remain reachable?
Architecture
Where do branch protection, the reflog, and bisect sit relative to the CI job that consumes the commit id?
A private feature branch is behind main, and two teammates share a different branch
Prefer
Rebase the private branch, merge the shared one
Replay only the commits you alone own. Join a shared tip with a merge commit so nobody has to reset.
- The private pull request stays linear and easy to bisect.
- The shared branch keeps the commit ids teammates already pulled.
- A later push of the private tip uses --force-with-lease.
- main itself is never rewritten. Undo there is a revert.
Alternative
Rebase every branch, including main
New commit ids look tidy until someone else has the old tip. Their next merge duplicates work or they are forced to reset.
- A shared rebase is a coordinated incident, not a habit.
- A force-push to main breaks tags, tickets, and CI pins.
- reset --hard does not bring back uncommitted files.
Integrate, then publish, without rewriting a shared tip
The flowchart below is the same choice. Shared branches merge. Private linear history rebases, then force-with-lease only if the tip was already pushed.
- 1
Look
status, diff, and diff --staged. Read the graph before you rewrite anything. - 2
Ask who else has the tip
If teammates pull this branch, merge main in. If only you have it, rebase or squash. - 3
Rewrite only a private tip
Rebase onto origin/main or squash at merge time. Old commit ids stay in your reflog. - 4
Publish safely
A new tip that was already pushed uses --force-with-lease. main gets a revert, not a reset.
Overview
Git is the collaboration substrate. Commits are snapshots. Branches are labels. The index is the draft of the next snapshot. Integration style (merge, rebase, or squash) decides whether history stays linear, whether a shared tip stays stable, and whether bisect and revert still work next month.
Interviews probe four things:
- Can you draw blob, tree, commit, and a ref?
- Do you choose rebase, merge, or squash from who else has the branch, not from taste alone?
- Will you revert on main and reflog a private mistake?
- Will you leave pipeline stages and supply chain on the CI/CD page?
Ask this out loud: you rebased a feature branch that two teammates already pulled. What happened to their commit ids, and how do you recover the team without rewriting main?
Everyday commands
| Command | Intent | Failure if misused |
|---|---|---|
status, diff, diff --staged | See working tree vs index vs HEAD | Shipping unreviewed staged junk |
add -p | Stage hunks deliberately | Staging secrets or debug prints |
commit, commit --amend | Record or fix the tip while it is private | Amend after others pulled that tip |
switch, restore | Move HEAD, or restore paths | Confusing restore --staged with discarding edits |
log --oneline --graph | Read topology | Reviewing a patch without the graph |
fetch, pull --rebase | Update without a surprise merge | A blind merge pull that adds noise |
rebase, rebase -i | Replay or edit private history | Rebase of a shared branch |
merge, merge --squash | Integrate two topologies, or fold a branch | A surprise conflict on a long-lived branch |
cherry-pick, revert | Copy a patch, or undo by adding a commit | A cherry-pick that later duplicates a merge |
reset (soft, mixed, hard) | Move the branch pointer | A hard wipe of uncommitted work |
reflog, fsck --lost-found | Recover | Giving up while the old tip is still local |
bisect, worktree, stash | Debug, parallel checkouts, brief WIP | Ignoring a stash pop conflict |
git status -sb
git diff
git diff --staged
git log --oneline --graph --decorate -20
git show --stat HEADDecision matrix
| Situation | Prefer | Why it beats the alternatives | Failure if wrong |
|---|---|---|---|
| Private feature, update from main | rebase onto main | Linear pull request, easy bisect | Merge-from-main spam in the pull request |
| Shared long-lived branch | merge main in | Preserves the shared tip. No rewrite | Rebase forces everyone to reset |
| One commit on main | Squash, local or on the forge | Clean main. Review stays on the pull request | Fine-grained revert needs the pull request id |
| Hotfix onto a release | cherry-pick | Smallest surface | Duplicate commits if the branches later merge |
| Undo a commit already on main | revert | Additive and safe for everyone who pulled | reset --hard plus force on main |
Rule of thumb: rewrite only history you alone have published, and publish that rewrite with --force-with-lease. Shared tips merge. Published main reverts.
Decisions
- 1
1. Integrate work
- next2. Branch shared?
- ?
2. Branch shared?
- no3. Want linear history?
- yes6. Merge or announce
- ?
3. Want linear history?
- yes4. Rebase or squash
- no5. Merge
- 4
4. Rebase or squash
- next7. Tip already pushed?
- 5
5. Merge
- 6
6. Merge or announce
- next10. Do not force main
- ?
7. Tip already pushed?
- yes8. force-with-lease
- no9. Push normally
- 8
8. force-with-lease
- 9
9. Push normally
- 10
10. Do not force main
Lesson map
Git — Everyday Commands, Rebase vs Merge & Safe History
Git is a content-addressed DAG of commits plus movable refs and a staging index. This hub is the decision matrix for rebase, merge, and squash, and the map to objects, history surgery, recovery, and pull-request hygiene.
Architecture. Architecture
Select a node to see why it exists, or an edge to see the protocol, direction, effect, and consequence.
Mermaid export
flowchart TB start["1. Integrate work"] shared["2. Branch shared?"] linear["3. Want linear history?"] tidy["4. Rebase or squash"] start -->|1. Integrate work| shared shared -->|no| linear linear -->|yes| tidy
Objects, refs, and the index
A commit points at a tree. A tree points at blobs and other trees. A branch ref points at a commit. HEAD usually points at a branch. git add updates the index. git commit writes a new commit from that index. The object lesson is the full picture.
Flow
- 1
1. Working tree
- next2. Index after add
- 2
2. Index after add
- next3. Commit object
- 3
3. Commit object
- next4. Tree
- 4
4. Tree
- next5. Blobs
- 5
5. Blobs
Flow
- 1
1. HEAD
- next2. Branch ref
- 2
2. Branch ref
- next3. Commit the ref names
- 3
3. Commit the ref names
Detail lives in Objects, refs, and the index. Graphs for the three integration styles live in Rebase vs merge vs squash.
What the rest of the cluster adds
- Objects, refs, and the index — blobs, trees, commits, HEAD, and the three trees.
- Rebase vs merge vs squash — before and after graphs, public versus private, forge buttons.
- History surgery — amend, interactive rebase, fixup, and autosquash.
- Cherry-pick, revert, reset, and reflog — additive undo versus moving a pointer.
- Branching, pull-request hygiene, bisect, and worktrees — trunk-based flow, bisect, worktrees, hooks.
What stays on the pipeline page
A pipeline builds the commit id this cluster produced. Stages, immutable digests, and supply-chain checks live on CI/CD Pipelines. Do not re-teach them here. The handoff is the SHA. The pipeline decides what must be true before that SHA can hurt production.
Choose the next move
The sandboxes encode the hub rule. They do not run Git. They only name the integration and the safe publish.
Press Run. Snippets must be self-contained — no network, files, or native modules.
Press Run. Snippets must be self-contained — no network, files, or native modules.
Interview Q&A
What is a commit?
Answer
An object with a tree id, parent ids, author, committer, and message. It is a snapshot. Diffs are computed later by comparing trees.
Merge versus rebase in one sentence?
Answer
Merge joins two tips with a merge commit that has two parents. Rebase copies your commits onto a new base, which creates new commit ids.
Why --force-with-lease instead of --force?
Answer
Lease refuses the push when the remote tip is not the commit you last fetched. Someone else pushed. A bare force would clobber that tip.
When is squash the wrong landing on main?
Answer
When the team relies on per-commit bisect or revert on main and the squash mixes a fix, a feature, and a refactor. A pull-request link does not split the tree back apart.
Is detached HEAD corruption?
Answer
No. HEAD points at a commit, not a branch. Commits you make there become unreachable after you switch away, unless you create a branch first. The reflog still sees them for a while.
Soft reset versus hard reset?
Answer
Soft moves HEAD and leaves the index and working tree alone. Hard moves HEAD and makes both the index and the working tree match the target. Uncommitted work is gone.
How do you recover a commit after reset?
Answer
git reflog, copy the old commit id, then git switch -c recover OID or reset the branch back to that id. Do this before the reflog entry expires.
Teammates already pulled the branch you rebased. Now what?
Answer
Your new tip has new commit ids. Their history diverged. Tell them. They reset or rebase onto your new tip. You do not force main. Next time, merge on any branch more than one person pulls.
What should you say in the first minute?
Answer
Commits are snapshots. Refs move. Rebase and squash are for private history. Merge is for shared history. Revert undoes main. reflog is the local safety net. The pipeline consumes the commit id and does not change these rules.
Pitfalls
- Treating rebase as a delete. The old objects remain until the reflog expires and garbage collection runs.
pullthat merges when the team wanted a linear private branch. Preferpull --rebaseonly on branches you alone own.- Amending a commit that already landed on main.
- A squash message with no pull-request link, so the next incident cannot find the review.
- Explaining CI stages when the interviewer asked how the commit graph changed.
A staff engineer asks what you do after rebasing a branch two people already pulled. Name the new commit ids, the command that refuses a clobber, the command you will not run on main, and where the old tip still lives on your machine.