Git: Deleting Branches, Merging, and Undoing a Bad Push
August 2, 2026 · – visitors
These three things come up all the time, and somehow the commands never quite stick between one time and the next. So here they are, written down properly.
Deleting a Branch
git branch -d feature-x
This is the safe version — Git checks first, and refuses if feature-x has commits that never made it into your current branch. If you're sure, you can override it: (1)
git branch -D feature-x
That only deletes it locally, though. If the branch also exists on the remote (GitHub, say), you need to delete it there separately:
git push origin --delete feature-x
One thing worth knowing: deleting a branch doesn't actually delete its commits. They just become unreferenced and sit in the repository until Git's garbage collector eventually sweeps them up, which can take a while. So git branch -D is more forgiving than it looks — if you delete the wrong branch, there's usually still a way back (more on that in the reflog section below). I wouldn't rely on that as a plan, but it's good to know it's there.
Merging Branches
The usual shape is: check out the branch you want to merge into, then merge the other one in.
git checkout main
git merge feature-x
What happens next depends on whether main has moved since you branched off. If it hasn't, Git just slides the main pointer forward to match feature-x — a fast-forward, no merge commit involved. If main has moved on in the meantime, Git creates an actual merge commit that ties both histories together (2).
Sometimes you want that merge commit even when a fast-forward would've been possible — it leaves a visible marker in history that a feature branch existed and was merged, rather than the change quietly blending in. For that:
git merge --no-ff feature-x
If the same lines were touched on both sides, Git stops and leaves the conflict for you to sort out:
git status
That'll list which files are conflicted. Open each one, you'll see <<<<<<<, =======, and >>>>>>> markers around the competing changes — pick what should actually stay, delete the markers, then:
git add resolved-file.txt
git commit
And if it turns into more of a mess than it's worth, you can just walk away from the whole thing:
git merge --abort
That puts everything back exactly how it was before you started merging.
Undoing a Bad Push
This is the one people panic about, and honestly the panic is usually unwarranted — but which fix you reach for actually matters here.
If there's any chance someone else has already pulled the branch, don't touch history. Add a new commit that undoes the old one instead:
git revert <bad-commit-sha>
git push
This is the boring, always-safe option. It doesn't rewrite anything — it just adds a commit on top that cancels out the mistake, so everyone's history stays in sync without anyone having to do anything special on their end (3).
If the branch is genuinely just yours and nobody's pulled it yet, you can rewind and rewrite: (4)
git reset --hard <last-good-commit-sha>
git push --force-with-lease
Use --force-with-lease, not plain --force, out of habit if nothing else. The difference matters more than it seems: --force-with-lease checks that nobody has pushed to the branch since you last fetched, and refuses if they have. Plain --force doesn't check anything — it'll happily overwrite someone else's work without so much as a warning (5).
And if you're staring at your terminal trying to remember what the last good commit even was — git log won't help here, since it only shows commits reachable from where you currently are, which doesn't include whatever you already reset away from. What you want is:
git reflog
It shows every place your branch has recently pointed to, including the ones that fell out of normal history. Scroll back to before things went wrong, then: (6)
git reset --hard HEAD@{2}
(swap in whatever position or SHA actually matches your case). The reflog is local to your machine and generally hangs onto entries for about 90 days, so it's less "emergency undo for bad pushes" and more a general safety net for "I think I just broke something" — worth remembering it exists even outside this specific situation.
Closing Thought
All three of these lean on the same underlying fact: Git almost never throws anything away immediately. Deleted branches, reset commits, old positions on a branch — they all linger around longer than they seem to. That's really what makes -D, reset --hard, and force-pushing safe enough to use day to day, as long as you know where to go looking if one of them turns out to be a mistake.
Related Reading
- Understanding Make — what actually triggers a rebuild
Further Reading
- git-branch — branch creation, listing, and deletion.
- git-merge — merge strategies and conflict resolution.
- git-revert — undoing commits by creating new ones.
- git-reset — moving a branch pointer, with the difference between
--soft,--mixed, and--hard. - git-push: --force-with-lease — why it's safer than
--force. - git-reflog — recovering commits that no longer appear in normal history.
Comments