Git and GitHub · Intermediate

Rebase, conflicts and recovering lost work

3 min read

Why it matters

On a team, main moves while you work. You will need to bring your branch up to date, resolve conflicts and occasionally undo a mistake under pressure. Engineers who can do this calmly unblock everyone; engineers who cannot tend to lose work or break shared branches.

The concept

  • Merge combines histories with a merge commit. It never rewrites existing commits: safe on shared branches.

  • Rebase replays your commits on top of another branch, producing a straight history. It rewrites your commits (new ids), so only rebase branches that others are not building on, and push with --force-with-lease.

  • Conflicts happen when both sides changed the same lines. Git stops, marks the file, and waits for you to choose.

  • The reflog records every position your branches pointed to, locally, for about 90 days by default. Almost nothing committed is ever truly lost.

Worked example: main moved while you worked

Continuing from Everyday Git in fifteen commands, a teammate changes report.sql on main while your feature/zone-report branch is open:

update-branch.sh
git switch main
printf 'select count(*) from trips where fare_amount >= 0;\n' > report.sql
git commit -am "Exclude refunds from trip count"
git push

git switch feature/zone-report
git fetch origin
git rebase origin/main
git log --oneline --graph --all
log-output
* 7768397 Add trips per pickup zone          <- your commit, replayed on top of main
* 820410e Exclude refunds from trip count
| * 166b8aa Add trips per pickup zone        <- the old copy, still on origin/feature/zone-report
|/
* aab2d4e Add trip count report

Your commit has a new id because it was rewritten. The remote branch still has the old one, so update it safely:

push-rebased.sh
git push --force-with-lease     # refuses if someone else pushed to this branch meanwhile

When a conflict happens during a rebase or merge:

conflict.sh
git status                      # lists files with conflicts
# edit each file: keep the right lines, delete the <<<<<<< ======= >>>>>>> markers
git add report.sql
git rebase --continue           # or: git merge --continue
# changed your mind?
git rebase --abort              # back to exactly where you started

Recovering "lost" work:

recover.sh
git reset --hard HEAD~1         # oops: the last commit is gone from the branch
git reflog                      # find it, e.g. "7768397 HEAD@{1}: commit: Add trips per pickup zone"
git reset --hard 7768397        # the branch points at it again

Common mistakes

  • Rebasing a shared branch such as main. Everyone else's history breaks. Rebase only your own branches.

  • git push --force without lease. It can silently delete a teammate's commits. Use --force-with-lease.

  • Resolving conflicts without running tests. A conflict-free merge can still be wrong; run the checks.

  • Panicking after reset --hard. Check the reflog first.

Interview angle

"Merge or rebase?" Answer: merge preserves history and is safe on shared branches; rebase gives a linear history for your own feature branch before review. Say which your team preferred and why, and mention --force-with-lease. "How would you undo a commit that is already on main?" Use git revert, which adds a new commit that undoes it, instead of rewriting shared history.

Practice task

  1. Create a conflict on purpose in a practice repository and resolve it both with merge and with rebase.

  2. Delete a branch with unmerged commits, then recover it from the reflog.

  3. Use git revert to undo a commit on main and read the resulting history.

Further reading