Git
Merge vs rebase
7 mins
Intro
Merge and rebase are solving the same problem. Both of these commands are designed to integrate changes from one branch into another branch — they just do it in very different ways.
Rebase is often perceived as an advanced Git operation that beginners might find intimidating, but it can actually make life much easier for a development team when used with care.
Comparison |
Merge |
Rebase |
Workflow |
Easy execution with minimal intervention |
Linear commits, may result in a cleaner history |
History |
Keeps branch history, adds merge commit |
Modifies commit history, integrates with latest changes |
Complexity |
May involve complex merges and conflict resolution |
Requires better understanding of Git concepts and commands |
1. Merge
1.1. Definition
Joins two or more development histories together.
1.2. When to use merge?
Merge is the preferred approach when changes need to be integrated from one branch into another while preserving the history of both branches. This is particularly useful in scenarios where:
- Maintaining a clear record of individual branch histories is essential (e.g. tracking bug fixes or feature development).
- Developer is working on a shared branch with other developers, as merging avoids rewriting history which can cause issues for collaborators.
- Branches have diverged significantly, and merging might be simpler than resolving potential conflicts during rebase.
1.3. Pros and cons
Pros
Simple workflow
The merge operation is straight forward to execute, requiring minimal manual intervention and making it accessible for developers of all experience levels.
Preserves branch history (non-destructive)
Merging retains a clear record of each branch's development history, making it easier to track changes and understand the evolution of the codebase. Merging does not alter the existing commit history, ensuring that previous states of the project remain intact.
Cons
Cluttered history
In projects with frequent merges, the commit history can become cluttered with merge commits, potentially making it harder to navigate and understand.
Complex merges
In cases where branches have diverged significantly or conflicts arise during the merge process, resolving conflicts manually can be time-consuming and rises capability of making errors.
1.4. Examples
In case of merge conflicts, when:
- Resolution is wanted and after conflicts have been resolved,
git merge --continue
should be used.
- Resolution is not wanted,
git merge --abort
can be used.
a) Initial state
feature C2---C3---C6
/
main C0---C1---C4---C5
b1) Merging feature into main branch from initial state
feature C2---C3---C6
/
main C0---C1---C4---C5
feature C2---C3---C6
/ \
main C0---C1---C4---C5---C7
Commands used:
git checkout main
git merge feature
See example of actual repository with commits
before
and
after
merge. Note that no actual files are included, only empty commits.
b2) Merging main into feature branch from initial state
feature C2---C3---C6
/
main C0---C1---C4---C5
feature C2---C3---C6---C7
/ /
main C0-----C1-----C4-----C5
Commands used:
git checkout feature
git merge main
Download example of actual repository with commits
before
and
after
merge. Note that no actual files are included, only empty commits.
2. Rebase
2.1. Definition
Reapply sequence of commits on top of a new base commit.
2.2. When to use rebase?
Rebase is a powerful tool for integrating changes, it's best suited for specific scenarios:
Integrating latest changes
If local branch wants to be in sync with the latest changes and maintain a linear history, rebasing is the way to go.
Cleaning up local branch history
Interactive rebase (i.e. rebase with interactive mode) shines when working on a local branch before pushing it to a shared repository. It allows to squash, reorder, or edit commits for a cleaner and more concise history.
Maintaining a clean history
Rebasing is ideal for projects that prioritize a clean, linear commit history. It helps avoid the clutter caused by frequent merges.
Warning
Rebasing rewrites history. It should be used it with caution, especially on shared branches, to avoid conflicts with collaborators who have already pulled the branch.
2.3. Pros and cons
Pros
Linear history
Rebasing creates a linear sequence of commits, simplifying the project history and making it easier to understand the order of changes.
Cleaner commit history
Interactive rebase allows developers to squash, reorder, or edit commits before applying them, enabling them to tidy up the development history and create more concise and descriptive commit messages.
Integration with latest changes
Rebasing allows developers to incorporate latest changes while maintaining a linear history, avoiding the clutter of merge commits.
Cons
Rewritten history
Rebasing involves rewriting the commit history, which can potentially cause confusion or conflicts for collaborators who are working on the same branch.
Risk of data loss
Incorrectly applied or force-pushed rebases can result in the loss of commits or divergence from the original branch's history, leading to data loss or inconsistencies.
Complexity
Interactive rebasing requires a deeper understanding of Git concepts and commands, making it less accessible for beginners or those unfamiliar with advanced Git workflows.
2.4. Examples
In case of rebase conflicts, when:
- Resolution is wanted and after conflicts have been resolved,
git rebase --continue
should be used.
- Resolution is not wanted,
git rebase --abort
can be used.
a) Initial state
feature C2---C3---C6
/
main C0---C1---C4---C5
b1) Rebasing feature onto main branch from initial state
This replays the commits (in other words, changes base commit) from the feature branch (C2, C3, C6) on top of the latest commit in the main branch (C5), creating a linear history.
feature C2---C3---C6
/
main C0---C1---C4---C5
main feature
| |
C0---C1---C4---C5---C2---C3---C6
Commands used:
git checkout feature
git rebase main
Download example of actual repository with commits
before
and
after
rebase. Note that no actual files are included, only empty commits.
b2) Rebasing main onto feature branch from initial state
This replays the commits (in other words, changes base commit) from the main branch (C4, C5) on top of the latest commit in the feature branch (C6), creating a linear history.
feature C2---C3---C6
/
main C0---C1---C4---C5
feature main
| |
C0---C1---C2---C3---C6---C4---C5
Commands used:
git checkout main
git rebase feature
Download example of actual repository with commits
before
and
after
rebase. Note that no actual files are included, only empty commits.
c) Interactive rebasing feature onto main branch from initial state
feature C2---C3---C6
/
main C0---C1---C4---C5
main feature
| |
C0---C1---C4---C5---C2---C3+C6
Commands used:
git checkout feature
git rebase --interactive main
Instead of picking all commits (which would result in default rebase), the last commit has been squashed with previous commit and message C3+C6
has been added (instead of C3
and C6
).
pick commitId C2
pick commitId C3
squash commitId C6
Download example of actual repository with commits
before
and
after
interactive rebase. Note that no actual files are included, only empty commits.
See
Git Tools — Rewriting History
for more interactive rebase commands.
Resources