ChatGPT解决这个技术问题 Extra ChatGPT

如何挑选多个提交

我有两个分支。提交 a 是一个的头部,而另一个在 a 之上有 bcdef。我想在不提交 b 的情况下将 cdef 移动到第一个分支。使用cherry pick很容易:逐个检查第一个分支cherry-pick cf,然后将第二个分支重新定位到第一个分支。但是有没有办法在一个命令中挑选所有 c-f

这是场景的直观描述(感谢 JJD):

https://i.stack.imgur.com/7k9Ev.png

您提到的变基与问题并不真正相关,是吗? (我知道您以后可能希望 b 基于 f,但这与挑选樱桃无关。)

A
ADTC

Git 1.7.2 引入了挑选一系列提交的能力。从 release notes

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 应该来自另一个分支。

在 Windows 上,它应该是 A^^..B,因为插入符号需要被转义,或者它应该是 "A^..B"(双引号)。

在 zsh shell 中,它应该是 'A^..B'(单引号),因为插入符号是一个特殊字符。

有关说明,请参阅 Gabriel Staples 的答案。

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


在“cherry-pick A..B”形式中,A 应该比 B 更老。如果它们的顺序错误,命令将静默失败。
如果您有 git 1.7.1 或更早版本并且无法更新,您可以通过运行 git cherry-pick f~3 然后 git cherry-pick f~2 等直到 git cherry-pick f 快速挑选它们(按向上箭头获取上一个命令所以我可以快速更改数字并运行它,在大多数控制台中应该是相似的)。
很高兴知道这种语法也适用于分支名称。 git cherry-pick master..somebranch 将挑选自 master 以来某个分支上的所有提交(假设已经重新基于 master),并将它们应用到您当前的分支。
在 Windows 的 cmd.exe 中,^ 是一个特殊字符,在 A^..B 中会被忽略。您必须将其加倍 (^^) 或将提交引用放在引号中。
请注意,A^ 正在选择 A 的父提交之一。这意味着如果它有多个父提交(例如,它是一个合并提交),您必须小心。
S
Shrikant Wandhare

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

git 樱桃挑选 ACFJ


C
CB Bailey

最简单的方法是使用 rebaseonto 选项。假设当前在 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以获得完整答案吗
这个答案帮助我了解了在这种情况下哪个提交是哪个。并且:您也可以使用 rebase 的交互模式。谢谢,@查尔斯!
这种方法的美妙之处在于,您可以使用 --interactive 从序列中删除一些提交或在“樱桃采摘”之前对它们重新排序。 +1
这是一个巧妙的命令,有点难以理解,但它可以创造奇迹。
你必须给出你不想想要变基的提交作为参数之一(在这个例子中是b)但是是的,这对我有用。
w
wolfc

或要求的单线:

git rebase --onto a b f

如果只是为了简洁,这是最好的答案。
赞成,但如果 f 是提交(而不是分支),将使您处于分离的 HEAD 状态 - 您应该编辑以添加一个应该像 answer below 中那样签出分支
为什么要打扰其他人?
应该注意的是,挑选一堆提交并不等同于重新定位它们。如果您查看图表,原始发布者似乎想要变基的效果,但是如果您已经将提交发布到团队或公共回购,变基是不安全的。
C
Community

您可以使用 git rebasegit branch 的串行组合将一组提交应用到另一个分支。正如 posted by wolfc 一样,第一个命令实际上复制了提交。但是,在您将分支名称添加到组的最顶部提交之前,更改是不可见的。

请在新标签页中打开图片...

https://i.stack.imgur.com/IbK6X.jpg

以文本形式总结命令:

使用以下命令将 gitk 作为独立进程打开:gitk --all &。运行 git rebase --onto ab f。在 gitk 中按 F5。没有什么变化。但是没有标记 HEAD。运行 git branch selection 在 gitk 中按 F5。出现带有提交的新分支。

这应该澄清一些事情:

提交 a 是组的新根目的地。

提交 b 是组的第一次提交之前的提交(独占)。

提交 f 是组的最后一次提交(包括)。

之后,您可以使用 git checkout feature && git reset --hard bfeature 分支中删除提交 cf

除了这个答案,我还写了一个 blog post,它描述了另一个场景中的命令,应该有助于一般使用它。


如果不再需要 mybranch(a..f 提交),则可以将其简化为:git rebase --onto a b mybranch 和顺便说一句 - 那些漂亮的 git 图片是哪个程序?
@Mr_and_Mrs_D 感谢您的评论。我想我用 cacoo.com 来绘制图片。
A
Andy

应用 JB Rainsberger 和 sschaef 的评论来专门回答这个问题......在这个例子中使用一个樱桃挑选范围:

git checkout a
git cherry-pick b..f

或者

git checkout a
git cherry-pick c^..f

我使用 git 2.7.0.windows.1 并注意到当我尝试选择提交范围时一切正常,但 git 并没有告诉您在再次尝试提交/cherry-pick 之前您必须做的任何地方 git cherry-pick --continue | --abort | --quit。因此,如果您选择提交范围,则每次您准备好(解决冲突等)时都需要运行 git cherry-pick --continue 来处理给定范围内的提交。
我做的完全一样,但致命:找不到'a..b'
我不知道我错在哪里,但是当我在我这边执行 'git cherry-pick c^..f' 时,这包括提交 f,但不包括提交 c。但正如我在各处阅读的那样,它应该将 c 和 f 定义为包容性。还是我错了?
@Samuel 是的,没错。 c 之后的 ^ 实际上表示“c 之前的提交”,在这种情况下是 b。这就是 c^..fb..f 同义的原因。尝试执行 git log c^..f,您应该会看到提交 c 到 f,与执行 git log b..f 完全相同
G
Gabriel Staples

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

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

1. 挑选一个名为 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

2. 挑选多个提交

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

git cherry-pick commit1 commit2 commit3 commit4 commit5

3. 挑选一系列提交

我最初是从 most-upvoted answer by @Eric Darchis here 中学习这种风格的基础知识的。

请注意,要挑选 范围 的提交,您必须指定一个开始和结束提交哈希,在它们之间使用 ..。但是,在一系列提交中,不包括开始提交。因此,要包含它,您必须在开始提交之前指定提交。指定 preceding 提交的语法是将 ~~1^ 放在您的提交之后 ,如:beginning_commit~,这意味着:“beginning_commit 之前的提交”。

# 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~1commit^ 都表示“一个提交 commit之前”,或者说:“{4 之前的提交}”。

要在 commit 之前指定 两个 提交,您可以使用如下语法:

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

要在 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.

4. 挑选你的同行提交到你的分支的范围

...当他们的分支 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_brach 的分支,然后推送到他们自己的名为 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

为了您的理解,上面带有 3 个点的 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 之间的公共父提交哈希。这是他们将 peer_branch 从您的 my_branch 中分叉出来的提交。然后,当然,您正在挑选从该点到 (..) 他们在 origin/peer_branch 的最终提交的提交范围

要了解有关该 3 点语法的更多信息,请参见此处:What are the differences between double-dot ".." and triple-dot "..." in Git diff commit ranges? [duplicate]。如需有关 git checkout -b new_branch from_branch 的帮助,请在此处查看我的回答:Various ways to create a branch in git from another branch

走得更远

其他要知道的事情:一个 git rebase 只是一堆顺序的 git cherry-picks。在这里查看我的另一个答案(根据 Git,谁是“我们”,谁是“他们”?),其中我展示了一个 ASCII 绘图,其中包括我制作的 git rebase 如何工作以及它在做什么。 Git diff 提交范围中的双点“..”和三点“...”有什么区别? [重复]我对从另一个分支在 git 中创建分支的各种方法的回答


这应该被接受为答案。
@VinaySharma,真的!但是,我的回答毕竟迟到了 12 年! :)
关于:commit~3 # my preferred syntax 为了与 git 命名保持一致,将其称为“修订版”可能会更好。
D
Dustin
git rev-list --reverse b..f | xargs -n 1 git cherry-pick

如果没有冲突,则完美运行,否则“重新定位”可能会更容易,因为您不必弄清楚它在哪里停止并重新应用其余补丁。
请添加评论来解释这是做什么的
因为没有人解释...... git rev-list 打印从分支 b 到 f (反转)的所有修订,以便当每一行(提交哈希)按顺序传递时,它会将每一行挑选到当前的 git HEAD 上。即git cherry-pick {hash of c}; git cherry-pick {hash of d}; ...
N
Nick F

另一个值得一提的变体是,如果您想从分支中进行最后一次 n 提交,~ 语法可能很有用:

git cherry-pick some-branch~4..some-branch

在这种情况下,上述命令将从名为 some-branch 的分支中选择最后 4 次提交(尽管您也可以使用提交哈希代替分支名称)


u
ut9081

要从提交 id 到分支的顶端进行挑选,您可以使用:

git cherry-pick commit_id^..branch_name


这已经是答案 stackoverflow.com/a/31640427/96823 的一部分
这个答案实际上是不同的,对我很有帮助。它指定分支名称,而不是最终提交 SHA。
我收到“致命:错误修订”错误
@Dentrax 我得到了同样的错误,你找到原因了吗?
Nvm,原来我使用的是 - 而不是 ...
e
ealfonso

实际上,最简单的方法可能是:

记录两个分支之间的合并基础: MERGE_BASE=$(git merge-base branch-a branch-b) 快进或将旧分支重新设置到新分支上 将生成的分支重新设置到自身上,从合并基础开始第 1 步,并手动删除不需要的提交: git rebase ${SAVED_MERGE_BASE} -i 或者,如果只有少数新提交,请跳过第 1 步,直接使用 git rebase HEAD^^^^^^^ -i在第一步中,使用足够的 ^ 移过合并基础。

您将在交互式 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

然后删除行 b (以及您想要的任何其他行)


M
Manohar Reddy Poreddy

我需要优先选择从一个分支到另一个分支的提交,但是这里的提交很难理解,希望下面对一个简单的提交有所帮助:

流程如下:

从“dev”分支获取 1 个带有名称(“Remove Last Name field”)的提交 在“hotfix1”分支中提交

1.从“dev”分支获取提交细节

// Go to "dev" branch
git checkout dev

// Get the commit id (1e2e3e4e1 here)
git log --oneline

    > ...
    > ...
    > 1e2e3e4e1     Remove Last Name field
    > ...
    > ...

2.将提交推送到“hotfix1”分支

// Go to "hotfix1" branch
git checkout hotfix1

// Get the commit (1e2e3e4e1) from "dev" branch to "hotfix1" branch
git cherry-pick 1e2e3e4e1

// verify changes are correct
gitk

// push to "hotfix1" branch
git push

一次做多个,上面只做1个改动,依次给出所有的commit id:

git cherry-pick 1e2e3e4e1 1e2e3e4e2 1e2e3e4e3


A
Ayush Gupta

Cherry-pick 多个提交:

结帐到您想要挑选提交的分支

使用此命令:(通过部分哈希)

git 樱桃挑选 1e038f10 1e038f11 1e038f12 ...


n
nickboldt

这是一个脚本,它允许您通过简单地告诉脚本樱桃选择的源分支和目标分支以及提交的数量来连续选择多个提交:

https://gist.github.com/nickboldt/99ac1dc4eb4c9ff003a1effef2eb2d81

要从您的分支中挑选到 master(使用当前分支作为源):

./gcpl.sh -m

要从 6.19.x 分支中挑选最新的 5 个提交来掌握:

./gcpl.sh -c 5 -s 6.19.x -t master

当您可以直接使用 Git 执行此操作时,为什么需要此脚本?...
更少的输入,我的脚本会自动为你挑选提交,所以你不必通过它的 SHA 挑选每一个。无论如何,YMMV。
V
VirtualBladeX

或者使用 GitHub 桌面应用程序,

您可以在源分支的历史选项卡中多选提交,然后右键单击以获取选项“Cherry-Pick Selected Commits”。


C
CervEd

除了 commit-ish,you can pipe in a list of SHAs from stdin

git rev-list --reverse ..main -- path/ | git cherry-pick --stdin 

rev-list 基本上是需要 --reversegit-log NBplumbing 命令(“丑陋”但快速的表亲)。

您可以通过这种方式做更高级的事情,而不仅仅是一个提交范围。


m
marc_s
git format-patch --full-index --binary --stdout range... | git am -3

请添加评论来解释这是做什么的