370 lines
9.0 KiB
Markdown
370 lines
9.0 KiB
Markdown
# Module 05: Cherry-Pick
|
|
|
|
## Learning Objectives
|
|
|
|
By the end of this module, you will:
|
|
- Understand what cherry-picking is and how it works
|
|
- Know when to use cherry-pick vs merge
|
|
- Apply specific commits from one branch to another
|
|
- Understand common use cases for cherry-picking
|
|
- Learn how cherry-pick creates new commits with different hashes
|
|
|
|
## Setup
|
|
|
|
Create the challenge environment:
|
|
|
|
```pwsh
|
|
.\setup.ps1
|
|
```
|
|
|
|
This creates a repository with a `development` branch containing both bug fixes and experimental features.
|
|
|
|
## Overview
|
|
|
|
**Cherry-pick** allows you to copy specific commits from one branch to another. Unlike merging (which brings ALL commits), cherry-pick lets you be surgical about exactly which changes you want to apply.
|
|
|
|
Think of it like picking cherries from a tree - you select only the ripe ones you want, leaving the rest behind.
|
|
|
|
### Why Use Cherry-Pick?
|
|
|
|
- **Selective deployment** - Apply critical bug fixes without merging unfinished features
|
|
- **Hotfixes** - Quickly move a fix from development to production
|
|
- **Backporting** - Apply fixes to older release branches
|
|
- **Wrong branch** - Move commits you accidentally made on the wrong branch
|
|
- **Duplicate commits** - Apply the same fix across multiple branches
|
|
|
|
## Your Task
|
|
|
|
### The Scenario
|
|
|
|
You're working on a project where:
|
|
- The `main` branch is stable and in production
|
|
- The `development` branch has new features being tested
|
|
- Development has critical bug fixes that need to go to production NOW
|
|
- But development also has experimental features that aren't ready yet
|
|
|
|
You need to cherry-pick ONLY the bug fixes to main, leaving the experimental features behind.
|
|
|
|
### Part 1: Explore the Development Branch
|
|
|
|
First, see what commits are on the development branch:
|
|
|
|
```pwsh
|
|
cd challenge
|
|
|
|
# First let's see what files are in the current branch and notice that there is a file security.py
|
|
ls
|
|
|
|
# View all commits on development branch
|
|
git log --oneline --graph
|
|
|
|
# View the full commit graph for all branches
|
|
git log --oneline --graph --all
|
|
```
|
|
|
|
**Study the commits:**
|
|
- Look for commits with "Fix" in the message (these are bug fixes)
|
|
- Look for commits with "experimental" or "beta" (these should stay on development)
|
|
- Note the commit hashes (the 7-character codes like `abc1234`)
|
|
|
|
**Inspect specific commits:**
|
|
```pwsh
|
|
# See what files a commit changed
|
|
git show <commit-hash>
|
|
|
|
# Example:
|
|
# git show abc1234
|
|
```
|
|
|
|
You should see:
|
|
- 2 commits that fix bugs (security and performance)
|
|
- 2 commits that add experimental features
|
|
|
|
### Part 2: Switch to Main Branch
|
|
|
|
Before cherry-picking, you need to be on the target branch (main):
|
|
|
|
```pwsh
|
|
# Switch to main branch
|
|
git switch main
|
|
|
|
# Verify you're on main
|
|
git branch
|
|
|
|
# See what files exist. Notice that we no longer have a security.py file
|
|
ls
|
|
```
|
|
|
|
The `*` should be next to `main`.
|
|
|
|
**Check what's currently on main:**
|
|
```pwsh
|
|
# See main's commits
|
|
git log --oneline
|
|
|
|
```
|
|
|
|
Main should only have the initial app and README - no bug fixes yet, no experimental features.
|
|
|
|
### Part 3: Cherry-Pick the Bug Fixes
|
|
|
|
Now copy the bug fix commits from development to main:
|
|
|
|
1. Find the security fix commit hash by looking at your earlier `git log --oneline --graph --all`
|
|
- Look for a commit message like "Fix security vulnerability in input validation"
|
|
- Note its hash (first 7 characters)
|
|
|
|
2. Cherry-pick the security fix:
|
|
```pwsh
|
|
git cherry-pick <security-fix-hash>
|
|
ls # we now have the security.py file!
|
|
|
|
# Example if the hash is abc1234:
|
|
# git cherry-pick abc1234
|
|
```
|
|
3. Verify it worked: Check that security.py, with `ls` or check your file explorer in VSCode, now exists and check that the commit has been added to the main branch with `git log --oneline --graph --all`
|
|
4. Find the performance fix commit hash
|
|
- Look for "Fix performance issue with data caching"
|
|
- Note its hash
|
|
|
|
5. Cherry-pick the performance fix:
|
|
```pwsh
|
|
git cherry-pick <performance-fix-hash>
|
|
ls # we now have the cache.py file!
|
|
```
|
|
|
|
6. Verify both fixes are now on main:
|
|
```pwsh
|
|
# You should see both security.py and cache.py
|
|
ls
|
|
|
|
# View the graph showing both branches
|
|
git log --oneline --graph --all
|
|
```
|
|
|
|
### Part 4: Verify Your Solution
|
|
|
|
Check that you completed the challenge correctly:
|
|
|
|
```pwsh
|
|
# From inside the module directory
|
|
.\verify.ps1
|
|
```
|
|
|
|
The verification checks:
|
|
- ✅ You're on the main branch
|
|
- ✅ Security fix is applied to main
|
|
- ✅ Performance fix is applied to main
|
|
- ✅ Experimental features are NOT on main
|
|
- ✅ Development branch still has all commits
|
|
|
|
## Understanding Cherry-Pick
|
|
|
|
### What Actually Happens?
|
|
|
|
When you cherry-pick a commit, Git:
|
|
1. Looks at what changed in that specific commit
|
|
2. Applies those same changes to your current branch
|
|
3. Creates a NEW commit with those changes
|
|
|
|
```
|
|
Before cherry-pick:
|
|
|
|
development: A---B---C---D
|
|
/
|
|
main: E---F
|
|
|
|
After: git switch main && git cherry-pick C
|
|
|
|
development: A---B---C---D
|
|
/
|
|
main: E---F---C'
|
|
```
|
|
|
|
Notice:
|
|
- `C'` is a NEW commit (different hash than original `C`)
|
|
- Original `C` still exists on development
|
|
- Main now has the changes from C, but not B or D
|
|
|
|
### Cherry-Pick vs Merge
|
|
|
|
**Merge brings everything:**
|
|
```pwsh
|
|
git switch main
|
|
git merge development
|
|
# Result: A, B, C, and D all come to main
|
|
```
|
|
|
|
**Cherry-pick is selective:**
|
|
```pwsh
|
|
git switch main
|
|
git cherry-pick C
|
|
# Result: Only C comes to main (as C')
|
|
```
|
|
|
|
### Important: New Commits, New Hashes
|
|
|
|
Cherry-picked commits are COPIES, not moves:
|
|
- Original commit stays on source branch
|
|
- New commit created on target branch
|
|
- Different commit hash (because different parent)
|
|
- Same changes, same message, different identity
|
|
|
|
## Key Commands
|
|
|
|
### Viewing Commits
|
|
|
|
```pwsh
|
|
# See commits on another branch
|
|
git log branch-name --oneline
|
|
|
|
# See what a specific commit changed
|
|
git show <commit-hash>
|
|
|
|
# See commit graph
|
|
git log --oneline --graph --all
|
|
|
|
# See only commit message (not changes)
|
|
git log --oneline
|
|
```
|
|
|
|
### Cherry-Picking
|
|
|
|
```pwsh
|
|
# Cherry-pick a single commit
|
|
git cherry-pick <commit-hash>
|
|
|
|
# Cherry-pick multiple commits (in order)
|
|
git cherry-pick <hash1> <hash2> <hash3>
|
|
|
|
# Cherry-pick a range of commits
|
|
git cherry-pick <start-hash>..<end-hash>
|
|
|
|
# Abort a cherry-pick if something goes wrong
|
|
git cherry-pick --abort
|
|
```
|
|
|
|
### After Cherry-Pick
|
|
|
|
```pwsh
|
|
# Verify the commit was added
|
|
git log --oneline
|
|
|
|
# See what files changed
|
|
git show HEAD
|
|
|
|
# Compare branches
|
|
git log main..development --oneline
|
|
```
|
|
|
|
## Common Workflows
|
|
|
|
### Hotfix to Production
|
|
|
|
Critical bug found in production:
|
|
|
|
```pwsh
|
|
# You're on feature-new-ui branch
|
|
# You just committed a critical security fix
|
|
|
|
git log --oneline
|
|
# Note the hash of your fix commit
|
|
|
|
# Switch to production branch
|
|
git switch production
|
|
|
|
# Apply just that fix
|
|
git cherry-pick <fix-commit-hash>
|
|
|
|
# Deploy to production
|
|
# Your fix is live, but new UI stays in development
|
|
```
|
|
|
|
### Backporting to Old Versions
|
|
|
|
```pwsh
|
|
# You fixed a bug on main
|
|
git switch main
|
|
git log --oneline
|
|
# Note the fix commit hash
|
|
|
|
# Apply to older release branch
|
|
git switch release-2.5
|
|
git cherry-pick <fix-commit-hash>
|
|
|
|
# Apply to even older release
|
|
git switch release-2.0
|
|
git cherry-pick <fix-commit-hash>
|
|
|
|
# Same fix now on three branches!
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### "I can't remember the commit hash!"
|
|
|
|
```pwsh
|
|
# See commits on the source branch
|
|
git log development --oneline
|
|
|
|
# Search for specific text in commit messages
|
|
git log development --oneline --grep="security"
|
|
|
|
# See recent commits with more detail
|
|
git log development --oneline -n 10
|
|
```
|
|
|
|
### "I cherry-picked in the wrong order!"
|
|
|
|
Order matters! If commit B depends on commit A, cherry-pick A first:
|
|
|
|
```pwsh
|
|
# Wrong order might cause issues
|
|
git cherry-pick B # Might fail if it needs changes from A
|
|
|
|
# Correct order
|
|
git cherry-pick A
|
|
git cherry-pick B
|
|
```
|
|
|
|
### "How do I see what will change before cherry-picking?"
|
|
|
|
```pwsh
|
|
# See what changes are in a commit
|
|
git show <commit-hash>
|
|
|
|
# Compare your current branch with a commit
|
|
git diff HEAD <commit-hash>
|
|
```
|
|
|
|
## Tips for Success
|
|
|
|
💡 **Copy the commit hashes** - Write them down before switching branches
|
|
💡 **Cherry-pick oldest first** - Apply commits in chronological order
|
|
💡 **Check your branch** - Always verify you're on the target branch first with `git branch`
|
|
💡 **Verify after each pick** - Run `git log --oneline` to confirm it worked
|
|
💡 **Use the graph** - `git log --oneline --graph --all` shows the full picture
|
|
💡 **Original stays put** - Cherry-pick copies, doesn't move commits
|
|
|
|
## What You've Learned
|
|
|
|
After completing this module, you understand:
|
|
|
|
- ✅ Cherry-pick copies specific commits between branches
|
|
- ✅ `git cherry-pick <hash>` applies a commit to current branch
|
|
- ✅ Cherry-picked commits get new hashes but same changes
|
|
- ✅ Use cherry-pick for selective deployment of changes
|
|
- ✅ Cherry-pick is different from merge (selective vs all)
|
|
- ✅ Original commit stays on source branch
|
|
|
|
## Next Steps
|
|
|
|
Ready to continue? Cherry-pick is a powerful tool for selective change management. Next modules will cover more advanced Git operations.
|
|
|
|
To start over:
|
|
```pwsh
|
|
.\reset.ps1
|
|
```
|
|
|
|
**Need help?** Run `git status` to see what Git suggests, or `git log --oneline --graph --all` to see the full picture!
|