4.8 KiB
4.8 KiB
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
andM^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
tomain
(ongit 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
andv1.4
.
- Example: We know a bug was introduced between
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
, rebasefeature
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 pushgit 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 (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
intofeature
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