Imagine your `main` branch has new commits, and your `feature` branch also has new work. Your goal is to integrate the `feature` into `main`.
A
←
B
main
↖
C
←
D
feature
Key Point: Both branches share a common ancestor (`A`), but have since diverged. We need to combine the work from commits `C` and `D` with commit `B`.
2
The `merge` Approach
Running `git merge feature` creates a new "merge commit" (`E`). This special commit has two parents (`B` and `D`) and combines their histories.
E
main
↙
↘
B
←
A
→
D
Result: History is preserved exactly as it happened, showing the parallel work. This creates a "diamond" shape in the graph. The downside is that many merges can make the history look complex or "noisy".
3
The `rebase` Approach
Running `git rebase main` on your feature branch rewrites history. It takes your commits (`C`, `D`) and replays them *on top of* `main`.
A
←
B
main
←
C'
←
D'
feature
Result: The history is now perfectly linear. Your feature commits appear as if they were made *after* the latest work on `main`. Notice the new SHAs (`C'`, `D'`)—the original commits were discarded and new ones were created.
4
Side-by-Side Comparison
Both methods achieve the same goal—integrating your feature. The difference is entirely in the shape of your project's history.
Merge History
E
main
↙
↘
B
←
A
→
D
Rebase History
B
←
C'
←
D'
main
Merge: Preserves the true history. Best for teams who value a precise, auditable record of when work was done in parallel. Rebase: Creates a cleaner, easier-to-read linear history. Best for teams who prioritize a simple, straightforward log. The cardinal rule is to never rebase a shared, public branch.