How to cherry-pick multiple commits

698,997

Solution 1

Git 1.7.2 introduced the ability to cherry pick a range of commits. From the release notes:

git cherry-pick learned to pick a range of commits (e.g. cherry-pick A..B and cherry-pick --stdin), so did git revert; these do not support the nicer sequencing control rebase [-i] has, though.

To cherry-pick all the commits from commit A to commit B (where A is older than B), run:

git cherry-pick A^..B

If you want to ignore A itself, run:

git cherry-pick A..B

(Credit goes to damian, J. B. Rainsberger and sschaef in the comments)

Solution 2

The simplest way to do this is with the onto option to rebase. Suppose that the branch which current finishes at a is called mybranch and this is the branch that you want to move c-f onto.

# checkout mybranch
git checkout mybranch

# reset it to f (currently includes a)
git reset --hard f

# rebase every commit after b and transplant it onto a
git rebase --onto a b

Solution 3

If you have selective revisions to merge, say A, C, F, J from A,B,C,D,E,F,G,H,I,J commits, simply use below command:

git cherry-pick A C F J

Solution 4

Or the requested one-liner:

git rebase --onto a b f

Solution 5

You can use a serial combination of git rebase and git branch to apply a group of commits onto another branch. As already posted by wolfc the first command actually copies the commits. However, the change is not visible until you add a branch name to the top most commit of the group.

Please open the picture in a new tab ...

Workflow

To summarize the commands in text form:

  1. Open gitk as a independent process using the command: gitk --all &.
  2. Run git rebase --onto a b f.
  3. Press F5 in gitk. Nothing changes. But no HEAD is marked.
  4. Run git branch selection
  5. Press F5 in gitk. The new branch with its commits appears.

This should clarify things:

  • Commit a is the new root destination of the group.
  • Commit b is the commit before the first commit of the group (exclusive).
  • Commit f is the last commit of the group (inclusive).

Afterwards, you could use git checkout feature && git reset --hard b to delete the commits c till f from the feature branch.

In addition to this answer, I wrote a blog post which describes the commands in another scenario which should help to generally use it.

Share:
698,997
tig
Author by

tig

Updated on February 08, 2022

Comments

  • tig
    tig over 2 years

    I have two branches. Commit a is the head of one, while the other has b, c, d, e and f on top of a. I want to move c, d, e and f to first branch without commit b. Using cherry pick it is easy: checkout first branch cherry-pick one by one c to f and rebase second branch onto first. But is there any way to cherry-pick all c-f in one command?

    Here is a visual description of the scenario (thanks JJD):

    enter image description here

  • tig
    tig over 14 years
    Thank you! Could you also add git checkout secondbranch && git rebase mybranch for full answer
  • damian
    damian over 13 years
    In the "cherry-pick A..B" form, A should be older than B. If they're the wrong order the command will silently fail.
  • Ruslan Kabalin
    Ruslan Kabalin over 12 years
    Works perfect if there is no conflicts, otherwise "rebase onto" might be easier as you will not have to figure out where it has stopped and re-applying the rest of the patches.
  • Nate Chandler
    Nate Chandler over 11 years
    If only for its brevity, this is the best answer.
  • Oliver
    Oliver about 11 years
    This answer helped me a lot to get my head around which commit is which in this scenario. And: you can use rebase's interactive mode, too. Thanks, @Charles!
  • Michael Merickel
    Michael Merickel over 10 years
    The beauty of this approach is that you can use --interactive to remove some commits from the sequence or reorder them prior to the "cherry pick". +1
  • David Mason
    David Mason about 10 years
    If you have git 1.7.1 or earlier and can't update, you can pretty quickly cherry-pick them in order by running git cherry-pick f~3 then git cherry-pick f~2 etc. up to git cherry-pick f (pressing the up arrow gets the previous command so I can quickly change the number and run it, should be similar in most consoles).
  • Mr_and_Mrs_D
    Mr_and_Mrs_D almost 10 years
    Please add comments explaining what this is doing
  • Mr_and_Mrs_D
    Mr_and_Mrs_D almost 10 years
    Please add comments explaining what this is doing
  • Mr_and_Mrs_D
    Mr_and_Mrs_D almost 10 years
    Upvoted but will leave you in detached HEAD state if f is a commit (as opposed to a branch) - you should edit to add that one should checkout a branch as in answer below
  • Mr_and_Mrs_D
    Mr_and_Mrs_D almost 10 years
    If the mybranch (the a..f commits) is not needed anymore this can be simplified to: git rebase --onto a b mybranch and btw - which program does those nifty git pictures ?
  • JJD
    JJD almost 10 years
    @Mr_and_Mrs_D Thanks for your comment. I think I used cacoo.com to draw the pictures.
  • kuskmen
    kuskmen about 8 years
    I use git 2.7.0.windows.1 and noticed that when I try to cherry pick range of commits everything is ok but git doesn't tell you anywhere that you have to do git cherry-pick --continue | --abort | --quit before you try to commit/cherry-pick again. So if you cherry-pick range of commits you gonna need to run git cherry-pick --continue every time you are ready(resolving conflicts or such) with a commit from the given range.
  • Amitkumar Karnik
    Amitkumar Karnik almost 8 years
    I did exactly same, but fatal: Cannot find 'a..b'
  • Tor Klingberg
    Tor Klingberg almost 8 years
    It may be good to know that this syntax works with branch names too. git cherry-pick master..somebranch will pick all commits on somebranch since master (assuming is already rebased onto master), and apply them to your current branch.
  • coderatchet
    coderatchet over 7 years
    since no one explained... git rev-list prints all revisions from branch b to f (reversed) so that when each line (the commit hash) is passed in order, it will cherry pick each one onto the current git HEAD. i.e. git cherry-pick {hash of c}; git cherry-pick {hash of d}; ...
  • Vibhu Dadhichi
    Vibhu Dadhichi about 7 years
    I am getting conflicts while doing a git cherry-pick A^..B I want to resolve all these conflicts using theirs. I tried git cherry-pick -X theirs A^..B Still getting conflicts Any help ?
  • dieend
    dieend almost 7 years
    You can also do git cherry-pick f~3 f which will take commits from branch f and 3 commits before that (inclusive)
  • Eugen Konkov
    Eugen Konkov over 6 years
    Is there a way to cherry-pick all commits for given file?
  • Neptilo
    Neptilo about 6 years
    On Windows in cmd.exe, ^ is a special character and is silently ignored in A^..B. You have to double it (^^) or put the commit reference in quotes.
  • Muhammad Qasim
    Muhammad Qasim over 5 years
    @VibhuDadhichi Try this: git cherry-pick --strategy=recursive -X theirs A^..B
  • jpmc26
    jpmc26 over 5 years
    Note that A^ is selecting one of A's parent commits. This means you have to be careful if it has multiple parent commits (e.g., it's a merge commit).
  • code_dredd
    code_dredd about 5 years
    Why would this script be needed when you can do that with Git directly?...
  • nickboldt
    nickboldt about 5 years
    Less typing, and my script automatically picks the commits for you, so you don't have to cherry pick each one by its SHA. Anyway, YMMV.
  • tig
    tig about 5 years
    This is already part of answer stackoverflow.com/a/31640427/96823
  • Subtletree
    Subtletree about 5 years
    This answer is actually different and was helpful to me. It specifies the branch name, not the final commit SHA.
  • user18099
    user18099 almost 5 years
    cherry-pick ... -n gives you the most control. It only stages, does not commit. So you can still look at what you are going to do.
  • Samuel
    Samuel almost 5 years
    I don't know where I'm wrong but when I do 'git cherry-pick c^..f' on my side, this includes the commit f but not the commit c. But as I read everywhere, it's supposed to define c and f as inclusive. Or am I wrong?
  • Andy
    Andy almost 5 years
    @Samuel yes, that's correct. The ^ after the c actually means "the commit before c" which is b in this case. This is why c^..f is synonymous to b..f. Try doing git log c^..f and you should see commits c through f, exactly the same as if you did git log b..f
  • Bojan Radivojevic Bomber
    Bojan Radivojevic Bomber over 4 years
    Note 3 should be Note 0 :)
  • Valerio
    Valerio over 4 years
    this is a genious command, a bit tricky to wrap your head around, but it works wonders.
  • Pete
    Pete about 4 years
    "A should be older than B" is not entirely correct. It picks everything from B that is not reachable from A, but A can be a different branch (with newer commits than in B), in which case everything that is in the B branch is picked.
  • asontu
    asontu about 4 years
    Wild that you have to give the commit that you don't want to rebase as one of the argumente (b in this example) but yes this has worked for me.
  • testing
    testing almost 4 years
    This command didn't work for me in the console of GIT Extension (3.4.1.9675). Always picked the first commit and not the range ...
  • Jason S
    Jason S about 3 years
    Why bother with the rest?
  • Ivan Kurmanov
    Ivan Kurmanov about 3 years
    One should note that cherry-picking a bunch of commits is not equivalent to rebasing them. The original poster seems to want the effect of rebasing, if one looks at the diagrams, but rebasing is not safe if you have already published your commits to a team or public repo.
  • TMin
    TMin almost 3 years
    I just ran into an issue where this wasn't working with zsh because ^ is a special character in zsh. Wrapping the range of commits in singe quotes got this to work. git cherry-pick 'A^..B' github.com/ohmyzsh/ohmyzsh/issues/4398 The error I was seeing was "zsh: no matches found: A^..B"
  • Gabriel Staples
    Gabriel Staples over 2 years
  • Przemek Nowicki
    Przemek Nowicki over 2 years
    That's strange but when I used double dots between the commits I got empty commits. Adding the third dot resolved the issue. git cherry-pick A^...B. I was cherry-picking from the different origin. In other words I had to cherry-pick commits from other repository. Maybe this was the reason, no idea.
  • Dentrax
    Dentrax over 2 years
    I got "fatal: bad revision" error
  • osacognitive
    osacognitive over 2 years
    @Dentrax I get the same error, did you manage to find a reason for it?
  • osacognitive
    osacognitive over 2 years
    Nvm, it turns out I was using a - instead of ...
  • Vinay Sharma
    Vinay Sharma over 2 years
    This should've been accepted as an answer.
  • Gabriel Staples
    Gabriel Staples about 2 years
    @VinaySharma, true! But, my answer was 12 years late to the party after-all! :)
  • Janusz 'Ivellios' Kamieński
    Janusz 'Ivellios' Kamieński almost 2 years
    Regarding: commit~3 # my preferred syntax Perhaps it would be better to call it "revision" for consistency with git naming.