As a full-stack developer, Git is one of my most used tools for managing code changes in professional software projects. While Git‘s flexible branching model makes developing features and fixing bugs in isolation easy, often I just need to bring over a single commit from one branch over to another. Git provides the powerful but often misunderstood tool for this – cherry-picking commits.

The Prevalence of Git in Modern Software Development

According to Stack Overflow‘s 2021 survey of software developers, Git remains by far the most commonly used version control system at 89.1% of respondents. This dwarfs second-place SVN at 13.6% usage amongst developers. Clearly, proficiency in Git is a mandatory skill for any aspiring or experienced software engineer today.

Within Git, 49.2% of developers utilize branching strategies for managing code, above centralized workflows at 39.6%. The need for jewels like cherry-picking arises from branching‘s popularity.

Commit SHA-1 Hashes – Fingerprints for Git History

To understand cherry-picking, we must first explain a core concept in Git – the commit hash. In Git, each commit is designated a unique 40-character string known as a SHA-1 hash that identifies it in the project history.

For example:

e116d26add9b154012b570b7a02ad13fa3f1a6b7

These SHA-1 hashes are generated based on the contents of the commit itself, meaning the hash will change if the commit message or contents change in any way. They act as a fingerprint that unambiguously references that specific commit.

Git Commits Form a Directed Acyclic Graph

Rather than a linear history, Git commits form a directed acyclic graph (DAG) structure. Commits can have one or more parent commits that they build on top of. This allows for branching – a core differentiator from older systems like SVN.

Git commit graph visualization

In this graph visualization, we can observe branches merging via commits having two parents. Our commits can thus trace their history by following the graph along the parent links.

Cherry Picking vs. Merging

Git‘s standard way of combining branch history is through git merge. This will bring together the entire commit sequence from the merged branchtip commit backwards. But occasionally, you may want only a single commit or small range from a branch rather than include unrelated or disruptive changes that branch contains.

This is where cherry-picking comes in – it allows grafting over just the specific commits you want. For example, say you had an active feature branch, but needed a critical bug fix from master. By cherry-picking just the bug-fix commit, you avoid disrupting your unfinished feature code.

Cherry-picking works by using the parent link structure of commits. It applies the diff patch from the pick source commit you specify to the working state of files in your current HEAD commit. Once any conflicts are resolved, it commits the changes, linking the new commit back to your current HEAD.

Cherry Picking Preserves Current Branch Structure

An important distinction versus merging is that cherry-picking will not move over other references or pointers like the upstream tracking branch. So unlike with git merge, your existing place on the branch is maintained with only the specific commits getting copied.

When to Use Cherry Picking

Based on my professional experience coordinating with Git teams, I recommend treating cherry-picking as a precision tool used sparingly rather than a catch-all process. Some cases where cherry-picking shines:

  • Bringing bugfix commits into feature branches
  • Applying commits previously reverted by mistake
  • Porting commits following a feature branch modelworkflow
  • Prototyping changes before formalizing feature branches

Common reasons I advise caution with excessive cherry-picking:

  • Bypassing code review processes for new feature work
  • Obscuring commit history and intention
  • Risk of compounding merge conflicts

Cherry pick works best when scoped to clearly defined problem-solving use cases rather than wholesale development workflows.

Step-By-Step Guide to Cherry Picking

Now that we have explored when and why to perform a cherry pick, let us walk through the process with examples. We will use a repository with an existing commit we want to bring into our active feature branch.

1. Identify the Commit SHA-1 Hash

Using git log, we can explore the relevant commit history of the code:

$ git log --oneline

e116d26 Bug fix - resolve memory leak in batch processing 
a3915cd Refactor user API to use repository pattern  
9b3d267 Add user registration API feature  

Let‘s say we want to bring in the memory leak bug fix commit while continuing work on an unfinished user registration API feature. We copy the hash e116d26.

2. Checkout Your Active Branch

We now checkout out our target feature branch user-registration-api:

$ git checkout user-registration-api
Switched to branch ‘user-registration-api‘

3. Use git cherry-pick with Commit Hash

We invoke git cherry-pick using the commit hash, applying it onto our feature branch:

$ git cherry-pick e116d26
[user-registration-api 74839aa] Bug fix - resolve memory leak in batch processing
 Date: 9 days ago
 1 file changed, 1 insertion(+)

The changes from commit e116d26 are now patched into our current working branch code.

Handling Merge Conflicts

Depending on the interplay between the cherry-picked commit and current branch, conflicts can occur. Git will mark conflicting files for manual resolution.

Once fixed and tested, stage changes via:

git add <resolved-files> 

Then commit to finalize the cherry pick:

git commit

Comparing Techniques – Cherry-pick vs. Revert vs. Rebase

Beyond merging and cherry-picking, Git offers other techniques for porting commits between branches. Let‘s contrast them:

git revert – Creates a new "inverse" commit that neutralizes an older commit. History remains intact other than the added revert commit.

git rebase – Rewrites branch history by "replaying" it from a specified point. Very powerful but rewrites history.

git cherry-pick – Cleanly inserts a commit while preserving surrounding history. However, duplicate commits can obscure intent over time without diligence.

Deciding between approaches depends greatly on the context of continue development, team workflows, and maintaining comprehensible history. As a full-stack developer, I consider cherry-picking an important tool best used judiciously as needed.

Cherry Picking Ranges and Folds

The examples so far showed cherry-pick on a single commit, But Git supports picking an entire range using the double-dot notation:

git cherry-pick firstCommit..lastCommit 

We can also "squash" or "fold" picked commits into a single commit using -n/--no-commit:

git cherry-pick -n e116d26 a3915cd  
# Resolve conflicts
git commit 

For rapid cherry-picks, I suggest setting up an alias:

git config --global alias.cp ‘cherry-pick‘

git cp e5543

Saving those keystrokes adds up long term!

Expert Tips for Cherry Picking

Drawing from my professional experience coordinating Git workflows, here are proven tips around cherry picks:

  • Comment commit messages – Add context like "Cherry-picked from commit " to retain metadata on origin
  • Limit range picking – Resist large multi-commit ranges to avoid unexpected issues
  • Fix conflicts early – Don‘t stack cherry-picks without verifying builds
  • Review again if changes are substantial – Special case for avoiding assumed approved status
  • Watch default branch clashes – Hotfixes may reflect temporary quick merges that overwrite

Cherry pick works best when used sparingly but effectively. Follow these tips to improve results.

Wrapping Up

While other commit portability tools like revert and rebase have their place, cherry-picking enables precise, granular commit management across Git branches. It comes with complexity, as commit SHA-1 hashes, merge conflicts, and Git DAG history graphs are advanced concepts.

But when utilized properly according to sound engineering practices, cherry-picking unlocks workflows otherwise encumbered by heavyweight branching and merging. Hopefully this guide has shed light on this powerful ability of Git for productivity and collaboration.

Similar Posts