Files
git-workshop/01-essentials/05-cherry-pick/README.md

368 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>
# 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>
```
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!