-
Notifications
You must be signed in to change notification settings - Fork 0
07. Rebasing
ivomac edited this page Mar 16, 2025
·
1 revision
- Cherry-picking is applying the changes in a specific commit on top of HEAD in the repository.
- π’ If the changes apply with no conflicts, a new commit is created.
- π‘ If the changes do not apply, conflict markers are left in the workdir to resolve.
- π You can apply several commits in a sequence. Cherry-picking stops at each conflict.
def cherry_pick(commits: list[Commit]) -> list[Commit]:- Cherry-picking creates a new commit with the same changes but a different parent.
A ββ B ββ C β main β HEAD
β²
D ββ E ββ F β feature
- We try to cherry-pick commits D, E, and F (the feature branch):
A ββ B ββ C ββ G β main β HEAD
β²
D ββ E ββ F β feature
- π’ D applied successfully.
diff(C, G)is (mostly) the same asdiff(B, D). - π‘
diff(E, D)does not apply properly on G. Conflicts need to be resolved. Example:
<<<<<<< HEAD # HEAD is G
(ours content)
=======
(theirs content)
>>>>>>> 674d107 # (part of) E's hash
- β We could decide to abort:
- π§Ή G is removed and we go back to the repo state before cherry-picking.
- βοΈ If we resolve all conflicts and eventually complete cherry-picking, the state will be:
A ββ B ββ C ββ G ββ H ββ J β main β HEAD
β²
D ββ E ββ F β feature
- π G, H, J, correspond to D, E, F in that order.
- π§ J contains changes from main and feature and effectively merged both branches.
def rebase(new_base: Commit | Branch):- Rebasing moves a series of commits forward so that the new_base commit is in their history.
- Rebasing is effectively a cherry-pick wrapper and a common merge alternative.
- It is a destructive operation (when successful), creating/deleting commits and rewriting history.
- π’ We replay the previous scenario, starting with HEAD on feature.
A ββ B ββ C β main
β²
D ββ E ββ F β feature β HEAD
- Currently, C/main is not in the history of feature.
- If feature is rebased successfully onto main, the new state will be:
A ββ B ββ C β main
β²
G ββ H ββ J β feature β HEAD
- π Again: G, H, J, correspond to D, E, F, the same commits as in the cherry-pick scenario.
- π The original commits D, E, F, still exist in the repository but are no longer referenced by any branch.
- β Rebasing is a sort of wrapper for cherry-picking, with extra branch handling.
- In the scenario above, rebasing feature onto main is the same as:
- β Creating a new feature-tmp branch in main and switching to it:
main
βΌ
A ββ B ββ C β feature-tmp β HEAD
β²
D ββ E ββ F β feature
- π Identify the commits of feature not in main's history: D, E, F.
- π Cherry-picking the feature's commits on top of feature-tmp:
main
βΌ
A ββ B ββ C ββ G ββ H ββ J β feature-tmp β HEAD
β²
D ββ E ββ F β feature
- π§½ Deleting feature and renaming feature-tmp to feature:
main
βΌ
A ββ B ββ C ββ G ββ H ββ J β feature β HEAD
- During rebasing, HEAD first changes to the new base branch.
- HEAD then moves forward as you cherry-pick commits one-by-one on top of the base branch.
- If there are conflicts during cherry-picking, conflict markers are added:
β οΈ The top version in the conflict markers will refer to the moving HEAD version.β οΈ The bottom version will refer to the commits being cherry-picked.
<<<<<<< HEAD # will go through C/G/H
(ours content)
=======
(theirs content)
>>>>>>> 674d107 # will go through D/E/F
βοΈ This can be unintuitive since HEAD will start and end in the branch being rebased (feature/F).
- Merge: Creates a new merge commit that combines changes from both branches.
- Rebase: Rewrites history by creating new commits on top of the target branch.
| Merge | Rebase |
|---|---|
| Preserves full history | Creates a linear history |
| Non-destructive | Rewrites commit history |
| Shows when branches were integrated | Makes it look like work happened sequentially |
| Creates merge commits | No extra merge commits |
- Interactive rebasing allows you to modify commits as you rebase them:
- During interactive rebasing, you can:
- π Pick: Keep the commit as is
- βοΈ Reword: Change the commit message
- π± Edit: Pause to amend the commit in the workdir
- π Squash/Fixup: Combine with previous commit, keeping/dropping its messages
- π₯ Drop: Remove the commit entirely
- π Reorder: Change the order of commits
- Interactive rebasing in-place (without changing base) let's you rewrite a branch's commit history.
- Squash/Fixup combines multiple commits into one:
A ββ B ββ C β main
β²
D ββ E ββ F β feature β HEAD
- After squashing commits E and F during in-place rebasing:
A ββ B ββ C β main
β²
D ββ G β feature β HEAD
- π€ G is a new commit with the combined changes of E and F.
- π¬ G's message will be a combination of E and F's messages.
- π§Ή Fixup would discard F's message.
- Right-click on the parent of the first commit that you want to modify.
- Select "Rebase children of [commit] interactively..."
- In the dialog that appears:
- Reorder commits by dragging
- Double-click a commit to edit its message
- Right-click for more options (squash, edit, etc.)
- Click "OK" to start the rebase