Introduction
Git's cherry-pick feature allows you to apply specific commits from one branch to another. While powerful, sometimes you might need to reverse a cherry-pick operation due to errors or conflicts. In this lab, you'll learn how to perform a cherry-pick and then use various methods to undo it when necessary. By the end, you'll have practical experience with cherry-pick operations and the skills to recover from common issues.
Setting Up a Test Repository
In this step, we'll create a test Git repository to practice cherry-pick operations. This will provide a safe environment to experiment with various Git commands.
Creating a New Git Repository
Let's start by creating a new directory for our test repository and initializing it as a Git repository:
mkdir -p ~/project/cherry-pick-lab
cd ~/project/cherry-pick-lab
git init
You should see output similar to:
Initialized empty Git repository in /home/labex/project/cherry-pick-lab/.git/
Setting Up Git User Configuration
Before we can make commits, we need to set up a user name and email for Git:
git config --local user.name "LabEx User"
git config --local user.email "labex@example.com"
Creating Initial Commits on the Main Branch
Let's create some initial commits on the main branch:
## Create and commit the first file
echo "## Cherry Pick Lab" > README.md
git add README.md
git commit -m "Initial commit with README"
## Create and commit a second file
echo "console.log('Hello, world!');" > app.js
git add app.js
git commit -m "Add main application file"
Viewing the Commit History
Let's check our commit history to make sure everything is set up correctly:
git log --oneline
You should see output similar to:
abcd123 (HEAD -> main) Add main application file
efgh456 Initial commit with README
The actual commit hashes will be different on your system. Take note of the commit hash for "Add main application file" as we'll use it later.
Creating a Feature Branch
Now, let's create a feature branch where we'll make some additional changes:
git checkout -b feature-branch
You should see output similar to:
Switched to a new branch 'feature-branch'
Now let's add some commits to this feature branch:
## Create and commit a new feature file
echo "function newFeature() { return 'awesome'; }" > feature.js
git add feature.js
git commit -m "Add new feature function"
## Modify the README file
echo -e "## Cherry Pick Lab\n\nThis repo demonstrates git cherry-pick operations." > README.md
git add README.md
git commit -m "Update README with project description"
Now we have a main branch with two commits and a feature branch with two additional commits. In the next step, we'll use cherry-pick to apply one of the feature branch commits to the main branch.
Performing a Cherry-pick Operation
In this step, we'll learn how to use the cherry-pick command to apply a specific commit from one branch to another. This is useful when you want to selectively incorporate changes from one branch to another.
Understanding Cherry-pick
Cherry-picking in Git allows you to pick a specific commit from one branch and apply it to another branch. Unlike merging or rebasing which typically apply multiple commits, cherry-picking applies just one commit at a time.
Switching Back to the Main Branch
First, let's switch back to the main branch where we want to apply a commit from the feature branch:
git checkout main
You should see output confirming the switch:
Switched to branch 'main'
Viewing the Feature Branch Commits
Before cherry-picking, let's examine the commits in the feature branch that we might want to apply to main:
git log feature-branch --oneline
This will show all commits in the feature branch, including those shared with the main branch. You'll see output similar to:
1234abc Update README with project description
5678def Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README
Take note of the commit hash for "Add new feature function" (in this example, it's 5678def). We'll use this hash in the next step.
Cherry-picking a Commit
Now let's cherry-pick the "Add new feature function" commit from the feature branch into our main branch:
git cherry-pick [COMMIT_HASH]
Replace [COMMIT_HASH] with the actual hash you noted earlier. For example:
git cherry-pick 5678def
If the cherry-pick is successful, you'll see output similar to:
[main 98765ab] Add new feature function
1 file changed, 1 insertion(+)
create mode 100644 feature.js
Verifying the Cherry-pick
Let's confirm that the cherry-pick worked as expected:
git log --oneline
You should now see the cherry-picked commit in your main branch's history:
98765ab (HEAD -> main) Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README
You can also verify that the file exists:
ls -la
You should see feature.js listed in the output:
total 16
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 .
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 ..
drwxr-xr-x 8 labex labex 4096 Jan 1 00:00 .git
-rw-r--r-- 1 labex labex 29 Jan 1 00:00 app.js
-rw-r--r-- 1 labex labex 42 Jan 1 00:00 feature.js
-rw-r--r-- 1 labex labex 16 Jan 1 00:00 README.md
The cherry-pick operation has successfully applied the commit from the feature branch to the main branch. In the next step, we'll learn how to undo this cherry-pick if needed.
Undoing a Cherry-pick with Git Reset
Now that we've successfully cherry-picked a commit, let's learn how to undo this operation. In this step, we'll use the git reset command, which is the most straightforward way to undo a recent cherry-pick.
Understanding Git Reset
The git reset command moves the current branch pointer to a specified commit, effectively "undoing" any commits that came after that point. There are three main modes of git reset:
--soft: Moves the branch pointer but leaves changes staged--mixed(default): Moves the branch pointer and unstages changes--hard: Moves the branch pointer and discards all changes
For undoing a cherry-pick, we'll use the --hard option to completely remove the cherry-picked commit and its changes.
Checking the Current Status
First, let's check our current status to confirm we're on the main branch with the cherry-picked commit:
git log --oneline -n 3
You should see output similar to:
98765ab (HEAD -> main) Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README
Undoing the Cherry-pick with Git Reset
To undo the cherry-pick operation, we'll use git reset with the --hard option to move the branch pointer back one commit:
git reset --hard HEAD~1
This command tells Git to reset the branch to the commit before the current HEAD (the ~1 part means "one commit before").
You should see output similar to:
HEAD is now at abcd123 Add main application file
Verifying the Reset
Let's verify that the cherry-pick has been undone:
git log --oneline
You should see that the cherry-picked commit is no longer in the history:
abcd123 (HEAD -> main) Add main application file
efgh456 Initial commit with README
Let's also check if the feature.js file has been removed:
ls -la
The output should not include feature.js:
total 12
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 .
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 ..
drwxr-xr-x 8 labex labex 4096 Jan 1 00:00 .git
-rw-r--r-- 1 labex labex 29 Jan 1 00:00 app.js
-rw-r--r-- 1 labex labex 16 Jan 1 00:00 README.md
Congratulations! You've successfully undone a cherry-pick operation using git reset. This method is clean and simple, but it rewrites history, so it should only be used for local changes that haven't been pushed to a shared repository.
Undoing a Cherry-pick with Git Revert
In the previous step, we used git reset to undo a cherry-pick. However, git reset rewrites history, which can be problematic if you've already pushed your changes to a shared repository. In this step, we'll learn how to use git revert to safely undo a cherry-pick without rewriting history.
Understanding Git Revert
The git revert command creates a new commit that undoes the changes introduced by a previous commit. Unlike git reset, which removes commits from history, git revert adds a new commit that counteracts the changes, preserving the commit history.
Performing a Cherry-pick Again
First, let's cherry-pick the commit again so we have something to revert:
## Get the commit hash from the feature branch
FEATURE_HASH=$(git log feature-branch --oneline | grep "new feature" | cut -d ' ' -f 1)
## Cherry-pick the commit
git cherry-pick $FEATURE_HASH
You should see output similar to:
[main 98765ab] Add new feature function
1 file changed, 1 insertion(+)
create mode 100644 feature.js
Checking the Current Status
Let's confirm that the cherry-pick was successful:
git log --oneline -n 3
ls -la
You should see the cherry-picked commit in the history and the feature.js file in the directory listing.
Reverting the Cherry-pick
Now, let's use git revert to undo the cherry-pick while preserving history:
git revert HEAD --no-edit
The --no-edit flag tells Git to use the default commit message without opening an editor.
You should see output similar to:
[main abc9876] Revert "Add new feature function"
1 file changed, 1 deletion(-)
delete mode 100644 feature.js
Verifying the Revert
Let's check the commit history:
git log --oneline -n 4
You should see both the cherry-picked commit and the revert commit:
abc9876 (HEAD -> main) Revert "Add new feature function"
98765ab Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README
Now, let's check if the feature.js file has been removed:
ls -la
The output should not include feature.js:
total 12
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 .
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 ..
drwxr-xr-x 8 labex labex 4096 Jan 1 00:00 .git
-rw-r--r-- 1 labex labex 29 Jan 1 00:00 app.js
-rw-r--r-- 1 labex labex 16 Jan 1 00:00 README.md
Although both git reset and git revert achieve the same end result (removing the changes introduced by the cherry-pick), they do so in different ways:
git resetremoves the commit from history, which can cause problems if the commit has been shared with others.git revertadds a new commit that undoes the changes, preserving the commit history, which is safer for shared repositories.
Choosing between these methods depends on your specific situation:
- Use
git resetfor local changes that haven't been shared - Use
git revertfor changes that have been pushed to a shared repository
Handling Cherry-pick Conflicts
Sometimes when you cherry-pick a commit, Git might encounter conflicts if the changes in the commit conflict with changes in your current branch. In this step, we'll learn how to handle cherry-pick conflicts and how to abort a cherry-pick operation.
Creating a Scenario with Potential Conflicts
First, let's create a scenario that will result in a cherry-pick conflict:
## Switch to main branch and modify README.md
git checkout main
echo -e "## Cherry Pick Lab\n\nThis is the main branch README." > README.md
git commit -am "Update README in main branch"
## Switch to feature branch and make a conflicting change to README.md
git checkout feature-branch
echo -e "## Cherry Pick Lab\n\nThis README has been updated in the feature branch." > README.md
git commit -am "Update README in feature branch"
Attempting a Cherry-pick with Conflicts
Now, let's switch back to the main branch and try to cherry-pick the commit from the feature branch:
git checkout main
CONFLICT_HASH=$(git log feature-branch --oneline | grep "Update README in feature" | cut -d ' ' -f 1)
git cherry-pick $CONFLICT_HASH
Since both branches modified the same lines in README.md, you should see a conflict:
error: could not apply a1b2c3d... Update README in feature branch
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'
Viewing the Conflict
Let's examine the conflict:
git status
You should see output indicating a conflict in README.md:
On branch main
You are currently cherry-picking commit a1b2c3d.
(fix conflicts and run "git cherry-pick --continue")
(use "git cherry-pick --abort" to cancel the cherry-pick operation)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
Let's look at the content of the conflicted file:
cat README.md
You should see something like:
## Cherry Pick Lab
<<<<<<< HEAD
This is the main branch README.
=======
This README has been updated in the feature branch.
>>>>>>> a1b2c3d... Update README in feature branch
Resolving the Conflict
To resolve the conflict, we need to edit the file and decide which changes to keep. Let's modify README.md to include both changes:
echo -e "## Cherry Pick Lab\n\nThis is the main branch README.\n\nThis README has also been updated with content from the feature branch." > README.md
Now, let's mark the conflict as resolved and continue the cherry-pick:
git add README.md
git cherry-pick --continue
Git will open an editor with a default commit message. Save and close the editor to complete the cherry-pick.
Aborting a Cherry-pick
Sometimes, you might decide you don't want to resolve the conflicts and would prefer to cancel the cherry-pick operation. Let's create another conflict and then abort the cherry-pick:
## Create another conflicting commit in feature branch
git checkout feature-branch
echo "// This will conflict with app.js in main" > app.js
git commit -am "Modify app.js in feature branch"
## Try to cherry-pick this commit to main
git checkout main
ANOTHER_CONFLICT=$(git log feature-branch --oneline | grep "Modify app.js" | cut -d ' ' -f 1)
git cherry-pick $ANOTHER_CONFLICT
You should see another conflict. This time, let's abort the cherry-pick:
git cherry-pick --abort
You should see that the cherry-pick operation has been cancelled, and your working directory has been restored to its previous state:
git status
Output:
On branch main
nothing to commit, working tree clean
Handling conflicts during cherry-pick operations is an essential skill for Git users. You have three options when you encounter a conflict:
- Resolve the conflict manually, then use
git addandgit cherry-pick --continue - Skip the conflicting commit with
git cherry-pick --skip - Abort the entire cherry-pick operation with
git cherry-pick --abort
The best approach depends on the specific situation and your project requirements.
Summary
In this lab, you've gained practical experience with Git's cherry-pick feature and learned multiple ways to undo cherry-pick operations:
- You created a test repository with multiple branches and commits to practice with
- You performed a cherry-pick operation to apply a specific commit from one branch to another
- You learned how to undo a cherry-pick using
git reset, which is suitable for local changes - You explored how to safely undo a cherry-pick using
git revert, which preserves history - You practiced handling cherry-pick conflicts and learned how to abort a cherry-pick operation
These skills are invaluable when working with Git in real-world projects. Cherry-picking allows you to selectively apply changes across branches, while knowing how to undo cherry-picks helps you recover from mistakes and maintain a clean Git history.
Remember that different undoing methods serve different purposes:
- Use
git resetfor local changes that haven't been shared - Use
git revertfor changes that have been pushed to a shared repository - Use
git cherry-pick --abortto cancel an in-progress cherry-pick operation
By understanding these options, you can choose the most appropriate method for your specific situation.



