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
  

 
Playground

Dive deeper with animation .


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
  

 
Playground

Dive deeper with animation .

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
  

 
Playground

Dive deeper with animation .

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
  

 
Playground

Dive deeper with animation .


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
  

 
Playground

Dive deeper with animation .

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
  

 
Playground

Dive deeper with animation .

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