Git 06. Why rebase, squash, and force push Need Care
Summary
rebase and squash can make history easier to read, but rewriting already shared history can disrupt other people’s work. force push is the operation that publishes rewritten history to a remote branch, so it deserves extra care.
The conclusion of this post is that rebase and squash are useful on personal work branches, but shared branches need team policy. If a forced update is truly needed, --force-with-lease is generally safer to consider than plain --force.
Document Information
- Written on: 2026-04-21
- Verification date: 2026-04-21
- Document type: analysis
- Test environment: Windows PowerShell, temporary local Git repository and bare remote repository
- Test version: Git 2.45.2.windows.1. Git official documentation was checked on 2026-04-21.
- Source level: Git official documentation and local reproduction results.
- Note: this post focuses on the safety boundary around rebase, squash, and force push. It is not a full guide to every interactive rebase command.
Problem Definition
Beginners often run into these issues:
- They think rebase is just a prettier merge.
- They miss that squashing creates different commits.
- They do not understand why normal push is rejected after rebasing a pushed branch.
- They use
git push --forceas a habit.
This post explains why history-changing commands need care.
Verified Facts
- According to the
git rebasemanual, rebase reapplies commits on top of another base tip. Evidence: git rebase - According to the
git rebasemanual, interactive mode can reorder or combine commits. Evidence: git rebase - According to the
git commitmanual,--amendreplaces the tip of the current branch by creating a new commit. Evidence: git commit - According to the
git pushmanual, push updates remote refs, and--force-with-leaseprotects the update when the remote value is not what you expected. Evidence: git push
A basic rebase flow looks like this:
git switch feature
git rebase main
This reapplies the feature branch’s commits on top of main. The resulting content may look similar, but the commits may not be the same commits.
Directly Reproduced Results
- Directly checked result: on 2026-04-21, I created a
rebase-demobranch, advancedmain, and rebasedrebase-demoontomain.
New-Item -ItemType Directory -Path git-rebase-demo
Set-Location git-rebase-demo
git init -b main local
Set-Location local
git config user.name "Codex Test"
git config user.email "codex@example.invalid"
Set-Content -LiteralPath README.md -Value "base"
git add README.md
git commit -m "Initial commit"
Set-Location ..
git init --bare remote.git
git --git-dir=remote.git symbolic-ref HEAD refs/heads/main
Set-Location local
git remote add origin ../remote.git
git push -u origin main
git switch -c rebase-demo
Set-Content -LiteralPath rebase.txt -Value "rebase work"
git add rebase.txt
git commit -m "Add rebase work"
git push -u origin rebase-demo
$before = git rev-parse --short HEAD
git switch main
Set-Content -LiteralPath base.txt -Value "base work"
git add base.txt
git commit -m "Advance main"
git switch rebase-demo
git rebase main
$afterRebase = git rev-parse --short HEAD
Set-Content -LiteralPath rebase.txt -Value "rebase work amended"
git add rebase.txt
git commit --amend -m "Add rebase work amended"
$afterAmend = git rev-parse --short HEAD
git push --force-with-lease origin rebase-demo
git log --oneline --decorate -3
- Result summary:
$before,$afterRebase, and$afterAmendwere different values. After rebase, theAdd rebase workcommit was recreated after theAdvance maincommit, and amend changed the commit again. In the isolated bare remote,git push --force-with-lease origin rebase-demoexited with code0because the remote-tracking ref still matched the expected value.
Interpretation / Opinion
My judgment is that rebase should first be taught as “a tool that rewrites history,” not merely as “a tool that makes history pretty.” It is helpful for cleaning up a personal branch before review, but changing a branch that other people depend on creates recovery work for them.
Force push follows the same rule. It has legitimate uses, but it should not be a default habit. Branches such as main, release, or production deployment branches are usually better protected by branch protection and review policies.
--force-with-lease is safer than plain --force, but it is not an absolute lock. It protects the update by checking that the remote ref still has the value you expect, so environments with background fetches or multiple remote configurations need extra care.
Limits and Exceptions
This post does not cover every interactive rebase command such as pick, reword, edit, squash, and fixup. It also does not treat hosted squash merge buttons as identical to local interactive rebase.
The reproduction used only an isolated bare remote. In real hosted repositories, protected branches, required reviews, or required status checks may reject force pushes.
Related Posts
- DevOps Operations Flow
- Reproducing and Resolving a Basic Conflict
- Connecting tags, releases, and Docker Image Versions
- PR/MR Collaboration Flow and Review Criteria
References
- Git, git rebase
- Git, git commit
- Git, git push
댓글남기기