Image of git cherry-pick | Learn to Cherry Pick Commits in Git

ADVERTISEMENT

Table of Contents

Introduction

Git is a popular version control system (VCS) often used to collaborate on a distributed code base. Git allows you to track all of the changes you make on your project using snapshots called commits.

Like other version control systems, Git allows you to store a series of commits within branches. We can diverge from the main branch, or any branch, as often as we like by creating a new branch. This workflow leads to the eventual necessity of merging some, or all, of one branch into another.

What is Git Cherry Pick?

Git cherry pick is a powerful tool for applying commits from another branch to the current branch.

Git cherry pick is a command for applying the changes made by specific commits in another branch to the current HEAD. Rather than applying all commits following a branch's divergence, such as with git merge, we can target only a specific commit or set of commits.

If you need only a small number of commits from one branch applied to your current branch, you can leverage the git cherry-pick command. Cherry pick allows you to surgically apply the changes made by commits, one at a time, from one branch to another.

Syntax to Cherry Pick a Single Commit

The most common use case of the cherry pick command is to reference a single commit and apply it to another branch. To do this, follow this syntax:

$ git cherry-pick <commit-id>

The <commit-id> parameter represents the commit to apply onto the current HEAD.

Git Cherry Pick Multiple Commits

In some cases, you might want to cherry pick multiple individual commits using a single command.

Achieving this is simple with the following syntax:

$ git cherry-pick <commit-id-1> <commit-id-2>

We simply include each commit one after the other, separated by a space.

Git Cherry Pick a Range of Commits

Cherry picking is an effective way of referencing a range of commits as well, which was introduced in Git version 1.7.2.

If you want to cherry pick a range of commits, use the following syntax:

$ git cherry-pick <commitA>..<commitB>

In this example, commitA must be older than commitB, or the command will fail. It's also important to note that if commitA needs to be included, we can add the ^ character in front of the commit in question, like so:

$ git cherry-pick commitA^..commitB

Git Cherry Pick Command Example

Now that you have a basic understanding of cherry pick, let's create an example repo and put it into practice.

We'll initialize a new repo called cherrypicker, and take the following steps:

1.) Create one empty file inside the working tree called cherry-picking.ext.

2.) Make an initial commit with the empty file, and check the log.

3.) Create a branch called feature and switch to it.

4.) Create a file inside the feature branch called cherry-feature.ext, and commit.

Let's check out what we have so far:

$ mkdir cherrypicker
$ cd cherrypicker
$ git init
$ touch cherry-picking.ext
$ git add .
$ git commit -m 'Initial commit.'
$ git log --oneline
5a34e26 (HEAD -> master) Initial commit.

$ git branch feature
$ git switch feature
Switched to branch 'feature'
$ touch cherry-feature.ext
$ git add .
$ git commit -m 'Started feature.'

Looks good. Now, let's assume that while working on our feature branch, an important bug fix was made inside the cherry-picking.ext file within the master branch.

Let us also assume we can't safely continue work on our feature branch without first applying the bug fix to the feature branch. This should be a breeze with cherry-pick, so let's try it out!

To simulate our bug fix, let's do the following:

1.) Switch to the master branch.

2.) Add the text 'Bug fix.' to cherry-picking.ext, and commit.

3.) View git log output and note the commit SHA of our bug fix.

4.) Switch to the feature branch and cherry-pick the bug fix commit.

$ git switch master
Switched to branch 'master'
$ echo 'Bug fix.' >> cherry-picking.ext
$ git commit -am 'Bug fix.'
$ git log --oneline
e211810 (HEAD -> master) Bug fix.
5a34e26 Initial commit.

$ git switch feature
Switched to branch 'feature'

$ git cherry-pick e211810
[feature 53cce80] Bug fix.
 Date: Sat Sep 17 18:08:01 2022 -0400
 1 file changed, 1 insertion(+)

$ git log --oneline
53cce80 (HEAD -> feature) Bug fix.
fc1ef1e Started feature.
5a34e26 Initial commit.

As we can see from the last two outputs, our cherry-pick was executed flawlessly. We can proceed safely with our feature branch, which was the goal.

Does Git Cherry Pick Create a New Commit?

If you look at the output from our last example, you can see that Git cherry-pick does create a new commit with a unique hash.

This is because cherry pick doesn't just extract a commit and tack it onto the current HEAD. Instead, it looks at the specified commit, compares it to its parent commit, and applies the resulting diff to a new commit at the current HEAD.

Furthermore, because a commit's ID depends on that of its parent, a cherry-picked commit will always have a new SHA1 commit ID, due to having a different history than the source commit of the cherrypick.

To verify this behavior, we can look at the two diffs in question by using the Git show command on each of the two branches:

$ git branch
* feature
  master

$ git show
commit 53cce802c7611eaf410a3087d48da761eddede1a (HEAD -> feature)
Author: Initial Commit LLC <initcommit@man.com>
Date:   Sat Sep 17 18:08:01 2022 -0400
     Bug fix.
 diff --git a/cherry-picking.ext b/cherry-picking.ext
index e69de29..1c1bca4 100644
--- a/cherry-picking.ext
+++ b/cherry-picking.ext
@@ -0,0 +1 @@
+Bug fix
\ No newline at end of file

$ git switch master
Switched to branch 'master'

$ git show
commit e211810f27270e5f23642acea586ea2ae17534ff (HEAD -> master)
Author: Initial Commit LLC <initcommit@man.com>
Date:   Sat Sep 17 18:08:01 2022 -0400
     Bug fix.
 diff --git a/cherry-picking.ext b/cherry-picking.ext
index e69de29..1c1bca4 100644
--- a/cherry-picking.ext
+++ b/cherry-picking.ext
@@ -0,0 +1 @@
+Bug fix
\ No newline at end of file

A quick review of the diff output confirms that we have two separate commits with identical diffs, but differing commit IDs.

Git Cherry Pick Conflict

A conflict occurs when a line in the file at the tip of your working branch conflicts with the same line in the file from the branch you are cherry picking from.

When using cherry pick in a large repository where frequent commits are made, it's common to run into conflicts.

To illustrate, let's create a conflict by taking the following steps:

1.) In the master branch, inside cherry-picking.ext, add the text 'Another bug fix in master' to line 2, commit, and view the log output.

2.) In the feature branch, inside cherry-picking.ext, add the text 'Modified bug fix in feature' to line 2, and commit.

3.) Attempt to cherry pick the last commit from master on top of the feature branch.

$ git commit -am 'Another bug fix in master'
[master 940fbe9] Another bug fix in master
 1 file changed, 2 insertions(+), 1 deletion(-)

$ git log --oneline
940fbe9 (HEAD -> master) Another bug fix in master
e211810 Bug fix.
5a34e26 Initial commit.

$ git switch feature
Switched to branch 'feature'
$ git commit -am 'Modified bug fix in feature.'
[feature 5f03ffa] Modified bug fix in feature.
 1 file changed, 2 insertions(+), 1 deletion(-)

$ git cherry-pick 940fbe9
Auto-merging cherry-picking.ext
CONFLICT (content): Merge conflict in cherry-picking.ext
error: could not apply 940fbe9... Another bug fix in master
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git cherry-pick --continue".
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the state before "git cherry-pick",
hint: run "git cherry-pick --abort".

As you can see, this cherry pick attempt didn't go quite as smoothly as the last one. This is because we modified the same line in cherry-picking.ext in both branches, and Git doesn't know which change to keep.

Luckily, Git makes resolving conflicts pretty simple. Taking a look inside cherry-picking.ext, we will find the following:

Bug fix
<<<<<<< HEAD
Modified bug fix in 'feature'
=======
Another bug fix in 'master'
>>>>>>> 940fbe9 (Another bug fix in master)

Git added some text to our file showing us the conflicting data. The two commits in question are separated by '=======', with the current HEAD on top, and the commit to be cherry picked on the bottom.

To resolve the conflict, you simply need to modify this file following these steps:

1.) Remove the text that Git injected into our file.

2.) Decide what text to leave and which to delete (if any).

3.) Stage the file, and continue the cherry pick operation.

In our case, let's leave both commits there. So, after step 2, our cherry-picking.ext file should look like this:

Bug fix
Modified bug fix in 'feature'
Another bug fix in 'master'

Now with our conflict resolved, we can move on to step 3 and finish the cherry pick operation:

$ git add .
$ git cherry-pick --continue
[feature 5056ca3] Another bug fix in master
 Date: Sun Sep 18 16:30:40 2022 -0400
 1 file changed, 4 insertions(+), 1 deletion(-)

$ git log --oneline
5056ca3 (HEAD -> feature) Another bug fix in master
5f03ffa Modified bug fix in feature.
53cce80 Bug fix.
fc1ef1e Started feature.
5a34e26 Initial commit.

Everything looks good. We've successfully resolved the conflict and completed the cherry pick operation.

Git Cherry Pick vs. Git Rebase

Cherry-pick keeps the original commits and branches and creates new ones. A rebase moves the base of the branch and all of the commits that go with it.

Conceptually, a rebase is similar to multiple cherry picks. However, in practice, these tools will achieve different results.

It's important to remember that Git rebase](/blog/git-rebase) actually moves the base of the topic branch to the tip of the master branch, hence the name re_base_. In contrast, a cherry pick will copy a commit and apply it to the current HEAD.

In other words, rebase moves a branch's base to the HEAD of another branch; cherry pick copies commits and applies them to the HEAD of another branch.

Is a Cherry Pick a Merge?

A Git merge will take all of the commits from a topic branch, such as a feature, combine them into a single history, and apply this history to another branch, such as the master branch.

Based on everything you have learned so far, it's safe to say that a merge is not the same as a cherry pick.

A cherry pick is great for surgically moving commits from one branch to another. In most cases, merging takes place when a topic branch has reached a level of completion and is ready to be merged with the master branch.

Summary

In this tutorial, we learned what git cherry-pick is, how it's used, and when it is the most appropriate tool for the job.

Cherry pick allows you to copy commits from one branch to another by applying the diff from the chosen commit and its parent to the HEAD of the current branch.

When you use cherry pick, you make small changes to a branch that significantly impact its development, for example, a bug fix or other consequential improvements.

Now that you have all the tools you need to effectively use Git cherry pick, it's time to get out there and put what you have learned into practice.

Next Steps

If you're interested in learning more about how Git works under the hood, check out our Baby Git Guidebook for Developers, which dives into Git's code in an accessible way. We wrote it for curious developers to learn how Git works at the code level. To do this, we documented the first version of Git's code and discuss it in detail.

We hope you enjoyed this post! Feel free to shoot me an email at jacob@initialcommit.io with any questions or comments.

References

  1. Git SCM Docs, git cherry pick - https://git-scm.com/docs/git-cherry-pick

Final Notes

Recommended product: Git Guidebook for Developers