summerschool_simtech_2023/material/2_tue/git/merge_rebase_slides.md

4.8 KiB
Raw Blame History

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 (dont confuse ^2 with ~2)
    • Cant 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 (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
  • Dont 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

Further Reading