Git Rebase
Straight Lines, Clean Releases: A Guide to Git Rebase
Left: Git merge
— a tangled web of branch history. Right: Git rebase
— pruned, linear, and ready for clear releases.
Your git history tells a story, but sometimes it reads less like a novel and more like a scrap piece of paper made for notes. A messy commit graph is like a bundled piece of yarn — all the threads are technically there but for every merge commit it creates a twist and a knot, burying code under unrelated changes.
Think of commit graphs as keeping your workspace tidy; you can work in chaos, but a well-organised desk means that you can find what you need faster.
git rebase
is a powerful decluttering tool for your repository, helping your team produce clean, easy-to-follow releases without any added cost. When the narrative of your project becomes tangled, losing sight of the story behind your code, the first casualty is the maintainability and flexibility of your repository—core benefits that git provides.
Why should I use rebase
?
git rebase
rewrites commits so that a branch’s commits are applied on top of another commit. Compared to merge, rebase gives you controllable, linear, and easy-to-follow history.
Main benefits:
- Prune messy trees into a straight, clean history.
Rebase linearizes history: instead of a tangle of branches and merge commits, you get a single line of meaningful commits — that are easier to read and reason about. - Easier release reasoning.
A linear history makes it simple to see exactly which commits are included in a release, which helps tagging, cherry-picking and reverting. - Readable, intentional commits.
Interactive rebase (git rebase -i
) lets you squash WIP noise and craft commit messages that explain intent rather than intermediate steps. - Better “bisectability” and debugging.
git bisect
andgit blame
are simpler to interpret with a clean, linear history.
But how does it do this?
Rebase doesn’t throw away your commits — it picks them up and carefully restacks them on top of the latest branch, like moving sticky notes from one page to another. This allows for linear, readable commit graphs.
Before:
A --- B --- C --- D develop\
\\
e1 --- e2 --- e3 feature
After `merge` :
A --- B --- C --- D ---- (Merge commmit) develop\
\ /\
e1 --- e2 --- e3 ------ feature
After `rebase` :
A --- B --- C --- D --- e1 --- e2 --- e3 feature
In short: *rebase*
keeps your history straight and intentional by lifting your commits and relaying them on top of another branch or commit. Merge works, but it leaves knots that make debugging and releasing harder.
When should I use rebase
?
Everyday uses of rebase
Rebase is most useful when you want to:
- keep your branch up to date with the latest changes from
main
/develop
squash
orfixup
noisy commitsreword
oredit
commits so they make sense- split one large commit into smaller ones
- change the base of a branch
Let’s look at some common scenarios.
Keep a feature branch up to date with develop
/main
If you’ve been working on a feature branch while develop
has moved forward, rebase helps you replay your changes on top of the latest commits.
Step 1: Update your local repository
git fetch origin\
git checkout feature-branch
Step 2: Rebase onto develop
git rebase origin/develop
Step 3: Resolve conflicts if they appear
# fix conflicts in files\
git add <file>\
git rebase --continue
Step 4: Push the rebased branch
git push -f
Pro Tip: Use git rebase
instead of git merge
here—you’ll end up with a clean, straight commit history instead of extra merge commits.
Interactive rebase to change commits
Interactive rebase (git rebase -i
) is where rebase
really shines. It gives you a TODO list of commits you can reorder, squash, fix-up, reword, or drop.
Start by running:
# Start interactive rebase:\
git rebase -i origin/develop
You’ll see something like:
pick 70f4d1c feature/created-safe-api: Added auth for api\
pick b98a2d3 Commiting environment variable for prod\
pick c6e5b94 Created config for auth variables\
pick a3d11b0 fixed tests\
pick 9b2c4e8 linting\
pick f7d3a12 Flixed spealling errours
Here’s what you might do:
r 70f4d1c Flixed spealling errours # reword to remove spelling errors\
d b98a2d3 env variable for prod # drop bad commit\
pick c6e5b94 Created functionality for auth and tests\
f a3d11b0 fixed tests # combine test fixes into previous commit\
s 9b2c4e8 linting # squash linting changes into feature commit\
e f7d3a12 feature/created-safe-api # edit the commit to add forgotten files
Next you will need to work through the TODO’s for these changes.
reword
:
First you will see this:
Flixed spealling errours
You might update this to:
Fixed spelling errors
Example fix-up
/squash
TODO:
First you will see:
# This is a combination of 2 commits.\
# The first commit's message is:\
Created functionality for auth and tests
# This is the 2nd commit message:\
fixed test
# Please enter the commit message for your changes. Lines starting\
# with '#' will be ignored, and an empty message aborts the commit.
You might update this to:
Created functionality for auth and tests
Example edit
:
Stopped at f7d3a12... feature/created-safe-api\
You can amend the commit now, with\
git commit --amend\
Once you are satisfied with your changes, run\
git rebase --continue
# Step 1: Add or remove to edit the commit\
git add src/cool_image.jpg
# Step 2: commit your file edits without message edit\
git commit --amend --no-edit
# or with edit:\
git commit --amend -m "Better message for this commit"
# Step 3: continue rebase\
git rebase --continue
Remember once you are done you should:
# Check you are on your feature branch\
git branch
# Push up your changes with\
git push -f
Warning: Rebase rewrites history. Only do this on your own branches, not on branches that other teammates are using.
Split one commit into two
Sometimes you commit too much at once. With edit
, you can split a commit into smaller, more meaningful ones.
# On feature branch
git rebase -i HEAD~3
# TODO, mark the big commit with "edit"
e 70f4d1c BIG COMMIT!
When rebase stops:
git reset HEAD^ # unstages the commit's contents
Now add and commit pieces separately:
# selectively add & commit parts\
git add ui/*\
git commit -m "feature/login: Added ui login elements to page"\
git add .\
git commit -m "feature/login: Added backed logic and testing for login"\
git rebase --continue
Now you have two clean commits instead of one messy one.
Rebase a branch onto a different branch
If you’ve branched off of main
but realize it should have been off develop
, you can rebase onto the correct branch:
# Change base from main to develop\
git checkout feature\
git rebase --onto develop main feature
Abort or skip during rebase
While in a rebase, it is easy to stop the process if you think you have gone astray, or skip certain commits with:
git rebase --abort # cancel rebase and return to original state\
git rebase --skip # skip the current commit (drops it)
In short: Use rebase to keep your feature branch up to date, to polish your commit history before opening a pull request, to split big commits, or to move a branch onto the right base. Interactive rebase gives you full control over how your history looks — without the mess of merge commits.
Best practices
- Only rebase on local branches
- Communicate with teammates before rewriting history
- If you are uncomfortable with recovery tools, practice on throwaway branches first or duplicate your branch
Conclusion
Rebase is the editor’s pen: it prunes, reshapes, and straightens the plot into something anyone can understand at a glance. It’s a powerful tool which can take a messy ball of yarn and turn it into a beautiful scarf.
By keeping your history linear and your commits meaningful, you make releases easier, debugging faster, and collaboration smoother. The more intentional your commit graph, the easier it is for a future teammate to trace the changes and understand why the code exists.
rebase
isn’t about rewriting the past for the sake of it; it is about crafting a clear, maintainable story of your project’s evolution. Use it to keep your branches up to date, polish your work before sharing, and ensure your repository reflects not just what happened but why.
Clean desk, clean history, clean releases. Long live git — and long live rebase! :)
Further reading
- A good resource for interactive rebase can be found here: https://about.gitlab.com/blog/keep-git-history-clean-with-interactive-rebase/
- Practical recovery tips when git fails you:
https://ohshitgit.com - Concise rebase guide:
https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase