Git Course 0%

What rewrites history and what does not

Beginner Core Git Git CLI ≈ 7 min

What you will learn

  • Which operations add to history and which replace it
  • Why rewriting a pushed commit causes "diverged" branches and rejected pushes
  • The rule: rewrite only what you have not pushed

After this lesson you can

  • I can tell, before running a command, whether it is safe on a shared branch
  • I know what git status looks like after history was rewritten, and what it means

Why this matters

Git can change the past: fix a commit message, squash five commits into one, remove a file from history. Those powers are useful on your own work and destructive on work you have shared. One rule separates the two, and knowing it on day one prevents the most stressful Git situations a team can have.

Two kinds of operations

Operations that add to history versus operations that rewrite it Two panels. Left, green: adds to history, safe on shared branches — commit, merge, revert, tag, push, fetch, pull. Right, red: rewrites history, only on your own unpushed work — commit --amend, rebase, reset, force push, interactive rebase (squash), filter-repo. A note explains that rewriting changes commits other people may already have. ADDS TO HISTORY safe on branches other people use git commita new snapshot git mergea new merge commit git reverta new commit that undoes one git taga name on a commit git push / fetch / pullmove commits around old commits keep their hashes REWRITES HISTORY only on your own, not-yet-pushed work git commit --amendreplaces the last commit git rebasere-creates commits git resetmoves the branch back git push --forceoverwrites the remote rebase -i, filter-reposquash, drop, purge commits get new hashes; teammates' copies no longer match
Left: operations that add commits. Right: operations that replace commits with new ones.

Recall from lesson 2.4 that a commit's hash includes its parent's hash. So:

  • Adding a commit on top leaves every existing commit untouched, with its hash. Anyone who already has those commits still has exactly the same history, plus your new commit. This is what commit, merge, revert, tag, push, fetch and pull do.
  • Rewriting a commit produces a different commit with a different hash, and therefore different hashes for everything after it. The old commits are not deleted immediately, but no branch points at them any more. This is what commit --amend, rebase, reset (when it moves a branch backwards), push --force, interactive rebase (squash, reorder, drop) and filter-repo do.

What it looks like when the rule is broken

Ana pushed a commit, then noticed a typo in the message and amended it:

Terminal
$ git commit --amend -m "docs: explain how to add a trail (#27)"
[main 7bc7f5f] docs: explain how to add a trail (#27)
 Date: Sat Sep 5 11:00:00 2026 +0200
 1 file changed, 5 insertions(+)

The commit 2f543f1 she pushed has been replaced locally by 7bc7f5f. Her local main and the remote now disagree about what the latest commit is:

Terminal
$ git status
On branch main
Your branch and 'origin/main' have diverged,
and have 1 and 1 different commits each, respectively.
  (use "git pull" if you want to integrate the remote branch with yours)

nothing to commit, working tree clean

"Diverged, 1 and 1": the remote has the old commit, she has the new one, and they are not related as parent and child. A plain git push is now rejected. Her options are both unpleasant: pull (which merges the old commit back in, creating a duplicate) or force-push (which overwrites the remote and breaks everyone who already pulled the old commit). Had she amended before pushing, none of this would exist.

The rule

Rewrite only commits that exist nowhere but your computer. Once a commit is pushed to a branch other people use, treat it as permanent: fix mistakes by adding a new commit (git revert, or simply a follow-up commit), never by rewriting.

Corollaries your team may add:

  • Feature branches that only you work on are yours to rewrite before the merge request is reviewed; many teams squash them at merge time anyway.
  • main and release branches are never rewritten by anyone; platforms enforce this with protected branches (lesson 6.9).
  • git push --force on a shared branch needs a conversation first, and --force-with-lease at minimum (lesson 12.8).

The lists

Adds to history (safe to share) Rewrites history (unpushed work only)
git commit git commit --amend
git merge git rebase, git rebase -i
git revert git reset moving a branch backwards
git tag git push --force, --force-with-lease
git push, git fetch, git pull git filter-repo, BFG
git cherry-pick (adds a copy) deleting and re-creating a branch at a different commit

Not on either list because they touch no commits: status, diff, log, add, restore, stash, switch. git reset deserves a note: with --soft or --mixed on unpushed commits it is an ordinary tidy-up; with --hard it also discards working-tree changes; on pushed commits it is history rewriting. Section 12 treats each carefully.

Common mistakes

  • Amending after pushing. The example above. If you notice at once and nobody has pulled, git push --force-with-lease on a personal branch is acceptable; on main, live with the typo.
  • "Fixing" a diverged branch with --force without knowing why it diverged. You may erase a colleague's commits. Fetch, look at git log --oneline --all, understand first.
  • Believing rewritten commits are gone. They remain in the reflog for weeks; lesson 12.1 uses that to recover from mistakes.

Try it yourself

Goal: amend an unpushed commit safely and observe the hash change.

  1. In the playground, make a small commit with a deliberate typo in its message: git commit --allow-empty -m "docs: fix typoo" (--allow-empty lets you commit without changes, useful for practice).
  2. Run git log --oneline -1 and note the hash.
  3. Run git commit --amend -m "docs: fix typo" and git log --oneline -1 again.

Expected result: the message changed and so did the hash; the old commit is no longer in the log. Because it was never pushed, nobody is affected.

Show solution

Amending creates a new commit with the corrected message and the same parent, and moves main to it. The old commit still exists in .git for a while but no branch points at it. If your playground has a remote and you had pushed first, git status would now say "diverged" — which is the whole lesson in one word.

Check yourself

1. You pushed a commit to a shared branch and then noticed a wrong word in its message. The right move is…
2. Which of these is safe to run on main after pulling?
3. After an amend, git status says your branch and origin/main "have diverged, and have 1 and 1 different commits each". What happened?

Key terms

Commit Hash (SHA) Push Remote