Skip to main content
CodeOath
← All posts

Git95 min total · 17 partsBy CodeOath · Updated

Git Internals and Workflows: Branching, Merging, and Rebasing

Part 17 of 17 · ~3 min

Common Mistakes Worth Remembering

Every one of these turned up somewhere in the shift-swap story, and most of them inside a single week.

  • Rebasing commits someone else had already pulled. You nearly did this on Wednesday, and the only thing that made it safe was telling Theo first. Rewriting shared commits forces a painful reconciliation on everyone downstream, because their repository still has the originals and Git cannot tell the copies are the same work.
  • Assuming HEAD means "my branch" during a rebase. It does not. HEAD is the branch you are rebasing onto, and your commit is the incoming side — the exact inverse of a merge. Resolve a rebase conflict on merge instincts and you will delete the commit you are currently replaying.
  • Reaching for git push --force instead of --force-with-lease. Plain --force would have erased Theo's review commit with no record anywhere. And --force-with-lease on its own has a real gap: a bare git fetch refreshes the lease and lets the overwrite through. Pair it with --force-if-includes.
  • Resetting a branch that is already public. git reset --hard on a pushed main undoes nothing for anybody else and sets up a force-push over a shared trunk. If it is public, git revert.
  • Forgetting -m when reverting a merge commit — and then, two weeks later, forgetting that merging the branch again will report Already up to date. and change nothing. Revert the revert.
  • Confusing git fetch with git pull. fetch downloads and touches nothing local. pull immediately merges or rebases into whatever you have checked out. One is a question; the other is a change.
  • Stashing without -u. Untracked files stay in the working tree and follow you onto every branch you visit, which produces failures that look supernatural until you notice the stray file.
  • Committing generated files or secrets because .gitignore was written after the first commit. Ignoring only applies to files Git is not already tracking, and deleting a secret in a later commit does not remove it from history — it is still in every clone, and it must be treated as compromised and rotated, not just deleted.
  • Leaving work in detached HEAD. Git warns you and prints the hash. Read the warning; it is telling you exactly what to do.
  • Letting merged branches accumulate. Deleting a merged branch deletes a label and nothing else. git branch --merged main lists what is safe to remove.
  • Treating lost work as gone for good after a reset --hard gone wrong, or a rebase that took a bad turn. git reflog almost always still has it — the one real exception is work that was never committed in the first place.
  • Resolving a conflict by taking one side wholesale without reading the other. Those markers show up precisely because each person had a legitimate reason for making a different change. On Wednesday, keeping either side alone would have shipped a bug: yours drops a timezone correctness fix, Nadia's drops the feature you spent two days on. The resolution usually has to serve both intents, not crown a winner.

That last one is the only entry on this list that Git cannot help you with, and it is the one that matters most. Everything else here is a mechanism you can learn once. Reading a conflict properly is reading code carefully, under mild time pressure, at the exact moment you most want to be finished.

For the data model all of this version control is ultimately protecting — joins, transactions, and the queries themselves — that is in SQL Fundamentals: Joins, NULL, Aggregate Functions, and Subqueries, and the code lab is right there if you would rather run real code than just read about it.