Is there a way to run `git cherry-pick` and specify the series of commits specific to a given branch?

Viewed 103

For example:

feature        C---D---E---G---H---L---M
              /         \       \      ^--- tip of feature
master   A---B-----------F---I---J---K
                                     ^--- tip of master

The commits I want to cherry-pick are: C D E G H L M

The key requirement: I don't want to specify any commit IDs manually --- I want a reliable way to specify them in terms of "commits I made to feature since it diverged from master". I don't want what's been put into master since feature diverged from it so I don't want F I J K.

The reason: I'd like to be able to cherry-pick those commits into a third branch, but I cannot just run git merge feature as it would also include additional ancestors such as A and B. (I do not want to get into the reasons why there's stuff in master I don't want in the third branch.)

Does this make sense?

2 Answers

You can get list of commits you want to pick by listing the first parents of feature, and remove the first parents of master ;
you can use the script provided in this answer :

git rev-list --first-parent master > listm.txt
git rev-list --first-parent feature > listb.txt

# use grep, use '-f' to read patterns from 'listm.txt',
# use '-v' to say "exclude these patterns"
cat listf.txt | grep -v -f listm.txt

In bash like shell, you can use <(...) to turn it into a one liner :

git rev-list --first-parent feature | grep -v -f <(git rev-list --first-parent master)

You can then feed that list to cherry-pick :

list=$(git rev-list ...)
git cherry-pick $list

TL;DR

You can do it easily by rebasing the specific part of the graph that interest you to a new branch onto the feature2 branch. The only tricky part is to identify the 1st commit to re-play (see bellow).


To make the reading easier, let's call your feature branch 'feature1' let's say the branch you want your cherry-picked to go into is called 'feature2'

for now let's create a working branch from the feature1 branch (will will use this in few seconds). let's call it 'feature2-with-feature1-commits'

  1. git checkout feature1
  2. git checkout -b feature2-with-feature1-commits

now we can find the hash the feature1 was created from (the original master commit) by finding the previous commit of the 1st shared commit between feature1 and master :
git show $(git rev-list f1..master | tail -1)~1 --pretty=%h
but we don't need to save it as we can now use rebase --onto command

so let's execute the third step that will contain the previous command to give to git the original commit to replay the commit from:

  1. git rebase --onto feature2 `git show $(git rev-list feature1..master | tail -1)~1 --pretty=%h` feature2-with-feature1-commits

You have now all the commits we wanted from feature1 cherry-picked into the new branch (going out from feature2 latest commit) without master commits and you can now integrate them into the feature2 branch by merging them (git checkout feature2; git merge --no-ff -;) or by fast forwarding the feature2 branch (git checkout feature2; git merge --ff-only -;)

Related