QZ qz thoughts
a blog from Eli the Bearded

Cherry Picking


One thing I have seen time and time again is people using two different branches of code for staging and production and then letting those branches slowly drift further and further apart.

I can fully understand staging should exist for testing stuff before you put it in production, but there should be a steady march of stuff that goes into staging and then maybe a few pieces get backed out, then all of staging syncs to production. Without the regular sync-ups, staging ceases to be an effective place to test things because it's not production + just these small changes but instead it's kinda like production but it has that, this, and some other differences.

But sometimes you have to deal with the hand you're dealt and can't ask for a reshuffle. Which brings us to git cherry-pick.

xkcd 1596

If that doesn't fix it, git.txt contains the phone number of a friend of mine who understands git. Just wait through a few minutes of "It's really pretty simple, just think of branches as..." and eventually you'll learn the commands that will fix everything.

I understand the "graph view" of git quite well. I still find the command line view of git to be a PITA. But it's a truism that people explaining Git get caught up that graph. Here's a page that came up in the first page of search results for git cherry-pick and provides a perfect example.

Once executed our Git history will look like:
    a - b - c - d - f   Master
         \
           e - f - g Feature

Yes, but how do I actually use git cherry-pick?

So with the background that my current most common environment has an "upstream" that represents the real (in-use) repo, a personal fork called "origin" (author dev), and a main (staging) branch of "master" and a production branch of "prod", here's a workable example of using cherry picking.

# If you have the same sort of setup, but haven't yet added prod
# locally, start with:
git checkout --track origin/prod

# Now switch to the prod branch
git checkout prod

# Make this current prod branch match the upstream prod.
# The rebase will discard your local prod history, but presumably
# the upstream prod history is what really matters
git pull --rebase upstream prod

# Now find some commit IDs that are in master but not prod
# and filter those with grep (the grep is optional, but may
# be very helpful). "master" here is a branch you've actually
# commited stuff to, and tested those commits there.
git cherry -v prod master | grep commit-description

# Armed with commits you want to apply, create a branch off
# your current prod to apply those
git branch -c PROD-CHERRYPICK

# Then use "git cherry-pick" to apply the commits to prod.
# If the diffs can be applied cleanly, this will completely
# "commit" the differences. If there are conflicts, you'll
# need to manually edit the files and select which set of
# changes are correct.
git cherry-pick commithash

# Changes applied, you can push that branch of prod to origin
# and make a pull request for origin PROD-CHERRYPICK to
# upstream prod
git push -u origin PROD-CHERRYPICK

Your workflow might not involve branching your origin "prod" for the changes, but it's a little cleaner and allows you to put a meaningful name on the branch. At $WORK, those meaningful names are by convention the Jira ticket names. It's a little awkward because I'll have a branch for PROJECT-NNN, apply that to master, then have to delete that branch and create a new one for my prod changes. The policy exists for the benefit of the computer code tracking my work, though. And poor simple computers are not great at subtly, so that's that.