Merge Conflict Mayhem
You're on `feature-auth` and ready to merge. But Alice pushed 3 commits to `main` editing the same files. Git can't auto-merge.
Both edited auth.js lines 14-28. Your OAuth vs her SAML.
Merge conflicts. Rebase hell. Stuck PRs. Force-push disasters. Hotfix juggling. Blame detective. Each scenario is a story you walk through with a real terminal underneath.
You're on `feature-auth` and ready to merge. But Alice pushed 3 commits to `main` editing the same files. Git can't auto-merge.
Both edited auth.js lines 14-28. Your OAuth vs her SAML.
Your `feature-dashboard` has 5 commits. Main moved 12 ahead from 4 developers. PR says 'Cannot merge'.
Alice, Bob, Charlie, Diana all pushed changes touching your files.
PR #247 has 2 approvals but 'conflicts must be resolved'. Merge button disabled.
8 commits landed on main during 3-day review. Two refactored your module.
You made 2 commits directly on `main` instead of a feature branch. CI failing, team lead pinging.
The commits are good — just need to move them to feature/payments.
Feature merge introduced a production bug. `git revert` on merges is special — two parents, Git doesn't know which to keep.
Merge hash is m3rg3h4. Parent 1 = main. Parent 2 = feature.
Junior dev ran `git push --force` on main, wiping 6 commits. Production broken.
Your local still has old refs from last fetch. Reflog is the lifeline.
11 commits including 'WIP', 'fix typo', 'actually fix it'. Tech lead won't approve.
Squash 11 messy commits into 3 clean ones.
Deep in feature dev when P0 production bug hits. Must fix, deploy, then resume without losing anything.
Feature branch has uncommitted changes. Bug is in payment module — separate from your feature.
Customer bug in payment calculation. Need to find who changed that code, when, why — then decide revert or fix-forward.
Bug is in payment.js. Calculation was correct 2 weeks ago.
You ran `git reset --hard HEAD~5` to 'clean up', then realized 3 of those commits weren't pushed anywhere. Panic.
The commits exist in the reflog for ~90 days. Reflog is your time machine.
You ran `git branch -D experiment` to 'clean up', forgetting it had 4 commits that were never merged. PM is asking for that prototype.
The commits still live in the object store. Reflog has the tip SHA.
You made 3 quick commits but now want to combine them into one polished commit with a better message.
Soft reset rewinds HEAD but leaves the working tree and index intact.
You accidentally committed `.env` with the production AWS keys and pushed. Rotating the key is step zero — but you also need it gone from history.
Rewriting history with filter-repo (or BFG) is required. Force-push to fix remote.
You set up a new laptop and forgot to configure git. Last 4 commits show `you@old-job.com`. Your manager wants the company email everywhere.
Fix config first, then amend the last commit, then rebase to fix the older ones.
Someone committed `build/app.dmg` (500MB) two days ago. Clones now take 8 minutes. Need to nuke it from history without losing real work.
filter-repo strips a path from every commit. Force-push, then everyone re-clones.
Two weeks ago you reverted a bad merge. Now the feature is fixed and you want to merge it back — but Git acts like it's already merged and brings in nothing.
The revert commit cancels the feature. You have to revert THAT revert before re-merging.
Your PR has 5 commits: 'wip', 'wip2', 'fix tests', 'lint', 'finally'. Reviewers want one clean commit.
Interactive rebase, mark 1 as pick and the next 4 as squash (or s/f).
You committed the refactor AFTER the feature. Reviewers want the refactor first so the feature diff is small.
Interactive rebase lets you swap commit order — but conflicts can appear.
Three commits ago you wrote 'fix bug' but it was actually a feature. The whole team uses conventional commits.
Interactive rebase, mark that commit `reword`, edit the message, save.
You bundled an unrelated CSS tweak into your big API refactor commit. Reviewer asks: 'Please separate these.'
Interactive rebase, mark `edit`, reset HEAD~ to unstage, then add + commit twice.
Designer updated `logo.png` on main while you updated it on `feature-rebrand`. Merge conflict — but Git can't 3-way merge a PNG.
You can't 'edit conflict markers' in a binary. Pick one side wholesale.
Both your branch and main bumped dependencies. The merge says `package-lock.json` is in conflict — 800 lines of unreadable diff.
Never hand-edit lockfiles. Take one side, then regenerate.
You started a merge, conflicts exploded across 30 files, and you realize you merged the wrong branch entirely.
`--abort` returns the repo to pre-merge state. No commits made, no shame.
You tried `git cherry-pick a3f9b21` to grab a hotfix from another branch. Conflict everywhere. The hotfix isn't worth the pain — abort.
Cherry-pick has its own --abort that returns you to pre-pick state.
Every `git pull` is creating ugly 'Merge branch main of origin/main' commits. The team standard is rebase-on-pull.
Set pull.rebase=true in config, or use --rebase per-pull.
You have `origin` (the fork) and `upstream` (the canonical repo). You meant to push to origin, but typed `git push upstream feature` — and upstream branch protection wasn't on.
Delete the remote branch you pushed by mistake, then push to the correct remote.
You push and get: 'Updates were rejected because the remote contains work you do not have locally.' A teammate pushed while you were coding.
Pull (with rebase) first to integrate their work, then push.
A contributor sent a PR from their fork. You want to test their branch locally before merging.
Add their fork as a remote, fetch, check out their branch.
Your branch is `feat-stuff`. Team convention is `feature/<ticket>-description`. You already pushed.
Rename locally, delete the old remote branch, push the new name.
You pushed `local-test-stuff` to origin while debugging. It's cluttering the branch list — and contains a half-typed password in commit messages.
git push origin --delete <branch> removes the remote ref.
You rebased your shared `feature/auth` branch. About to push — but a teammate may have pushed to it 5 minutes ago.
--force-with-lease aborts if remote moved unexpectedly. --force never does.
You rebased onto main without fetching first. Two teammate commits that landed on your branch yesterday are gone.
Reflog has every commit your branch tip touched in the last 90 days.
You have 4 stashes from the past week. You need the one labeled 'WIP: payment flow' — not the most recent.
git stash list shows them. Reference by stash@{N}.
You ran `git stash` to switch branches, but your new untracked `migration.sql` was left behind — and you accidentally committed it on the wrong branch.
`git stash` ignores untracked by default. Use -u (or -a for ignored too).
You stashed, pulled, and popped. Pop conflict on `config.js`. The stash didn't disappear — Git kept it because pop failed.
Resolve conflict, add, commit (or not). Then `stash drop` cleans up.
You stashed WIP while on `main`. It was actually feature work. You want it on a new branch instead.
`git stash branch <name>` creates a branch from the stash's parent and applies it.
You ran `git stash drop` thinking it was an old one. It was today's WIP. Stashes don't show in reflog, but the objects still exist.
`git fsck --unreachable` lists dangling commits. Find the stash, apply by hash.
You ran `git checkout <hash>` to look at an old version, then 'just made a quick fix' and committed. Now Git warns about leaving the commit behind.
Detached HEAD commits are orphans until you branch from them.
Release engineer asked: 'Tag the current main as v1.2.3, signed and annotated, then push the tag.'
Annotated tags carry author + date + message. Lightweight tags are just refs.
You tagged `v2.0.0` on the wrong commit and pushed. CI already kicked off a release build. You need to delete the tag — fast.
Delete locally with -d, delete remote with `push --delete`.
You tagged a backlog of releases locally (v1.0, v1.1, v1.2). None are on origin. Marketing needs the GitHub releases page populated.
`git push --tags` pushes every annotated/lightweight tag in one go.
Your app needs to pin a fork of `shared-ui` at an exact commit. Vendoring is messy — a submodule is correct.
Submodules pin a sub-repo at a specific commit. Tracked via .gitmodules.
Your submodule `vendor/shared-ui` is 8 commits behind upstream. CI is failing because a fix you need lives in newer commits.
Update the submodule pointer, then commit the new SHA in the parent repo.
You're deep in a feature branch with a half-broken build. Production page is on fire. Switching branches will break your dev server.
git worktree gives you a second checkout in a sibling directory — same repo, different branch.
Login was working 3 weeks ago. Now it's broken. 87 commits landed since then. Binary search through them.
git bisect halves the commit range each step. Mark good/bad until you find the culprit.
Hotfix branch has 4 sequential commits. You need all of them on `release-1.x`. One at a time is tedious.
Use `A..B` (exclusive) or `A^..B` (inclusive) range syntax with cherry-pick.
Windows teammate committed and now every file shows as 'modified' on macOS. `git diff` is full of invisible \r characters.
Set core.autocrlf properly, add a .gitattributes, renormalize.
You added `dist/` to .gitignore but `git status` keeps showing dist files as modified. The folder was already tracked.
.gitignore only ignores UNtracked files. Already-tracked files need `git rm --cached`.
Every `git push` over HTTPS prompts you for username + token. You've typed it 40 times today.
Configure a credential helper — osxkeychain on Mac, manager on Windows, cache/store on Linux.
Customers report a P1 bug in production. Feature work on `develop` continues. You need to ship a fix from main, tag it, and merge it into develop too.
Branch from main, fix, merge back, tag, then merge main into develop.
Clone times are 12 minutes. You suspect someone committed huge files years ago. Need to find them before excising.
rev-list + cat-file -s + sort surfaces the largest blobs in history.
Power loss mid-commit. `git status` now errors: 'object file is empty'. Your local clone has corrupted objects.
fsck identifies corruption. Re-fetch missing objects from origin to repair.
Three bugfix branches (`fix/a`, `fix/b`, `fix/c`) are all approved. You need them combined onto `release/v3` for a coordinated deploy.
Create release branch from main, merge each fix, push.
A subtle UI bug appeared somewhere in the last 50 commits. Visual blame on the file gives 8 candidates. Bisect narrows it further.
Use blame to scope the file, bisect to pinpoint the commit, show to read it.
Your feature branched off `develop`, but `develop` was deleted in favor of `main` and the histories diverged. You need to replant your branch on top of main.
`git rebase --onto <newbase> <oldbase> <branch>` replays only YOUR commits onto the new base.
Mid-rebase, your phone buzzes: a collaborator pushed 2 commits to the same feature branch. You're about to overwrite their work.
Finish your rebase, fetch their work, integrate before push. Force-with-lease will refuse.
Last commit shows old email. Branch isn't pushed yet, so amending is safe.
`git commit --amend --reset-author --no-edit` rewrites author/email using current config.
You shipped v4.0 to production an hour ago. Customers are reporting checkout failures. main is public — you can't reset.
Revert (don't reset) public history. Tag the revert release as v4.0.1.
A teammate pushed `feature/payments`. You want a local copy that pulls/pushes against theirs.
`git switch --track origin/feature/payments` creates and tracks in one go.
You have 3 stashes from last month and forgot what's in each. Before applying, you want to see the diff.
`git stash show -p stash@{N}` prints the full patch.
`config/local.yml` is checked in. It should be developer-local. You need to stop tracking it but keep the file on disk.
`git rm --cached` removes from index, leaves working tree.
A mysterious feature flag `EXPERIMENTAL_FOO` appears in the codebase. No one remembers adding it. Find when and why.
`git log -S '<string>'` (pickaxe) finds commits that add/remove that exact text.