git cherry-pick说:“…38c74d是合并,但未提供-m选项”


518

我在master分支中进行了一些更改,并希望将其引入上游。当我选择以下提交时,但是我陷入了git说的fd9f578上:

$ 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 ...

Answers:


606

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

因此,如果一个提交有两个或多个父项,则它还代表两个或多个差异-应该应用哪个差异?

您正在尝试选择fd9f578,这是两个父母的合并。因此,您需要通过使用该-m选项来告诉cherry-pick命令应针对哪个diff计算差异。例如,git cherry-pick -m 1 fd9f578以父级1为基数。

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


3
@wufoo您可能还应该了解git rebase-就像是合并,但是与其合并两个分支,不如将两个分支移植到另一个分支之上。
Borealid 2012年

91
你怎么知道父母的号码?
Anentropic 2012年

66
@Anentropic 1是“第一父级”,2是“第二父级”,依此类推。顺序是它们在提交中列出的顺序(由git show等等查看)。
Borealid 2012年

2
@lkraav您也可以做一个a git reset --hard HEAD@{1}来找回丢失的提交。git reset不限于历史上的“后退”。git checkout -b mybranch HEAD@{1}也可以。
Borealid 2013年

4
警告:git merge可能会有意想不到的后果。该命令将添加父分支上存在的所有其他(较旧的)提交。通常,人们选择摘樱桃是因为他们不希望其他提交。确保仔细检查您是否仅在实现所需的更改!
凯V

52

-m 表示父母编号。

从git doc:

通常,您无法选择合并,因为您不知道合并的哪一侧应被视为主线。此选项指定主线的父代号(从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


32

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

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

  1. git checkout -b tempZ Z
  2. git rebase Y
  3. git checkout -b newX X
  4. git cherry-pick Y..tempZ
  5. (可选的) git branch -D tempZ

这里做的事情是创建一个分支tempZ基础上Z,但随着历史的Y向前线性化,然后樱桃挑选到一个副本XnewX。(在新分支上执行此操作而不是进行更改是更安全的方法X。)当然,在第4步中可能存在冲突,您必须以通常的方式解决(在这方面的cherry-pick工作非常类似rebase)。最后,它删除临时tempZ分支。

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

然后查看 newX并查看是否满足您的要求。

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


1
git rebase YCurrent branch tempZ is up to date
Basilevs

我认为这Y..Z已经是线性的。所以,你可以忽略该消息,并与步骤3和4进行
Daira霍普伍德

1
有趣的主意,我不得不将其画在纸上才能完全理解= D发生的一切
克里斯(Chris)

2
辉煌。整个范围内的git cherry-pick抱怨-m选项丢失或已提供。您的解决方案是黄金。(一个建议:之后删除tempZ分支)
Otheus

1
这真太了不起了!我一直在努力挑选樱桃,只有这样才有意义。我在选择字母时遇到了麻烦(某些分支和提交是大写字母,有些分支是小写字母)
pcarvalho

19

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

这是对已接受答案的重写,可以理想地阐明可能方法的优点/风险:

您正在尝试挑选fd9f578,它与两个父母合并。

除了简单地选择合并,最简单的方法是从合并中的每个分支中挑选您实际想要的提交。

由于您已经合并,因此可能所有需要的提交都在列表中。直接选择它们,您无需弄乱合并提交。

说明

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

如果一个提交有两个或多个父级(如合并情况),则该提交也代表两个或多个差异。发生错误是由于不确定应应用差异的原因。

备择方案

如果确定需要包括合并与挑选相关提交的比较,则有两种选择:

  1. (更加复杂和晦涩;也将丢弃历史记录),您可以指明应采用哪个家长。

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

    • 还要考虑一下,当您选择一个合并提交时,它会将您未指定的对父级所做的所有更改折叠-m到该提交中。您会失去他们的所有历史,并将他们所有的差异混在一起。您的来电。

  2. (更简单,更熟悉;保留历史记录),您可以git merge代替使用git cherry-pick

    • 像往常一样git merge,它将尝试应用您要合并的分支上存在的所有提交,并将它们分别在git日志中列出。

2

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

对于作者而言:

  • Z是通缉犯(fd9f578)
  • Y在它之前提交
  • X当前工作分支

然后做:

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

2
当然,这会丢失与原始提交关联的元数据。我想是否更简单是一个问题。当我丢失元数据而仅保留整体代码更改时,有时会使用它。请注意,即使Y不是Z的直接父级,它也可以工作(在这种情况下,更改将被压缩)。
Daira Hopwood
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.