乐闻世界logo
搜索文章和话题

Git 如何 cherry pick 多个提交记录?

9 个月前提问
5 个月前修改
浏览次数130

6个答案

1
2
3
4
5
6

在使用Git进行版本控制时,cherry-pick 是一项功能,它允许开发者选择一个或多个提交(commit)从一个分支复制到当前所在的分支。当你想要将指定的提交应用到你的分支,而不是合并整个分支的内容时,这非常有用。

要逐个挑选多个提交记录,你可以重复使用 git cherry-pick 命令,后面跟着你想要挑选的提交的哈希值(commit hash)。例如:

sh
git cherry-pick commit_hash1 git cherry-pick commit_hash2 git cherry-pick commit_hash3

每执行一次 cherry-pick,就会将指定的提交应用到当前分支上。

如果你想一次挑选一系列连续的提交,你可以使用如下命令:

sh
git cherry-pick commit_hash1^..commit_hash3

在这个例子中,commit_hash1^ 表示 commit_hash1 的父提交,而 commit_hash3 是你想要挑选的最后一个提交。上面的命令将会挑选 commit_hash1commit_hash3 之间的所有提交(包括 commit_hash1commit_hash3)。

如果你想要挑选不连续的多个提交,可以在 git cherry-pick 命令中一次性列出所有想要挑选的提交哈希值,每个哈希值之间用空格隔开。例如:

sh
git cherry-pick commit_hash1 commit_hash3 commit_hash5

这将会分别挑选 commit_hash1commit_hash3commit_hash5 这三个提交。

在执行 cherry-pick 操作时,可能会发生冲突。如果发生冲突,Git 会停止应用提交,并让你解决冲突。解决完冲突后,你需要使用 git add 命令将冲突文件标记为已解决,然后使用 git cherry-pick --continue 继续应用挑选的提交。如果你决定不继续这个 cherry-pick 操作,可以使用 git cherry-pick --abort 放弃更改,回到操作前的状态。

2024年6月29日 12:07 回复

Git 1.7.2 引入了挑选一系列提交的功能。从发行说明来看:

git cherry-pick学会了选择一系列提交(例如cherry-pick A..Bcherry-pick --stdin), 也是如此git revertrebase [-i]不过,这些不支持更好的排序控制。

A要从一个提交到另一个提交B(其中A早于B)挑选所有提交,请运行:

shell
git cherry-pick A^..B

如果你想_忽略_A 本身,请运行:

shell
git cherry-pick A..B

评论中的注释:

  • A应该早于B,或者A应该来自另一个分支。
  • 在 Windows 上,它应该是A^^..B因为插入符号需要转义,或者应该是"A^..B"(双引号)。
  • zshshell 中,它应该是'A^..B'(单引号),因为插入符号是一个特殊字符。
  • 有关说明,请参阅Gabriel Staples 的回答

(感谢评论中的 damian、JB Rainsberger、sschaef、Neptilo、Pete 和 TMin。)

2024年6月29日 12:07 回复

如果您有选择性的修订要合并,例如来自 A、B、C、D、E、F、G、H、I、J 提交的 A、C、F、J,只需使用以下命令:

shell
git cherry-pick A C F J
2024年6月29日 12:07 回复

最简单的方法是onto选择rebase. 假设当前结束的分支称为 mybranch,并且这是您要移动到的a分支。c``f

shell
# 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
2024年6月29日 12:07 回复

如何挑选单个提交、多个提交或一系列提交

...到您当前签出的分支:

1. 挑选一个名为的_分支_或提交commit

shell
git cherry-pick commit

例子:

shell
git cherry-pick my_branch # by branch name git cherry-pick 1e038f108a130831f108329b1083a8139813fabc # by full hash git cherry-pick 1e038f10 # by partial hash

2. 挑选_多个_提交

请注意,您可以按您想要的任何顺序一次挑选_任意数量的提交哈希值__。_它们只会按照您指定的顺序一次应用一个。如果出现任何冲突,您必须一次解决一个问题,然后在完成后使用git add my_filethengit cherry-pick --continue继续挑选过程。

shell
git cherry-pick commit1 commit2 commit3 commit4 commit5

3. 挑选_一系列_提交

我最初是从@Eric Darchis 在这里获得最多支持的答案中学习了这种风格的基础知识。

请注意,要挑选一系列_提交_,您必须指定开始和结束提交哈希,以及..它们之间的值。但是,在一系列提交中,不包括开始提交。因此,要包含它,您必须在开始提交_之前_指定提交。_指定前面_提交的语法是在提交_之后_放置~~1或 ,如: ,这意味着^:“之前的提交”。beginning_commit~``beginning_commit

shell
# 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~1和all 表示“之前的commit^一次提交”,或者换句话说:“之前的提交”。 commit``commit

要指定之前的_两次_commit提交,您可以使用如下语法:

shell
commit~~ commit~2 # my preferred syntax commit^^

要指定之前的_三个_commit提交,您可以执行以下操作:

shell
commit~~~ commit~3 # my preferred syntax commit^^^

这不起作用:

shell
commit^3 # INVALID syntax

这_确实_有效,但这是一个非常特殊的情况。另请参阅我的问答:git merge-style 工作流程中,仅显示合并之前某人在其 PR(拉取请求)功能分支中拥有的唯一提交

shell
# valid on **merge commits** only commit^2 # this is the immediate **right** parent of the two parents # involved in the merge (which made commit `commit`) # valid on any commits (gets the left parent of a merge commit, or # the only parent of a non-merge commit) commit~ # and this is the immediate **left** parent of the two # parents involved in the merge (which made commit `commit`)

要自己测试上述“先前提交语法”概念,最简单的方法是使用git log命令。前任:

shell
git log commit git log commit~ git log commit~1 git log commit^ git log commit~~ git log commit~5 # etc.

4. 挑选一系列同行的提交到您的分支上

...当他们的分支peer_branch从您的分支的早期版本中分叉出来时my_branch

快速总结

shell
# 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

提交范围内 2 点和 3 点之间的差异非常显着。git diff branch1...branch2相当于git diff $(git merge-base branch1 branch2) branch2. branch2当您想要查看自 偏离 以来所做的更改branch1,而不是两个分支在当前状态下的差异时,这非常有用。请参阅此处和此处的评论以及此处的答案:What are the Differences between double-dot ".." and Triple-dot "..." in Git diff commit Ranges?

完整的详细信息和工作流程演练

假设您正在开发功能分支my_branch,而您的同事希望帮助您进行一些更改以帮助您完成功能。您已经推my_branch送到名为 的远程origin。因此,他们将获取名为my_branch其本地计算机的远程分支,从中分叉出自己的名为 的分支peer_brach,然后推送到自己名为 的分支peer_branch。一旦他们这样做了,你就可以立即挑选他们添加的所有内容。该过程的第一部分如下所示:

shell
# **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,您可以挑选他们添加到您的工作之上的_所有提交,如下所示:_

shell
# **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上面那个带有 3 个点的命令_完全等同_于这个更长的命令:

shell
git cherry-pick $(git merge-base my_branch origin/peer_branch)..origin/peer_branch

该部分查找branch和branchgit merge-base my_branch origin/peer_branch之间的公共父提交哈希。这是他们从你的你的. 然后,您当然会挑选从该点到 ( ) 的最终提交_的提交范围_。my_branch``origin/peer_branch``peer_branch``my_branch``..``origin/peer_branch

要了解有关 3 点语法的更多信息,请参阅此处:Git diff 提交范围中双点“..”和三点“...”之间的区别是什么?[复制]。有关 的帮助git checkout -b new_branch from_branch,请参阅我的答案:从另一个分支在 git 中创建分支的各种方法

官方 Git 文档

  1. https://git-scm.com/docs/gitrevisions - 提到 git commit 3 点 ( ...) 与 2 点范围语法、^commit("not" commit)、commit^( 的父级commit) 等。

更进一步

  1. 还有一点需要知道: agit rebase只是一堆连续的git cherry-picks。请参阅我的其他答案(根据 Git,谁是“我们”,谁是“他们”?),其中我展示了我制作的 ASCII 绘图,其中显示了 a 的git rebase工作原理及其正在执行的操作。
  2. Git diff 提交范围中的双点“..”和三点“...”有什么区别?[复制]
  3. 我对从另一个分支在 git 中创建分支的各种方法的回答
  4. 我的问答:git merge风格的工作流程中,仅显示合并之前某人在其 PR(拉取请求)功能分支中的唯一提交
2024年6月29日 12:07 回复

或者所要求的一行:

shell
git rebase --onto a b f
2024年6月29日 12:07 回复

你的答案