---
type: slide
slideOptions:
transition: slide
width: 1400
height: 900
margin: 0.1
---
# Merge vs. Rebase
---
## Linear History
- Commits are snapshots + pointer to parent, not diffs
- But for linear history, this makes no difference
- Each normal commit has one parent commit
- `c05f017^` <-- `c05f017`
- `A` = `B^` <-- `B`
- (`^` is the same as `~1`)
- Pointer to parent commit goes into hash
- `git show` gives diff of commit to parent
---
## Merge Commits
- `git checkout main && git merge feature`
- A merge commit (normally) has two parent commits `M^1` and `M^2` (don't confuse `^2` with `~2`)
- Can't show unique diff
- First parent relative to the branch you are on (`M^1` = `C`, `M^2` = `E`)
- `git show`
- `git show`: *"combined diff"*
- GitHub: `git show --first-parent`
- `git show -m`: separate diff to all parents
---
## Why is a Linear History Important?
We use here:
> Linear history := no merge commits
- Merge commits are hard to understand per se.
- A merge takes all commits from `feature` to `main` (on `git log`). --> Hard to understand
- Developers often follow projects by reading commits (reading the diffs). --> Harder to read (where happened what)
- Tracing bugs easier with linear history (see `git bisect`)
- Example: We know a bug was introduced between `v1.3` and `v1.4`.
---
## How to get a Linear History?
- Real conflicts are very rare in real projects, most merge commits are false positives (not conflicts) and should be avoided.
- If there are no changes on `main`, `git merge` does a *"fast-forward"* merge (no merge commit).
- If there are changes on `main`, rebase `feature` branch.
---
## Rebase
- `git checkout feature && git rebase main`
- States of issues change (and new parents) --> history is rewritten
- If `feature` is already on remote, it needs a force push `git push --force myfork feature` (or `--force-with-lease`).
- Be careful: Only use rebase if **only you** work on a branch (a local branch or a branch on your fork).
- For local branches very helpful: `git pull --rebase` (fetch & rebase)
---
## GitHub PR Merge Variants
- GitHub offers three ways to merge a non-conflicting (no changes in same files) PR:
- Create a merge commit
- Squash and merge
- Rebase and merge
- Look at a PR together, e.g. [PR 1432 from preCICE](https://github.com/precice/precice/pull/1432) (will be closed eventually)
> What do the options do?
---
## Squash and Merge
- ... squashes all commits into one
- Often, single commits of feature branch are important while developing the feature,
- ... but not when the feature is merged
- Works well for small feature PRs
- ... also does a rebase (interactively, `git rebase -i`)
---
## Conflicts
> But what if there is a conflict?
- Resolve by rebasing `feature` branch (recommended)
- Or resolve by merging `main` into `feature`
---
## Summary and Final Remarks
- Try to keep a linear history with rebasing whenever reasonable
- Don't use rebase on a public/shared branch during development
- Squash before merging if reasonable
- Delete `feature` branch after merging
- Local view: `git log --graph`
- Remote view on GitHub, e.g. [for preCICE](https://github.com/precice/precice/network)
---
## Further Reading
- [Bitbucket docs: "Merging vs. Rebasing"](https://www.atlassian.com/git/tutorials/merging-vs-rebasing)
- [Hackernoon: "What's the diff?"](https://hackernoon.com/git-merge-vs-rebase-whats-the-diff-76413c117333)
- [GitHub Blog: "Commits are snapshots, not diffs"](https://github.blog/2020-12-17-commits-are-snapshots-not-diffs/)
- [Stack Overflow: "Git show of a merge commit"](https://stackoverflow.com/questions/40986518/git-show-of-a-merge-commit?)