Search code examples
gitgitlabgit-mergegit-bashcherry-pick

Merging/Cherry-Picking a range of Commits from Branch A to Branch B


I have the following git history:

...--A--B--C--D---E--I--M--N--O--P   <-- Branch-A
  \  \       /
   \  F--G--H
    \
     J--K--L   <-- Branch-B (HEAD)

I want to Merge/Cherry-Pick commits (I .. P) to the branch (Branch-B)

I have tried git cherry-pick using following command:

git cherry-pick I..P

But instead of merging from commit I to P. cherry-pick is being performed from I to A (i.e. backwards in the history).

Any Solutions? Solutions other than cherry-pick are also welcome.


Solution

  • Updated - I've been looking at this, and I can't see how the command you've specified would do what you're saying it did. If you start with Branch-B checked out and say

    git cherry-pick I..P
    

    then you should get copies of the commits from M to P added to Branch-B. Since you want to also get I, you should say E..P instead, but the idea of cherry-pick working "backwards" through the history doesn't make sense, or match the docs, or match my tests.

    I've also adjusted my answer a bit. I still prefer to use rebase for ranges of commits, but I originally said it's the "easiest" way, and objectively that's not accurate since it requires extra manipulation of branches.


    The way I would duplicate the changes of a range of commits (so long as that range doesn't include merges) is with git rebase using the --onto option. That might look like this:

    git rebase --onto Branch-B E P
    

    Note that you specify E, not I, as the "upstream" argument. That's because rebase treats this argument as a negative ref - everything reachable from E (including E itself) will not be copied.

    Also note that I specified P as the final argument, rather than branch-A. That's because if you do a rebase with a branch checked out, the branch moves with the rewritten commits, and it doens't sound like you want that. The result is that you're now in detached HEAD state, and the rewritten commits are not currently on any branch.

    ...--A--B--C--D---E--I--M--N--O--P   <-- Branch-A
      \  \       /
       \  F--G--H
        \
         J--K--L   <-- Branch-B 
                \
                 I'--M'--N'--O'--P' <-- (HEAD)
    

    To integrate these commits into Branch-B you could now

    git branch -f Branch-B
    git chekcout Branch-B
    

    or

    git checkout branch
    git merge -
    

    to get

    ...--A--B--C--D---E--I--M--N--O--P   <-- Branch-A
      \  \       /
       \  F--G--H
        \
         J--K--L--I'--M'--N'--O'--P' <-- Branch-B (HEAD)