Dangerous Commands
Some git commands are powerful but risky because they can rewrite history, move branch tips, or discard work. Used carelessly, they break open reviews, hide teammatesβ changes, and make it hard to trace what actually shipped. Treat history edits as exceptional: prefer additive fixes for shared code, keep risky changes local until youβre sure, and coordinate before publishing them. Always back up your branch, read prompts carefully, and verify the target youβre changing. In short, these tools are essential for cleanupβjust use them sparingly, with safeguards and team alignment.
Rebase (git rebase)
Rebase takes the commits on your branch and replays them on top of a new base (usually the updated main), creating new commit IDs for each replayed commit. Itβs commonly used to keep a feature branch up to date or to clean up history (e.g., squash, reorder, edit commits).
Visual β before β after (rebasing feature onto main)
BEFORE
main: AββBββC
\
feature: DββE
AFTER
main: AββBββCββD'ββE' (D,E replayed; new hashes)
Does this rewrite history?
Yes. Rebased commits get new hashes. If others already pulled the old history, youβll create divergence.
When is it safe?
Safe on local/unshared branches. If you must rebase a published branch, coordinate and use git push --force-with-lease.
Advantages
- Produces a linear, easy-to-read history.
- Lets you resolve conflicts once against the latest base.
- Interactive mode (
git rebase -i) enables squash/reword/reorder.
Disadvantages
- History rewrite can confuse collaborators and break open PRs.
- Risk of lost work if conflicts are mishandled.
- Requires a force push to publish rewritten commits.
When to Use
- Before opening a PR, to refresh a feature branch onto
main. - To curate commits with
rebase -i. - Avoid on shared/protected branches; prefer merge if others already built on your branch.
Reset (git reset)
Reset moves the current branch (and possibly your index and working tree) to another commit. Mode determines what happens to your files: --soft keeps changes staged, --mixed (default) keeps changes unstaged, --hard discards them.
Move HEAD from C β B (git reset)
ββββββββββββββββ BEFORE ββββββββββββββββ
COMMITS (history)
A ββ B ββ C β HEAD
STAGING AREA (index)
matches C
WORKING DIRECTORY
matches C
ββββββββββββββββ AFTER --soft ββββββββββ
COMMITS (history)
A ββ B β HEAD
STAGING AREA (index)
changes from C (STAGED)
WORKING DIRECTORY
changes from C (same as index)
ββββββββββββββββ AFTER --mixed (default)
COMMITS (history)
A ββ B β HEAD
STAGING AREA (index)
matches B
WORKING DIRECTORY
changes from C (UNSTAGED)
ββββββββββββββββ AFTER --hard ββββββββββ
COMMITS (history)
A ββ B β HEAD
STAGING AREA (index)
matches B
WORKING DIRECTORY
matches B (changes from C DISCARDED)
Does this rewrite history?
Yes, the branch pointer moves. On shared branches this rewrites public history.
How is this different from revert?
reset moves your branch pointer; revert adds a new commit that undoes prior changes. Use revert on published history.
Advantages
- Quick way to undo the last commit(s) locally.
- Adjust whatβs staged vs. unstaged without editing files.
Disadvantages
--hardcan destroy work.- Using reset on shared branches breaks collaborators.
When to Use
- Local cleanups (e.g., βoops, wrong commitβ) β
--softor--mixed. - Reserve
--hardfor disposable work or after backing up. - Use
git revertto undo commits that are already public.
Force Push (git push --force / --force-with-lease)
Force push publishes a rewritten local history by overwriting the remote branch. Itβs typically needed after a rebase or amend.
Visual β before β after (overwriting remote with rebased local)
BEFORE (diverged)
origin/feature: AββBββCββD
local/feature : AββBββXββY (HEAD)
AFTER
origin/feature: AββBββXββY
local/feature : AββBββXββY (HEAD)
Is it safe?
Use --force-with-lease to refuse overwriting new remote work you havenβt seen. Coordinate with teammates first.
Where is it allowed?
Generally fine on your own feature branches. Avoid on main or protected branches.
Advantages
- Lets you publish a clean, linear history after rebase/amend.
- Removes accidental commits from the remote branch.
Disadvantages
- Can erase othersβ work if they pushed meanwhile.
- Breaks PR comment threads anchored to old commits.
When to Use
- After
rebase -iorcommit --amendon your branch. - With
--force-with-lease, after confirming no one else pushed.
History Rewrite (git filter-branch / alternatives)
filter-branch rewrites repository history commit-by-commit (e.g., to remove secrets, large files, or change authors). Modern practice prefers git filter-repo (faster/safer) or BFG Repo-Cleaner for common cases.
Visual β before β after (remove a secret added in C)
BEFORE
AββBββC[secret]ββDββE
AFTER (new hashes)
A'ββB'ββC'ββD'ββE' (secret purged from all affected commits)
Will this change commit IDs?
Yesβpotentially across most of history. All clones/forks become incompatible until updated.
What else must I do?
Rotate any exposed credentials, and force-push rewritten branches. Inform downstreams to reclone or run git fetch --all && git reset --hard origin/main (replace origin/main with the correct branch as needed) to realign their local history.
Advantages
- Removes sensitive data or bloat everywhere in history.
- Can significantly shrink repository size.
Disadvantages
- Disruptive to collaborators and forks; breaks old SHAs.
- Easy to make mistakes; recovery can be tedious.
When to Use
- Security/legal incidents; purging large binaries.
- On repos you control and after thorough backups.
- Prefer
git filter-repoor BFG over rawfilter-branchfor safety/speed.
Note:
git filter-repoand BFG Repo-Cleaner are not included with Git by default.
- To installgit filter-repo, see https://github.com/newren/git-filter-repo or install viapip install git-filter-repo.
- To use BFG, download the jar from https://rtyley.github.io/bfg-repo-cleaner/.
Amend (git commit --amend)
Amend replaces the most recent commit with a new one (e.g., fix message, add a forgotten file). The result is a new commit ID.
Visual β before β after (replace last commit)
BEFORE
AββB (HEAD)
AFTER
AββB' (HEAD) (B replaced with B')
Does this rewrite history?
Yes. If the old commit was pushed, youβll need a force push and must coordinate.
Whatβs a safe workflow?
Amend before pushing, or amend your branch and publish with --force-with-lease.
Advantages
- Quick fix for typos, messages, or small omissions.
- Keeps history tidy by avoiding extra βfixupβ commits.
Disadvantages
- Rewrites history, which can disrupt collaborators.
- Amending repeatedly can confuse review threads.
When to Use
- Local changes not yet pushed.
- Minor corrections to your own branch (with coordinated force push).
- Avoid on shared/protected branches; add a new commit instead.
Recovery Cheat Sheet
When things go wrong, these commands can help you recover:
| Situation | Recovery Command |
|---|---|
| Accidentally reset commits | git reflog β find the commit β git reset --hard <hash> |
| Lost commits from detached HEAD | git reflog β git branch recovery <hash> |
| Bad merge you want to undo | git reset --hard ORIG_HEAD (immediately after merge) |
| Need to undo a rebase | git reflog β git reset --hard <pre-rebase-hash> |
| Accidentally deleted a branch | git reflog β git branch <name> <hash> |
| Force pushed and lost remote work | Ask teammates for their local copy, or check git reflog on the server |
# The reflog is your safety net β always check it first
git reflog
# Example: recover from a bad reset
git reflog
# output:
# a1b2c3d HEAD@{0}: reset: moving to HEAD~3
# e4f5a6b HEAD@{1}: commit: Important feature
# ...
# Restore to before the reset
git reset --hard e4f5a6b
Pre-Push Safety Checklist
Before running any dangerous command on a shared branch, walk through this checklist:
- Back up your branch first:
git branch backup-$(date +%Y%m%d) HEAD - Check what youβre about to change:
git log --oneline HEAD~5..HEAD - Verify no one else is working on the branch: check with your team
- Use
--force-with-leaseinstead of--force: it refuses to push if the remote has unseen changes - After the operation: run
git logandgit diffto verify the result is what you expected - Communicate: let your team know if you rewrote shared history
# Safe force push workflow
git branch backup-$(date +%Y%m%d) # step 1: backup
git log --oneline -10 # step 2: review
git push --force-with-lease # step 4: safe push
git log --oneline -10 # step 5: verify