How can I selectively merge specific changes from one Git branch to another without merging all commits?
I’m working on a project with three branches:
master: imported codebase with some modifications I’m confident aboutexp1: experimental branch with one architectural approachexp2: experimental branch with a different architectural approach
I need to occasionally move specific changes between exp1 and exp2 without merging all the experimental code. The approaches I’ve considered are:
- Using
git merge --no-commitfollowed by manually unstaging unwanted changes - Manually copying files to a temporary directory, switching branches, then copying back
- Using separate local repositories for each experimental branch
These methods seem tedious and error-prone. Is there a more efficient way to selectively merge specific changes between Git branches, perhaps with a filter path parameter or another Git feature?
Git cherry-pick is the most efficient and professional way to selectively merge specific changes between branches without merging all commits. Unlike the manual methods you’re considering, cherry-pick allows you to apply individual commits from one branch to another, creating new commits that contain only the changes you want.
Contents
- Understanding Git Cherry-Pick
- Basic Cherry-Pick Workflow
- Advanced Cherry-Pick Techniques
- Selective File-Level Operations
- Handling Merge Conflicts
- Alternative Approaches
- Best Practices
Understanding Git Cherry-Pick
Git cherry-pick is a powerful command that enables arbitrary Git commits to be picked by reference and appended to the current working HEAD. Unlike merge operations that bring entire branch histories, cherry-pick is selective: only the targeted commit is copied and applied to the current branch.
As Atlassian Git Tutorial explains, “cherry picking is the act of picking a commit from a branch and applying it to another.” This makes it perfect for your scenario of moving specific architectural changes between exp1 and exp2 branches without importing unrelated experimental code.
The key advantage is that cherry-pick creates new commits in the target branch, maintaining the integrity of the commit history while only incorporating the changes you want.
Basic Cherry-Pick Workflow
Here’s how to cherry-pick specific commits between your experimental branches:
Step 1: Identify the Commit
First, find the commit hash you want to apply:
# View commit history with hashes
git log --oneline exp1
# or
git log --oneline exp2
Step 2: Switch to Target Branch
# Switch to where you want to apply the changes
git checkout exp2
Step 3: Apply the Cherry-Pick
# Apply a specific commit from exp1 to exp2
git cherry-pick <commit-hash>
Step 4: Verify and Commit
# Check the changes
git status
git diff
# If everything looks good, commit
git commit
The DataCamp tutorial emphasizes that this process provides precision, especially in scenarios where you only need to integrate particular changes rather than entire branches.
Advanced Cherry-Pick Techniques
Multiple Commits
You can cherry-pick multiple commits at once:
git cherry-pick <commit1> <commit2> <commit3>
Range of Commits
# Cherry-pick a range of commits
git cherry-pick <start-commit>..<end-commit>
No-Commit Option
The --no-commit option prepares the changes but doesn’t automatically commit them:
git cherry-pick --no-commit <commit-hash>
This gives you the opportunity to review and modify the changes before committing, addressing your concern about error-prone operations.
Author Attribution
Use the -x option to include the original commit author information:
git cherry-pick -x <commit-hash>
As Hatica notes, this is particularly useful when you want to selectively integrate only the necessary changes without merging the entire branch.
Selective File-Level Operations
While cherry-pick works on entire commits, you can achieve file-level selectivity through these approaches:
Method 1: Interactive Cherry-Pick with Path Filtering
# Cherry-pick but only apply changes to specific files
git cherry-pick <commit-hash> -- <path/to/file1> <path/to/file2>
However, this may not work as expected since cherry-pick applies the entire commit’s changes.
Method 2: Three-Way Merge with Path Selection
A more sophisticated approach is to use git merge --no-commit followed by selective staging:
# Switch to target branch
git checkout exp2
# Prepare merge without committing
git merge --no-commit exp1
# Unstage all changes
git reset HEAD
# Stage only specific files you want to keep
git add <path/to/desired/file>
# Commit the selective merge
git commit -m "Selective merge from exp1"
Method 3: Patch-Based Approach
Create and apply patches for specific files:
# Generate a patch for specific files from exp1
git diff exp1..exp1 -- <path/to/file> > feature.patch
# Apply to exp2
git checkout exp2
git apply feature.patch
# Commit the changes
git add <path/to/file>
git commit -m "Applied feature from exp1"
The Stack Overflow discussion provides additional insights into these selective merge techniques.
Handling Merge Conflicts
Cherry-picking can trigger conflicts, just like regular merges. Here’s how to handle them:
Conflict Resolution Workflow
# Cherry-pick may fail with conflicts
git cherry-pick <commit-hash>
# Resolve conflicts manually in affected files
# Edit files marked as "both modified"
# Stage resolved files
git add <resolved-file>
# Continue cherry-pick
git cherry-pick --continue
# Or abort if needed
git cherry-pick --abort
Skip Problematic Commits
If a commit causes issues, you can skip it:
git cherry-pick --skip
As phoenixNAP explains, “picking individual commits facilitates management and integrates changes granularly within a Git repository.”
Alternative Approaches
Interactive Rebase with Selective Picking
For more complex scenarios, consider interactive rebase:
git checkout exp2 git rebase -i exp1
This opens an editor where you can selectively pick, drop, or edit commits.
Git Range Diff
Preview changes before cherry-picking:
git range-diff exp1..exp2 <commit-hash>
Third-Party Tools
Consider specialized tools like:
git cherry-toolsgit subtreegit filter-branch
The Medium guide provides comprehensive coverage of these advanced techniques.
Best Practices
When to Use Cherry-Pick
- Hotfixes and urgent bug fixes
- Selective feature backporting
- Moving specific architectural changes between branches
- Maintaining separate release branches
When to Avoid Cherry-Pick
- Regular development work (use merge or rebase instead)
- Complex branch histories
- When you need to preserve exact commit relationships
Pro Tips
- Always test cherry-picks on a feature branch first
- Use
--no-committo review changes before committing - Document why you’re cherry-picking specific commits
- Consider branch organization to reduce the need for cherry-picking
- Use meaningful commit messages when cherry-picking
Your Specific Scenario
For your exp1 and exp2 branches, I recommend:
# To move a specific architectural change from exp1 to exp2:
git checkout exp2
git cherry-pick --no-commit <exp1-commit-hash>
# Review and potentially modify the changes
git status
git diff
# If only certain files are relevant, reset and stage selectively
git reset HEAD
git add <architectural-file>
git commit -m "Applied architectural change from exp1"
This approach gives you the precision you need while avoiding the tedium of manual file copying and the risks of full merges.
Sources
- Git Cherry-Pick Documentation
- Git Cherry Pick - Atlassian Tutorial
- Git Cherry-Pick Tutorial - DataCamp
- Selective Merging in Git - Stack Overflow
- Git Cherry-Pick Commands - Hatica
- Cherry-Picking from Merge Commits - Medium
- How to Cherry Pick Git Commits - devconnected
- Mastering Git Cherry-Pick - Advanced Guide
- Git Cherry Pick - Git Tower
- Cherry-pick changes with GitLab
Conclusion
Git cherry-pick is the ideal solution for your selective merging needs between exp1 and exp2 branches. By applying individual commits rather than entire branch histories, you can precisely control which architectural changes move between your experimental approaches without the baggage of unrelated code.
The key advantages over your current approaches are:
- Precision: Apply only the commits you need
- Efficiency: No manual file copying or temporary directories
- Safety: Built-in conflict resolution and rollback capabilities
- Maintainability: Clean commit history with proper attribution
For your workflow, start with basic cherry-picking and gradually incorporate the advanced techniques like --no-commit and selective staging as needed. This approach will save you significant time while reducing the risk of errors in your experimental branch management.