One of the most common tasks in a developer’s daily workflow is integrating changes from one Git branch into another. Two primary commands serve this purpose: git merge
and git rebase
. While both achieve the same goal of combining histories, they do so in fundamentally different ways. Understanding these differences is crucial for maintaining a clean and readable project history. This article will explain how these commands work, compare their outcomes, and provide guidance on when to use each method.
Example: The Scenario
Let’s assume you’re working on a new feature on a branch named dev_working_branch
. In the meantime, other developers have committed and pushed important changes to the main branch (main
). Your goal is to update your working branch with these new changes and then integrate your feature back into main
.
The initial Git history looks like this:
A---B---C (main) \ D---E---F (dev_working_branch)
Where C
is the last common commit. In the meantime, new commits G
and H
have been added to the main
branch:
A---B---C---G---H (main) \ D---E---F (dev_working_branch)
1. Integrating Branches with git merge
git merge
is the simplest and safest integration method. It works by creating a new commit, called a “merge commit”, which links the histories of both branches together.
How to Merge dev_working_branch
into main
:
- Switch to the target branch (
main
):
git checkout main
- Fetch the latest changes from the remote (optional but recommended):
git pull origin main
- Merge the working branch into
main
:
git merge dev_working_branch
Git will create a new commit that combines the histories of both branches. If conflicts occur, Git will prompt you to resolve them before creating the merge commit.
The Resulting Git History:
The history after a git merge
operation will look like a tree. Both histories are preserved, and the new merge commit I
explicitly shows their combination.
A---B---C---G---H-------I (main) \ / D---E---F---
2. Integrating Branches with git rebase
git rebase
is a more advanced method. Instead of creating a merge commit, it “re-applies” the commits from your working branch on top of the target branch’s latest commit. This results in a clean, linear history.
How to Rebase dev_working_branch
onto main
:
- Switch to your working branch (
dev_working_branch
):
git checkout dev_working_branch
- Fetch the latest changes from the remote (optional but recommended):
git pull origin main
- Use
git rebase
to move the commits fromdev_working_branch
to the end ofmain
:
git rebase main
Git will attempt to re-apply commits
D
,E
, andF
on top of commitH
. This will create new commitsD'
,E'
, andF'
.
- Switch back to
main
and merge the working branch:
git checkout main
git merge dev_working_branch
In this scenario, Git will perform a “fast-forward merge” because
dev_working_branch
is now directly ahead ofmain
in the history. It simply moves the `main` pointer to the last commit of your working branch.
The Resulting Git History:
The history after a git rebase
operation is linear, with no extra merge commits. Commits D
, E
, and F
have been replaced with new ones (D'
, E'
, F'
).
A---B---C---G---H---D'---E'---F' (main, dev_working_branch)
3. Key Differences and When to Use Each
Feature | git merge | git rebase |
---|---|---|
History | Creates a new, “tree-like” history with merge commits. Preserves the original commits and their timestamps. | Creates a linear, “flat” history. It rewrites the commit history by creating new commits, thus changing their SHAs. |
Conflicts | Conflicts are resolved once, when the merge commit is created. | If conflicts occur, you may need to resolve them for each individual commit being re-applied. |
Usage | Ideal for branches that are shared, public, or have multiple contributors. It’s a safe option that does not rewrite history. | Ideal for local, private feature branches that no one else is working on. It helps maintain a clean and readable history. |
Skill Level | Simpler and safer for beginners. | Requires more caution, especially with public branches. Never rebase a branch that has already been shared with others! |
When to use git merge
:
- When you are working on a shared branch where other developers are also pushing their changes.
- When you want to explicitly preserve the merge history as a record that work from different branches was combined.
- When you prioritize simplicity and safety, without the risk of rewriting history.
When to use git rebase
:
- When you are working on your own, local feature branch that has not been shared yet.
- When you want to prepare a clean series of commits before merging them into
main
(e.g., before a Pull Request). You can usegit rebase -i
to squash, reorder, or edit commits. - When you want to maintain a simple, linear history that is easier to read and trace with commands like
git log
.
In summary, git merge
is a safer, non-destructive option that creates a readable, tree-like history. git rebase
, on the other hand, rewrites history to achieve a clean, linear structure. In most teams, the convention is to rebase local feature branches and use merge for main or shared branches.