可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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):
回答1:
Git 1.7.2 introduced the ability to cherrypick 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.
Including important comments (credits to respective authors)
Note 1: In the \"cherry-pick A..B\" form, A should be older than B. If they\'re the wrong order the command will silently fail. – damian
Note 2: Also, this will not cherry-pick A, but rather everything after A up to and including B. – J. B. Rainsberger
Note 3: To include A just type git cherry-pick A^..B – sschaef
回答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
回答3:
Or the requested one-liner:
git rebase --onto a b f
回答4:
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 ...
To summarize the commands in text form:
- Open gitk as a independent process using the command:
gitk --all &
.
- Run
git rebase --onto a b f
.
- Press F5 in gitk. Nothing changes. But no
HEAD
is marked.
- Run
git branch selection
- 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.
回答5:
To apply J. B. Rainsberger and sschaef\'s comments to specifically answer the question... To use a cherry-pick range on this example:
git checkout a
git cherry-pick b..f
or
git checkout a
git cherry-pick c^..f
回答6:
git rev-list --reverse b..f | xargs -n 1 git cherry-pick
回答7:
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
回答8:
git format-patch --full-index --binary --stdout range... | git am -3
回答9:
Actually, the simplest way to do it could be to:
- record the merge-base between the two branches:
MERGE_BASE=$(git merge-base branch-a branch-b)
- fast-forward or rebase the older branch onto the newer branch
rebase the resulting branch onto itself, starting at the merge base from step 1, and manually remove commits that are not desired:
git rebase ${SAVED_MERGE_BASE} -i
Alternatively, if there are only a few new commits, skip step 1, and simply use
git rebase HEAD^^^^^^^ -i
in the first step, using enough ^
to move past the merge-base.
You will see something like this in the interactive rebase:
pick 3139276 commit a
pick c1b421d commit b
pick 7204ee5 commit c
pick 6ae9419 commit d
pick 0152077 commit e
pick 2656623 commit f
Then remove lines b (and any others you want)