cherry-pick as a Basis for Rebase
cherry-pick as a Basis for Rebase κ΄λ ¨
It is useful to think of rebase as performing git cherry-pick
β a command takes a commit, computes the patch this commit introduces by computing the difference between the parent's commit and the commit itself, and then cherry-pick
"replays" this difference.
Let's do this manually.
If we look at the difference introduced by "Commit 5" by performing git diff main <SHA_OF_COMMIT_5>
:
Note
If you want to play around with the repository I used and try out the commands for yourself, you can get the repo here (Omerr/rebase_playground
).
You can see that in this commit, John started working on a song called "Lucy in the Sky with Diamonds":
As a reminder, you can also use the command git show
to get the same output:
git show <SHA_OF_COMMIT_5>
Now, if you cherry-pick
this commit, you will introduce this change specifically, on the active branch. Switch to main
first:
git checkout main
# or
git switch main
And create another branch, just to be clear:
git checkout -b my_branch
# or
git switch -c my_branch
And cherry-pick
this commit:
git cherry-pick <SHA_OF_COMMIT_5>
Consider the log (output of git lol
):
Note
git lol
is an alias I added to Git to visibly see the history in a graphical manner. You can find it here (Omerr
).
git lol
git log --graph \
--pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' \
--abbrev-commit
To configure as an alias git lol
:
git config --global alias.lol \
"log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
It seems like you copy-pasted "Commit 5". Remember that even though it has the same commit message, and introduces the same changes, and even points to the same tree object as the original "Commit 5" in this case β it is still a different commit object, as it was created with a different timestamp.
Looking at the changes, using git show HEAD
:
They are the same as "Commit 5"'s.
And of course, if you look at the file (say, by using nano lucy_in_the_sky_with_diamonds.md
), it will be in the same state as it has been after the original "Commit 5".
Cool! π
OK, you can now remove the new branch so it doesn't appear on your history every time:
git checkout main
git branch -D my_branch
Beyond cherry-pick
β How to Use git rebase
You can look at git rebase
as a way to perform multiple cherry-pick
s one after the other β that is, to "replay" multiple commits. This is not the only thing you can do with rebase
, but it's a good starting point for our explanation.
It's time to play with git rebase
! ππ»ππ»
Before, you merged paul_branch
into john_branch
. What would happen if you rebased paul_branch
on top of john_branch
? You would get a very different history.
In essence, it would seem as if we took the changes introduced in the commits on paul_branch
, and replayed them on john_branch
. The result would be a linear history.
To understand the process, I will provide the high level view, and then dive deeper into each step. The process of rebasing one branch on top of another branch is as follows:
- Find the common ancestor.
- Identify the commits to be "replayed".
- For every commit
X
, computediff(parent(X), X)
, and store it as apatch(X)
. - Move
HEAD
to the new base. - Apply the generated patches in order on the target branch. Each time, create a new commit object with the new state.
The process of making new commits with the same changesets as existing ones is also called "replaying" those commits, a term we have already used.