git cherry-pick | Learn to Cherry Pick Commits in Git
Table of Contents
- What is Git Cherry Pick?
- Syntax to Cherry Pick a Single Commit
- Git Cherry Pick Multiple Commits
- Git Cherry Pick a Range of Commits
- Git Cherry Pick Command Example
- Does Git Cherry Pick Create a New Commit?
- Git Cherry Pick Conflict
- Git Cherry Pick vs. Git Rebase
- Is a Cherry Pick a Merge?
- Next Steps
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>
<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
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 <email@example.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 <firstname.lastname@example.org> 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.
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.
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 email@example.com with any questions or comments.
- Git SCM Docs, git cherry pick - https://git-scm.com/docs/git-cherry-pick
Recommended product: Git Guidebook for Developers