Last modified: September 13, 2025
This article is written in: 🇺🇸
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.
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
.
git rebase -i
) enables squash/reword/reorder.main
.rebase -i
.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.
Visual — before → after (moving HEAD from C to B)
BEFORE
branch: A──B──C (HEAD)
AFTER --soft
branch: A──B (HEAD)
└─ changes from C kept **staged**
AFTER --mixed (default)
branch: A──B (HEAD)
└─ changes from C kept **unstaged**
AFTER --hard
branch: A──B (HEAD)
(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.
--hard
can destroy work.--soft
or --mixed
.--hard
for disposable work or after backing up.git revert
to undo commits that are already public.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.
rebase -i
or commit --amend
on your branch.--force-with-lease
, after confirming no one else pushed.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.
git filter-repo
or BFG over raw filter-branch
for safety/speed.Note:
git filter-repo
and 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/.
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
.