a
,而另一个分支在 a
之上有 b
、c
、d
、e
和 f
。我想将 c
、d
、e
和 f
移动到第一个分支,而不包括提交 b
。使用 cherry-pick 很容易实现:切换到第一个分支,逐个 cherry-pick c
到 f
,然后将第二个分支变基到第一个分支上。但是否有一种方法可以用一条命令来 cherry-pick 所有的 c
-f
?以下是该场景的可视化描述(感谢 JJD):
a
,而另一个分支在 a
之上有 b
、c
、d
、e
和 f
。我想将 c
、d
、e
和 f
移动到第一个分支,而不包括提交 b
。使用 cherry-pick 很容易实现:切换到第一个分支,逐个 cherry-pick c
到 f
,然后将第二个分支变基到第一个分支上。但是否有一种方法可以用一条命令来 cherry-pick 所有的 c
-f
?Git 1.7.2引入了选择一系列提交(commit)的能力。从发行说明中可以看到:
git cherry-pick
学习了如何挑选一系列的提交(例如cherry-pick A..B
和cherry-pick --stdin
),而git revert
也是这样;不过,它们没有像rebase [-i]
那样良好的序列控制。
要挑选所有从提交A
到提交B
之间的提交(其中A
比B
更旧),请运行:
git cherry-pick A^..B
如果你想要忽略 A 自身,运行以下命令:
git cherry-pick A..B
评论中的注意事项:
A
应该比 B
更早,或者 A
应该来自另一个分支。A^^..B
,因为插入符号需要转义,或者应该使用双引号包裹 "A^..B"
。zsh
shell 中,应该使用单引号包裹 'A^..B'
,因为插入符号是一个特殊字符。(感谢评论区的 damian、J. B. Rainsberger、sschaef、Neptilo、Pete 和 TMin。)
git cherry-pick master..somebranch
会挑选自主分支以来某分支上的所有提交,并将它们应用到当前分支上。注意不要改变原意。 - Tor Klingberg^
是一个特殊字符,在A^..B
中会被静默地忽略。你需要将其加倍(^^
)或将提交引用放在引号中。 - NeptiloA^
会选择A的父提交记录之一。这意味着如果A有多个父提交记录(例如合并提交),您需要小心处理。 - jpmc26如果您需要合并选择性的修订版本,例如从A、B、C、D、E、F、G、H、I和J的提交中选择A、C、F、J,则只需使用以下命令:
git cherry-pick A C F J
最简单的方法是使用rebase
命令的onto
选项。假设当前分支结束于a
,该分支称为mybranch,您想将c-f移动到该分支。
# 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
git checkout secondbranch && git rebase mybranch
添加到完整答案中? - tigrebase
的交互模式。谢谢,@Charles! - Oliver--interactive
从序列中删除一些提交或在“cherry pick”之前对它们进行重新排序。+1 - Michael Merickel--committer-date-is-author-date
一起使用,以保留原始提交时间戳(与--interactive
不兼容)。 - joH1...到您当前检出的分支上:
commit
的单个分支或提交git cherry-pick commit
例子:
git cherry-pick my_branch # by branch name
git cherry-pick 1e038f108a130831f108329b1083a8139813fabc # by full hash
git cherry-pick 1e038f10 # by partial hash
请注意,您可以一次挑选任意数量的提交哈希,并且可以按照任何顺序进行。它们将逐个应用,并按照您指定的顺序进行。如果出现冲突,您需要逐个解决它们,然后使用git add my_file
命令,完成后使用git cherry-pick --continue
命令继续挑选过程。
git cherry-pick commit1 commit2 commit3 commit4 commit5
# A. INCLUDING the beginning_commit
git cherry-pick beginning_commit~..ending_commit
# OR (same as above)
git cherry-pick beginning_commit~1..ending_commit
# OR (same as above)
git cherry-pick beginning_commit^..ending_commit
# B. NOT including the beginning_commit
git cherry-pick beginning_commit..ending_commit
commit~~
commit~2 # my preferred syntax
commit^^
commit~~~
commit~3 # my preferred syntax
commit^^^
commit^3 # INVALID syntax
git log
命令。例如:git log commit
git log commit~
git log commit~1
git log commit^
git log commit~~
git log commit~5
# etc.
peer_branch
从您的分支my_branch
的早期版本分叉出来时。
# you cherry-pick all of their extra commits from their `peer_branch` onto
# your `my_branch` (note: the 3 dots below are very important!)
git fetch origin peer_branch # get their latest changes from the remote
git checkout my_branch # ensure you're on your branch
# cherry-pick their range of commits
git cherry-pick my_branch...origin/peer_branch
git log # review the commits you just chery-picked
git push # push your changes to the remote
假设你正在处理你的特性分支my_branch
,而你的同事想要帮助你进行一些修改以支持你的特性。你已经将my_branch
推送到名为origin
的远程仓库。所以,他们将会从远程仓库中获取你的名为my_branch
的分支到他们的本地计算机上,然后从这个分支中创建一个名为peer_branch
的自己的分支,并将其推送到自己的分支peer_branch
上。一旦他们完成这个操作,你将一次性挑选出他们所有的修改内容。这是整个过程的第一部分:
# **your peer** does this
# peer fetches your branch named `my_branch` and forks their `peer_branch`
# off of it
# they fetch your latest work from remote `my_branch` into their locally-stored
# remote-tracking "hidden" branch named `origin/my_branch`
# (note: you can see all locally-stored remote-tracking "hidden" branches
# with `git branch -r`)
git fetch origin my_branch
# create `peer_branch` as a fork off of `origin/my_branch`, and check it out
git checkout -b peer_branch origin/my_branch
# Now they can add their changes and commits and `git push` to remote `origin`
# as their own `peer_branch` when done.
origin
,作为他们自己的分支peer_branch
。你可以像这样挑选出他们在你的工作之上添加的所有提交:# **you** do this to cherry-pick your peer's helpful changes they added to
# your work
# you fetch their latest work from their branch named `peer_branch` on remote
# `origin` into your locally-stored remote-tracking "hidden" branch named
# `origin/peer_branch`
# (note: you can see all locally-stored remote-tracking "hidden" branches
# with `git branch -r`)
git fetch origin peer_branch
# ensure you are on `my_branch` (if you aren't already)
git checkout my_branch
# you cherry-pick all of their extra commits from their `peer_branch` onto
# your `my_branch` (note: the 3 dots here are very important!)
git cherry-pick my_branch...origin/peer_branch
git log # review the commits you just chery-picked
git push # push your changes to the remote
cherry-pick
命令,与下面这个更长的命令是完全等效的:git cherry-pick $(git merge-base my_branch origin/peer_branch)..origin/peer_branch
git merge-base my_branch origin/peer_branch
部分找到分支my_branch
和分支origin/peer_branch
之间的共同父提交哈希。这是它们在你的my_branch
上从其peer_branch
分叉的提交。然后,当然,您要挑选从该点到(..
)他们在origin/peer_branch
的最终提交的一段提交。
要了解更多关于3个点语法的内容,请参阅此处:Git diff commit范围中双点".. "和三点"..."之间的区别?[重复]。有关git checkout -b new_branch from_branch
的帮助,请参阅我的答案:使用其他分支在git中创建分支的各种方法
...
)与两个点范围语法,^commit
("非" commit
),commit^
(commit 的父节点),等等。commit~3 # 我偏爱的语法
也许更好的做法是为了与 Git 命名保持一致,将其称为“修订”。 - Janusz 'Ivellios' Kamieńskicommit~3 # my preferred syntax
。这是我能记住的少数几件事情之一,HEAD~1
比 HEAD
提交早一次。在相同的概念下,我认为 git cherry-pick beginning_commit~1..ending_commit
是最好的语法。由于我很少使用 cherry-pick
,所以有额外的明确性非常有用,这样当我在我的 bash 历史记录中搜索它时,我不必再去搜索互联网来确定 ^
的确切含义。 - icc97或者可以使用请求的单行代码:
git rebase --onto a b f
git branch tmp
(保存你的分离的HEAD状态)+ git checkout destination-branch
(切换到目标分支,可能是develop)+ git merge tmp
(将你的分离的HEAD合并到你的目标分支中)。 - BigRongit rebase
和 git branch
的串行组合将一组提交应用到另一个分支上。正如回答所述,第一个命令实际上是复制提交。然而,在将分支名称添加到组中最上面的提交之前,更改是不可见的。
请在新标签页中打开图片...
以文本形式总结命令:
gitk --all &
将 gitk 作为独立进程打开。git rebase --onto a b f
。HEAD
。git branch selection
。这应该澄清问题:
a
是组的新根目标。b
是组中第一个提交之前的提交(不包括)。f
是组中最后一个提交(包括)。之后,您可以使用 git checkout feature && git reset --hard b
从 feature
分支中删除提交 c
至 f
。
除了这个答案外,我还写了一篇博客文章,描述了另一个情景下的命令,可以帮助你更好地使用它。
git rebase --onto a b mybranch
另外,那个很酷的Git图片是用哪个程序做的? - Mr_and_Mrs_D为了回答问题,根据J.B.Rainsberger和sschaef的评论,可以使用此示例中的cherry-pick范围:
git checkout a
git cherry-pick b..f
或者git checkout a
git cherry-pick c^..f
git 2.7.0.windows.1
,发现当我尝试精选一系列提交时,一切都很好,但是 git 并没有告诉你在再次提交/精选之前需要执行 git cherry-pick --continue | --abort | --quit
。因此,如果你精选了一系列的提交,每次准备好(解决冲突或其他)给定范围内的提交时,你都需要运行 git cherry-pick --continue
。 - kuskmen^
表示“c 的前一个提交”,在这种情况下是 b。这就是为什么 c^..f
和 b..f
是同义词。尝试执行 git log c^..f
命令,你应该会看到从 c 到 f 的提交记录,与执行 git log b..f
命令完全相同。 - Andy要从提交ID选择到分支末尾,您可以使用:
git cherry-pick commit_id^..branch_name
git rev-list --reverse b..f | xargs -n 1 git cherry-pick
git rev-list
打印从分支b
到f
的所有修订版本(顺序相反),因此当按顺序传递每行(提交哈希)时,它将把每个提交应用于当前的 gitHEAD
。即git cherry-pick {hash of c}; git cherry-pick {hash of d}; ...
git cherry-pick {c的哈希}; git cherry-pick {d的哈希}; ...
- coderatchetgit cherry-pick b..f
有何不同?也许在2009年不存在 cherry-pick b..f
语法? - icc97paste
,在合并冲突时可以使用以下命令完成操作(不使用xargs
): git cherry-pick -x $(git rev-list --reverse b..f | paste -sd ' ' -)
- site还有一种值得一提的变体是,如果你想要从一个分支中获取最后 n
次提交,那么 ~
语法将会很有用:
git cherry-pick some-branch~4..some-branch
在这种情况下,上述命令会从名为some-branch
的分支选择最后4次提交记录(尽管您也可以使用提交哈希代替分支名称)。