git cherry-pick说"...... 38c74d是合并但没有给出-m选项"

wuf*_*foo 462 git merge rebase cherry-pick

我在我的主分支中做了一些更改,并希望将这些更改带到上游.当我樱桃挑选以下提交但是我被卡在fd9f578上,其中git说:

$ git cherry-pick fd9f578
fatal: Commit fd9f57850f6b94b7906e5bbe51a0d75bf638c74d is a merge but no -m option was given.
Run Code Online (Sandbox Code Playgroud)

git试图告诉我什么是樱桃挑选正确的东西在这里使用?主分支确实包含对上游分支中已修改的文件的更改,因此我确信会出现一些合并冲突,但这些并不是很难理解.我知道哪些地方需要改变.

这些是我想要上传的提交.

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 ...
Run Code Online (Sandbox Code Playgroud)

Bor*_*lid 543

樱桃挑选的工作方式是通过取一个变量集代表的差异(该点的工作树与其父亲的工作树之间的差异),并将其应用于当前分支.

因此,如果一个提交有两个或更多父母,它也代表两个或更多的差异 - 应该应用哪一个?

你正试图挑选fd9f578,这是与两个父母的合并.因此,您需要通过使用该-m选项告诉cherry-pick命令应该计算diff的哪一个.例如,git cherry-pick -m 1 fd9f578使用父1作为基础.

我无法确定您的具体情况,但通常建议使用git merge而不是使用git cherry-pick.当您选择合并提交时,它会将您未指定的父级中所做的所有更改折叠-m到该一次提交中.你失去了他们所有的历史,并将他们所有的差异融合在一起.你的来电.

  • 你怎么知道父母的号码? (79认同)
  • @Anentropic 1是"第一个父",2是"第二个父",依此类推.顺序是它们在提交中列出的顺序(由`git show`等查看). (64认同)
  • 警告:`git merge` 可能会产生意想不到的后果。该命令将添加父分支上存在的所有其他(较旧的)提交。通常人们选择挑选是因为他们不想要其他提交。请务必仔细检查您是否只实施了您想要的更改! (22认同)
  • @wufoo你可能也应该学习`git rebase` - 它就像一个合并,但它不是整合两个分支,而是移植一个分支坐在另一个分支上面. (3认同)
  • 从cherry-pick帮助文件中不太清楚的是,如果您想要第一个父级,您应该在cherry-pick命令中键入第二个父级。为了强调答案:“它会将 **您未指定的父级**中所做的所有更改折叠到 -m 到该一次提交中”。 (3认同)
  • @lkraav你也可以做一个`git reset --hard HEAD @ {1}`来取回你丢失的提交.`git reset`不限于在历史中"向后"移动.`git checkout -b mybranch HEAD @ {1}`也可以. (2认同)
  • @wufoo:Git 比用剪刀运行要安全得多——一般来说,一旦提交(甚至隐藏),你就永远不会真正丢失任何东西。看起来历史记录可能被某些命令删除/重写,但您总是可以使用“gitk --reflog”再次找到它。就我而言,我能够使用“git重置(sha)”,然后重新提交,围绕该消息抱怨的“合并”设置樱桃选择(它是作为“ git commit --amend`)。 (2认同)
  • @Borealid 好吧,知道父母 1 是第一个父母并没有多大帮助......他们是随机给出的数字吗?或者是否有某种结构(可能是),例如父级 1 是要合并到的父级(即,它是调用 git merge otherBranch 的分支)或其他东西。 (2认同)

Dai*_*ood 28

@ 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开始线性化,然后将其挑选到一个X被调用的副本上newX.(在新的分支上执行此操作更安全,而不是变异X.)当然,步骤4中可能存在冲突,您必须以通常的方式解决(在这方面cherry-pick非常类似rebase).最后,它删除临时tempZ分支.

如果步骤2给出消息"当前分支tempZ是最新的",那么Y..Z它已经是线性的,所以只需忽略该消息并继续执行步骤3.

然后检查newX并查看是否符合您的要求.

(注意:这与git rebase Xon branch上的简单不一样Z,因为它不以任何方式依赖于X和之间的关系Y;共同的祖先和Y你不想要的东西之间可能有提交.)

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

小智 28

-m 表示父母编号。

从git doc:

通常,您无法选择合并,因为您不知道合并的哪一侧应被视为主线。此选项指定主线的父代号(从1开始),并允许Cherry-pick重播相对于指定父代的更改。

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

- A - D - E - F -   master
   \     /
    B - C           branch one
Run Code Online (Sandbox Code Playgroud)

然后git cherry-pick E会产生您遇到的问题。

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

  • `-m` 最好解释 (7认同)
  • 这个答案 /sf/answers/2706865451/ 为“-m”值提供了很好的解释 (6认同)
  • 答案有点模棱两可,“gitcherry-pickE -m 1 表示使用 DE”是什么意思? (2认同)

eph*_*err 9

@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
Run Code Online (Sandbox Code Playgroud)

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

Kay*_*y V 6

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

你正试图挑选fd9f578,这是与两个父母的合并.

而不是挑选合并,最简单的事情是从合并中的每个分支中挑选您真正想要的提交.

由于您已经合并,因此您的列表中可能包含所有您想要的提交.Cherry直接挑选它们,你不需要搞乱合并提交.

说明

cherry-pick的工作方式是获取changeset表示的diff(该点的工作树与其父级的工作树之间的差异),并将changeset应用于当前分支.

如果提交具有两个或更多个父项,就像合并的情况一样,该提交也表示两个或更多个差异.由于应该应用差异的不确定性而发生错误.

备择方案

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

  1. (更复杂和模糊;也丢弃历史记录)您可以指出应该应用哪个父级.

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

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

  2. (更简单,更熟悉;保留历史记录)您可以使用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” (20认同)