version v7.2.
For up-to-date documentation, see the
latest version.
Git clean history
5 minute read
Concept
This guide explains how to clean up your branch’s Git history. A clean history makes code reviews easier, reduces merge conflicts, and keeps the main branch readable.
- Remove noisy commits like
fix bug,wip,debug. - Group related changes into meaningful commits.
- Make the history easier to understand for reviewers.
Be careful when rebasing shared branches.
Rebasing rewrites commit history,
which can cause problems for other developers working on the same branch.
Before rebasing a shared branch,
make sure you coordinate with your team and communicate clearly.
When in doubt, prefer rebasing only your local feature branches before they are pushed.
Tasks
Make sure your work is committed
Check your status and commit any uncommitted work:
git status
git add .
git commit -m "Your latest changes"
Interactive rebase on your local history
Assuming you want to clean your last 5 commits:
git rebase -i HEAD~5
Pick, reword, edit, squash, fixup
When you run git rebase -i, an editor opens showing a list of commits and their actions.
By default, all commits are marked as pick.
You can change the action word at the start of each line to control how Git rewrites the history.
Here’s a summary of the most common and useful options:
pick→ Keep the commit as-is.
Use this when the commit is fine and doesn’t need changes.reword→ Keep the commit content, but edit the commit message.
This is useful when you want to clarify or complete commit messages.edit→ Pause the rebase at this commit so you can change its content (and/or message).
Git will stop, let you make changes, then you continue the rebase.squash→ Combine this commit with the previous one and merge both commit messages.
Use this to group related commits into one, while keeping a record of their intent.fixup→ Combine this commit with the previous one but discard its commit message.
Use this for small corrections or cleanups you want merged into the earlier commit without cluttering the final message.
You can also reorder commits by moving the lines up or down in the editor.
This lets you change the sequence of commits if needed and it allows to use the action above.
Example: You can move a commit up in the list before changing its action to fixup.
For example, we start with the following situation:
gitGraph commit id: "Start" branch dev checkout dev commit id: "Initial login form" commit id: "Continue to add backend API" commit id: "Update CSS" commit id: "Fix typo in API" commit id: "Fix CSS color"
Next, running the command git rebase -i HEAD~5 opens an editor showing these lines:
pick a1b2c3 Initial login form
pick d4e5f6 Continue to add backend API
pick j1k2l3 Update CSS
pick f7g8h9 Fix typo in API
pick m4n5o6 Fix CSS color
Remember to set your preferred editor. For example: export EDITOR=vim
To improve the commit history, we apply the following changes in the editor:
- Rename the first commit message (
reword) - Combine
Add backend APIinto the first commit usingfixup - Move
Fix typo in APIbelowContinue to add backend APIand set it tofixupto include it in the same commit group - Combine
Fix CSS colorintoUpdate CSSwithfixup
This results in the following rebase plan:
reword a1b2c3 Initial login form
fixup d4e5f6 Continue to add backend API
fixup f7g8h9 Fix typo in API
pick j1k2l3 Update CSS
fixup m4n5o6 Fix CSS color
When the editor opens for the reword step,
make sure to replace the default message with a meaningful one (Login form with backend API),
as this will be the final commit message after the fixups are applied.
After completing the rebase, we obtain a much cleaner and more meaningful commit history:
gitGraph commit id: "Start" branch dev checkout dev commit id: "Login form with backend API" commit id: "Update CSS"
To facilitate editing the rebase file, you can configure an external tool like
[git-interactive-rebase-tool].
You can also use the --autosquash
option of rebase to prepare the file
if you have used the --fixup
or --squash
options
during commits.
Some Git clients, like lazygit
, also make the rebase operation easier.
Resolve any conflicts
If conflicts occur during rebase:
git status
# Edit conflicted files
git add <file>
git rebase --continue
Rebase onto remote source branch
If your merge strategy
is Fast Forward or Merge Commit with
Semi-linear History, you need to rebase your dev branch on top of the source branch.
Assuming the source branch is called main:
# Starting from dev branch, switch to main and update it
git switch main # → on main
git pull
# back to dev branch and rebase it on main
git switch dev # → on dev
git rebase main
git switch, introduced in Git 2.23.0, instead of git checkout
Or (without updating your local main branch) :
# directly from dev branch
git pull origin main --rebase
Push your cleaned branch
If you need to update your dev branch on the remote,
you need to force the push as the history has been modified.
git push --force-with-lease --force-if-includes
--force option, use the safer options
--force-with-leasewith
–force-if-includes
.–force-with-lease: Force push only if I have the latest remote state.–force-if-includes: Force push only if I’ve incorporated remote changes locally.