Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git cherry pick vs rebase

People also ask

Why you should not use rebase?

Rebasing can be dangerous! Rewriting history of shared branches is prone to team work breakage. This can be mitigated by doing the rebase/squash on a copy of the feature branch, but rebase carries the implication that competence and carefulness must be employed.

What is the difference between cherry-pick and merge?

With the cherry-pick command, Git lets you incorporate selected individual commits from any branch into your current Git HEAD branch. When performing a git merge or git rebase , all the commits from a branch are combined. The cherry-pick command allows you to select individual commits for integration.

Is it better to pull or rebase?

It is best practice to always rebase your local commits when you pull before pushing them. As nobody knows your commits yet, nobody will be confused when they are rebased but the additional commit of a merge would be unnecessarily confusing.

When should I use git rebase?

Use rebase whenever you want to add changes of a base branch back to a branched out branch. Typically, you do this in feature branches whenever there's a change in the main branch.


Since the time git cherry-pick learned to be able to apply multiple commits, the distinction indeed became somewhat moot, but this is something to be called convergent evolution ;-)

The true distinction lies in original intent to create both tools:

  • git rebase's task is to forward-port a series of changes a developer has in their private repository, created against version X of some upstream branch, to version Y of that same branch (Y > X). This effectively changes the base of that series of commits, hence "rebasing".

    (It also allows the developer to transplant a series of commits onto any arbitrary commit, but this is of less obvious use.)

  • git cherry-pick is for bringing an interesting commit from one line of development to another. A classic example is backporting a security fix made on an unstable development branch to a stable (maintenance) branch, where a merge makes no sense, as it would bring a whole lot of unwanted changes.

    Since its first appearance, git cherry-pick has been able to pick several commits at once, one-by-one.

Hence, possibly the most striking difference between these two commands is how they treat the branch they work on: git cherry-pick usually brings a commit from somewhere else and applies it on top of your current branch, recording a new commit, while git rebase takes your current branch and rewrites a series of its own tip commits in one way or another. Yes, this is a heavily dumbed down description of what git rebase can do, but it's intentional, to try to make the general idea sink in.

Update to further explain an example of using git rebase being discussed.

Given this situation,
a state of the repo before rebasing
The Book states:

However, there is another way: you can take the patch of the change that was introduced in C3 and reapply it on top of C4. In Git, this is called rebasing. With the rebase command, you can take all the changes that were committed on one branch and apply them onto another one.

In this example, you’d run the following:

$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command

"The catch" here is that in this example, the "experiment" branch (the subject for rebasing) was originally forked off the "master" branch, and hence it shares commits C0 through C2 with it — effectively, "experiment" is "master" up to, and including, C2 plus commit C3 on top of it. (This is the simplest possible case; of course, "experiment" could contain several dozens of commits on top of its original base.)

Now git rebase is told to rebase "experiment" onto the current tip of "master", and git rebase goes like this:

  1. Runs git merge-base to see what's the last commit shared by both "experiment" and "master" (what's the point of diversion, in other words). This is C2.
  2. Saves away all the commits made since the diversion point; in our toy example, it's just C3.
  3. Rewinds the HEAD (which points to the tip commit of "experiment" before the operation starts to run) to point to the tip of "master" — we're rebasing onto it.
  4. Tries to apply each of the saved commits (as if with git apply) in order. In our toy example it's just one commit, C3. Let's say its application will produce a commit C3'.
  5. If all went well, the "experiment" reference is updated to point to the commit resulted from applying the last saved commit (C3' in our case).

Now back to your question. As you can see, here technically git rebase indeed transplants a series of commits from "experiment" to the tip of "master", so you can rightfully tell there indeed is "another branch" in the process. But the gist is that the tip commit from "experiment" ended up being the new tip commit in "experiment", it just changed its base:
state after merging

Again, technically you can tell that git rebase here incorporated certain commits from "master", and this is absolutely correct.


With cherry-pick, the original commits/branch sticks around and new commits are created. With rebase, the whole branch is moved with the branch pointing to the replayed commits.

Let say you started with:

      A---B---C topic
     /
D---E---F---G master

Rebase:

$ git rebase master topic

You get:

              A'--B'--C' topic
             /
D---E---F---G master

Cherry-pick:

$ git checkout master -b topic_new
$ git cherry-pick A^..C

You get:

      A---B---C topic
     /
D---E---F---G master
             \
              A'--B'--C' topic_new

for more info about git this book has most of it (http://git-scm.com/book)


Cherry-picking works for individual commits.

When you do rebasing it applies all commits in the history to the HEAD of the branch that are missing there.


A short answer:

  • git cherry-pick is more "low level"
  • As such, it can emulate git rebase

Answers given above are good, I just wanted to give an example in an attempt to demonstrate their interrelation.

It is not recommended to replace "git rebase" with this sequence of actions, it's just "a proof of concept" which, I hope, helps to understand how things work.

Given the following toy repository:

$ git log --graph --decorate --all --oneline
* 558be99 (test_branch_1) Test commit #7
* 21883bb Test commit #6
| * 7254931 (HEAD -> master) Test commit #5
| * 79fd6cb Test commit #4
| * 48c9b78 Test commit #3
| * da8a50f Test commit #2
|/
* f2fa606 Test commit #1

Say, we have some very important changes (commits #2 through #5) in master which we want to include into our test_branch_1. Usually we just switch to a branch and do "git rebase master". But as we are pretending we are only equipped with "git cherry-pick", we do:

$ git checkout 7254931                # Switch to master (7254931 <-- master <-- HEAD)
$ git cherry-pick 21883bb^..558be99   # Apply a range of commits (first commit is included, hence "^")    

After all these operations our commit graph will look like this:

* dd0d3b4 (HEAD) Test commit #7
* 8ccc132 Test commit #6
* 7254931 (master) Test commit #5
* 79fd6cb Test commit #4
* 48c9b78 Test commit #3
* da8a50f Test commit #2
| * 558be99 (test_branch_1) Test commit #7
| * 21883bb Test commit #6
|/
* f2fa606 Test commit #1

As we can see, commits #6 and #7 were applied against 7254931 (a tip commit of master). HEAD was moved and points a commit which is, essentially, a tip of a rebased branch. Now all we need to do is delete an old branch pointer and create a new one:

$ git branch -D test_branch_1
$ git checkout -b test_branch_1 dd0d3b4

test_branch_1 is now rooted from the latest master position. Done!


They're both commands for rewriting the commits of one branch on top of another: the difference is in which branch - "yours" (the currently checked out HEAD) or "theirs" (the branch passed as an argument to the command) - is the base for this rewrite.

git rebase takes a starting commit and replays your commits as coming after theirs (the starting commit).

git cherry-pick takes a set of commits and replays their commits as coming after yours (your HEAD).

In other words, the two commands are, in their core behavior (ignoring their divergent performance characteristics, calling conventions, and enhancement options), symmetrical: checking out branch bar and running git rebase foo sets the bar branch to the same history as checking out branch foo and running git cherry-pick ..bar would set foo to (the changes from foo, followed by the changes from bar).

Naming-wise, the difference between the two commands can be remembered in that each one describes what it does to the current branch: rebase makes the other head the new base for your changes, whereas cherry-pick picks changes from the other branch and puts them on top of your HEAD (like cherries on top of a sundae).