← Back to blog

Git rebase vs merge: when to use which

tutorial git

Two Ways to Integrate Changes

When you work with Git branches, there comes a point where you need to bring changes from one branch into another. Git gives you two main strategies for this: merge and rebase. Both achieve the same end result -- your branch has all the latest changes -- but they do it in fundamentally different ways, and choosing the right one matters for your project's history and your team's workflow.

How Merge Works

A merge takes two branches and combines them by creating a new merge commit. This merge commit has two parents: the tip of your current branch and the tip of the branch you are merging in.

git checkout feature/login
git merge main

After this, your feature branch contains all the changes from main, joined together by a merge commit. The history of both branches is preserved exactly as it happened. If you look at the commit graph, you will see the two lines of development converging at the merge point.

The key characteristics of merge:

  • Non-destructive. No existing commits are altered. The history is exactly what happened.
  • Creates a merge commit. This extra commit ties the two histories together.
  • Preserves context. You can always see when a branch was created and when it was merged back.

Fast-forward merge

If your branch has not diverged from the target (meaning there are no new commits on the target since you branched off), Git performs a fast-forward merge by default. It simply moves the branch pointer forward. No merge commit is created because none is needed. You can force a merge commit even in this case with:

git merge --no-ff feature/login

This is useful when you want to preserve the fact that work happened on a separate branch, even if the merge was trivial.

How Rebase Works

Rebase takes a different approach. Instead of creating a merge commit, it replays your commits on top of another branch. The result is a linear history that looks as if you started your work from the latest point on the target branch.

git checkout feature/login
git rebase main

What happens behind the scenes:

  • Git finds the common ancestor of the two branches.
  • It temporarily removes your branch's commits.
  • It moves your branch pointer to the tip of main.
  • It replays your commits one by one on top.

The resulting history is perfectly linear. No merge commit, no branching and converging lines in the graph. It looks as though you wrote all your code after the latest changes on main, even if that is not what actually happened.

The key characteristics of rebase:

  • Creates a linear history. The commit graph is clean and easy to read.
  • Rewrites commit hashes. The replayed commits get new SHA hashes, even though their content is the same.
  • No merge commit. The branch integrates cleanly without extra commits.

When to Use Merge

Merge is the safer and more straightforward choice in several situations:

  • Shared branches. When multiple people are working on the same branch, merge preserves everyone's history without rewriting commits that others depend on.
  • Preserving history is important. In projects where you need to trace exactly when and how changes were integrated, merge provides a complete, unaltered record.
  • Integrating long-lived branches. When merging a release branch back into main, or combining two branches that have diverged significantly, a merge commit clearly marks the integration point.
  • You want simplicity. Merge is conceptually easier. There are fewer things that can go wrong, especially for developers who are newer to Git.

When to Use Rebase

Rebase shines when you want a clean, linear project history:

  • Updating a feature branch. Before merging your feature into main, rebasing it on top of the latest main gives you a clean set of commits that apply directly without a merge commit.
  • Keeping a clean history. A linear history is easier to navigate with git log, easier to bisect when hunting bugs, and easier to review in pull requests.
  • Local cleanup. If you have been making small incremental commits while working, you can use rebase to tidy up before sharing your branch.

The Golden Rule of Rebase

Never rebase commits that have been pushed to a shared branch.

This is the single most important rule to remember. Because rebase rewrites commit hashes, anyone else who has based their work on the original commits will have problems. Their history no longer matches the rebased history, leading to duplicated commits, conflicts, and confusion.

The rule is simple: if other people might have pulled your commits, do not rebase them. Use rebase only on your own local branches, or on branches where you are the sole contributor.

If you accidentally rebase a shared branch, the other developers on the team will need to deal with the diverged history. This typically means force-pushing (which overwrites the remote) and having everyone else reset their local copies. It is disruptive and avoidable.

Interactive Rebase: Rewriting History with Precision

Interactive rebase (git rebase -i) goes beyond simply moving commits. It lets you modify the commit history itself:

git rebase -i HEAD~5

This opens a list of the last 5 commits, where you can:

  • pick -- keep the commit as is
  • reword -- change the commit message
  • edit -- pause to amend the commit
  • squash -- combine with the previous commit
  • fixup -- like squash, but discard the commit message
  • drop -- remove the commit entirely
  • reorder -- change the order by rearranging lines

Interactive rebase is powerful for cleaning up a messy branch before merging. You can squash "fix typo" commits into their parent, reword unclear messages, and reorder commits so they tell a logical story.

A Practical Workflow

Many teams use a combined approach that gets the best of both strategies:

  1. Create a feature branch from main.
  2. While working, periodically rebase your feature branch on top of main to stay up to date.
  3. Before opening a pull request, use interactive rebase to clean up your commits.
  4. Merge the feature branch into main (often using a merge commit to mark the integration point).

This gives you a clean, linear history on the feature branch and a clear merge point on main. It is a pragmatic middle ground that works well for most teams.

Rebase and Merge in GitSquid

GitSquid supports both merge and rebase directly from the interface. You can merge branches from the context menu on any branch label in the commit graph. For rebase, GitSquid includes a visual interactive rebase editor that lets you reorder, squash, fixup, reword, and drop commits by dragging and clicking rather than editing a text file in your terminal. This makes interactive rebase accessible even if you find the command-line version intimidating.

Summary

Merge Rebase
History Non-linear, preserves branches Linear, clean
Commit hashes Unchanged Rewritten
Merge commit Yes (unless fast-forward) No
Safe for shared branches Yes No
Best for Integrating shared work Cleaning up feature branches

Neither merge nor rebase is universally better. They are tools for different situations. Understand what each one does to your history, follow the golden rule of rebase, and pick the one that fits the context. Your future self reading git log will thank you.