NeuroAgent

Git Cherry-Pick: Selective Branch Merging Guide

Learn how to use Git cherry-pick to selectively merge specific changes between branches without importing unrelated code. Master precise branch management with this comprehensive guide.

Question

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 about
  • exp1: experimental branch with one architectural approach
  • exp2: 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:

  1. Using git merge --no-commit followed by manually unstaging unwanted changes
  2. Manually copying files to a temporary directory, switching branches, then copying back
  3. 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?

NeuroAgent

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

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:

bash
# View commit history with hashes
git log --oneline exp1
# or
git log --oneline exp2

Step 2: Switch to Target Branch

bash
# Switch to where you want to apply the changes
git checkout exp2

Step 3: Apply the Cherry-Pick

bash
# Apply a specific commit from exp1 to exp2
git cherry-pick <commit-hash>

Step 4: Verify and Commit

bash
# 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:

bash
git cherry-pick <commit1> <commit2> <commit3>

Range of Commits

bash
# 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:

bash
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:

bash
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

bash
# 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:

bash
# 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:

bash
# 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

bash
# 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:

bash
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:

bash
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:

bash
git range-diff exp1..exp2 <commit-hash>

Third-Party Tools

Consider specialized tools like:

  • git cherry-tools
  • git subtree
  • git 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

  1. Always test cherry-picks on a feature branch first
  2. Use --no-commit to review changes before committing
  3. Document why you’re cherry-picking specific commits
  4. Consider branch organization to reduce the need for cherry-picking
  5. Use meaningful commit messages when cherry-picking

Your Specific Scenario

For your exp1 and exp2 branches, I recommend:

bash
# 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

  1. Git Cherry-Pick Documentation
  2. Git Cherry Pick - Atlassian Tutorial
  3. Git Cherry-Pick Tutorial - DataCamp
  4. Selective Merging in Git - Stack Overflow
  5. Git Cherry-Pick Commands - Hatica
  6. Cherry-Picking from Merge Commits - Medium
  7. How to Cherry Pick Git Commits - devconnected
  8. Mastering Git Cherry-Pick - Advanced Guide
  9. Git Cherry Pick - Git Tower
  10. 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.