ChatGPT解决这个技术问题 Extra ChatGPT

git cherry-pick 说“...38c74d 是一个合并,但没有给出 -m 选项”

我在我的主分支中进行了一些更改,并希望将这些更改带到上游。当我挑选以下提交时。但是,我卡在 fd9f578 上,git 说:

$ git cherry-pick fd9f578
fatal: Commit fd9f57850f6b94b7906e5bbe51a0d75bf638c74d is a merge but no -m option was given.

git 试图告诉我什么,并且挑选合适的东西在这里使用? master 分支确实包含对上游分支中已修改的文件的更改,因此我确信会有一些合并冲突,但这些冲突并不算太糟糕,无法理顺。我知道在哪里需要进行哪些更改。

这些是我想带到上游的提交。

e7d4cff added some comments...
23e6d2a moved static strings...
44cc65a incorporated test ...
40b83d5 whoops delete whitspace...
24f8a50 implemented global.c...
43651c3 cleaned up ...
068b2fe cleaned up version.c ...
fd9f578 Merge branch 'master' of ssh://extgit/git/sessions_common
4172caa cleaned up comments in sessions.c ...
如果您只想从一个分支到另一个分支进行大量更改,而不关心合并历史记录,请直接前往 this golden answer

B
Borealid

樱桃选择的工作方式是获取变更集所代表的差异(该点的工作树与其父工作树之间的差异),并将其应用于当前分支。

所以,如果一个提交有两个或更多的父母,它也代表了两个或更多的差异——应该应用哪一个?

您正在尝试挑选 fd9f578,这是与两个父母的合并。因此,您需要使用 -m 选项告诉cherry-pick 命令应该根据哪个计算差异。例如,git cherry-pick -m 1 fd9f578 使用父级 1 作为基础。

对于您的特定情况,我不能肯定地说,但通常建议使用 git merge 而不是 git cherry-pick。当您选择合并提交时,它会将您未指定给 -m 的父项中所做的所有更改折叠到该一个提交中。你失去了他们所有的历史,并把他们所有的差异放在一起。你的来电。


@wufoo您可能还应该了解git rebase - 它就像一个合并,但它不是集成两个分支,而是将一个移植到另一个之上。
你怎么知道父母号码?
@Anentropic 1 是“第一父”,2 是“第二父”,依此类推。顺序是它们在提交中列出的顺序(由 git show 等查看)。
@lkraav 您也可以刚刚完成 git reset --hard HEAD@{1} 来取回您丢失的提交。 git reset 不限于在历史中“向后”移动。 git checkout -b mybranch HEAD@git reset --hard HEAD@{1} 也可以。
警告:git merge 可能会产生意想不到的后果。该命令将添加父分支上存在的所有其他(旧)提交。通常人们选择挑选是因为他们不想要其他提交。确保您仔细检查您是否只实施了您想要的更改!
A
Afaq Ahmed Khan

-m 表示父编号。

来自 git 文档:

通常你不能挑选合并,因为你不知道合并的哪一侧应该被视为主线。此选项指定主线的父编号(从 1 开始),并允许cherry-pick 重播相对于指定父的更改。

例如,如果您的提交树如下所示:

- A - D - E - F -   master
   \     /
    B - C           branch one

那么 git cherry-pick E 将产生您面临的问题。

git cherry-pick E -m 1 表示使用 D-E,而 git cherry-pick E -m 2 表示使用 B-C-E


这个答案 stackoverflow.com/a/38669506 很好地解释了 -m
-m 最佳解释
M
Machavity

简化。樱桃挑选提交。不要挑选合并。

如果您确定需要包含合并与挑选相关提交,您有两种选择:

(更复杂和模糊;也丢弃历史)您可以指出应该申请哪个父母。

使用 -m 选项来执行此操作。例如, git cherry-pick -m 1 fd9f578 将使用合并中列出的第一个父级作为基础。

另请考虑,当您选择合并提交时,它会将您未指定到 -m 的父项中所做的所有更改折叠到该提交中。你失去了他们所有的历史,并把他们所有的差异放在一起。你的来电。

(更简单、更熟悉;保留历史记录)您可以使用 git merge 而不是 git cherry-pick。

与 git merge 一样,它会尝试应用您正在合并的分支上存在的所有提交,并在您的 git 日志中单独列出它们。


git merge 不是cherry-pick 的替代品,因为它还将合并基于合并分支的提交。我实际上在这里有一个整洁的图表,但是堆栈溢出不允许在评论中进行格式化。想象一下,您有单独的发布分支 R、开发分支 D 和功能分支 F 和 G。F 合并到 D 中,然后 G 启动并合并到 D。业务决定只有来自 G 的更改应该进入,并且您希望这些更改进入发布分支 R,您可以选择合并提交或 R 上的 rebase --onto 分支 G。替代方法是 git rebase --onto
-m 选项的含义是什么?
@pkozuchowski 你能用你提到的图表来回答你的评论吗?我怀疑你提到的是我正在寻找的东西,因为不是我的合并提交正在潜入我的分支。
D
Daira Hopwood

@Borealid 的答案是正确的,但是假设您不关心保留分支的确切合并历史,而只想挑选它的线性化版本。这是一种简单而安全的方法:

起始状态:您在分支 X,并且您想要挑选提交 Y..Z

git checkout -b tempZ Z git rebase Y git checkout -b newX X git cherry-pick Y..tempZ (可选) git branch -D tempZ

这样做是基于 Z 创建一个分支 tempZ,但从 Y 开始的历史线性化,然后将其挑选到名为 newXX 的副本上。 (在新分支上执行此操作比更改 X 更安全。)当然,第 4 步中可能存在冲突,您必须以通常的方式解决(cherry-pick 的工作方式非常类似于 {8 } 在这方面)。最后它删除了临时的 tempZ 分支。

如果第 2 步给出消息“当前分支 tempZ 是最新的”,则 Y..Z 已经是线性的,因此请忽略该消息并继续执行第 3 步。

然后查看 newX 并查看它是否符合您的要求。

(注意:这与分支 Z 上的简单 git rebase X 不同,因为它不依赖于 XY 之间的关系;可能有共同祖先之间的提交和您不想要的 Y。)


git rebase YCurrent branch tempZ is up to date
我认为这意味着 Y..Z 已经是线性的。因此,您可以忽略该消息并继续执行步骤 3 和 4。
有趣的想法,我必须把它画在纸上才能完全理解发生了什么=D
杰出的。整个范围的 git cherry-pick 抱怨缺少 -m 选项或提供了该选项。你的解决方案是黄金。 (一个建议:删除 tempZ 分支之后)
这真太了不起了!我一直在努力挑选樱桃,只有这样才有意义。我选择的字母有点麻烦(一些分支和提交是大写字母,一些分支是小写)
e
ephemerr

@Daira Hopwood 方法的简化有利于选择一个提交。不需要临时分支。

在作者的情况下:

Z 被通缉提交 (fd9f578)

Y 在它之前提交

当前工作分支

然后做:

git checkout Z   # move HEAD to wanted commit
git reset Y      # have Z as changes in working tree
git stash        # save Z in stash
git checkout X   # return to working branch
git stash pop    # apply Z to current branch
git commit -a    # do commit

这当然会丢失与原始提交相关的元数据。我想它是否更简单是一个见仁见智的问题。当我想丢失元数据并且只保留整体代码更改时,我有时会使用它。请注意,即使 Y 不是 Z 的直接父级,它也可以工作(在这种情况下,更改将被压缩)。