git cherry-pick говорит: «... 38c74d - это слияние, но опция -m не была предоставлена» - PullRequest
431 голосов
/ 10 февраля 2012

Я сделал некоторые изменения в своей основной ветке и хочу внести их в апстрим. когда я выбираю следующие коммиты, я застреваю на fd9f578, где git говорит:

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

Что мерзавец пытается сказать мне, и является ли вишневый выбор правильным выбором для использования здесь? Основная ветвь содержит изменения к файлам, которые были изменены в восходящей ветке, так что я уверен, что будут некоторые конфликты слияния, но они не так уж и плохи, чтобы их исправить. Я знаю, какие изменения нужны где.

Это коммиты, которые я хочу внести в апстрим.

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

Ответы [ 5 ]

507 голосов
/ 10 февраля 2012

Метод вишневого пика работает, используя diff, который представляет набор изменений (различие между рабочим деревом в этой точке и рабочим деревом его родителя), и применяя его к вашей текущей ветви.

Итак, если коммит имеет двух или более родителей, он также представляет два или более различий - какой из них следует применить?

Вы пытаетесь выбрать вишню fd9f578, которая была слиянием с двумя родителями. Таким образом, вы должны указать команде cherry-pick, на какую команду рассчитывать разницу, используя опцию -m. Например, git cherry-pick -m 1 fd9f578 для использования родителя 1 в качестве базы.

Не могу с уверенностью сказать, что для вашей конкретной ситуации, но обычно рекомендуется использовать git merge вместо git cherry-pick. Когда вы выбираете коммит слияния, он сворачивает все изменения, внесенные в родительский элемент, который вы не указали, в -m в этот один коммит . Вы теряете всю их историю и собираете вместе все их различия. Ваш звонок.

25 голосов
/ 02 мая 2016

@ Ответ Бореалида верный, но предположим, что вы не заботитесь о сохранении точной истории слияния ветви и просто хотите черриковать ее линеаризованную версию.Вот простой и безопасный способ сделать это:

Начальное состояние: вы находитесь на ветке 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 X в ветке Z, потому чтоэто никак не зависит от отношений между X и Y; между общим предком и Y могут быть коммиты, которые вам не нужны.)

13 голосов
/ 09 декабря 2018

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

5 голосов
/ 23 апреля 2018

Вот переписанный принятый ответ, который идеально проясняет преимущества / риски возможных подходов:

Вы пытаетесь выбрать вишню fd9f578, которая была объединена с двумя родителями.

Вместо выбора вишни для слияния проще всего выбрать вишню коммит (ы), который вы на самом деле хотите, из каждой ветви в слиянии.

Поскольку вы уже слились, вероятно, все ваши коммиты есть в вашем списке. Cherry-выберите их напрямую, и вам не нужно возиться с коммитом слияния.

Объяснение

Способ, которым работает вишневый кир, заключается в том, чтобы взять diff, который представляет набор изменений (различие между рабочим деревом в этой точке и рабочим деревом его родителя), и применить набор изменений к текущей ветви.

Если у коммита есть два или более родителей, как в случае слияния, этот коммит также представляет два или более различий. Ошибка возникает из-за неопределенности, к которой должен применяться diff.

альтернативы

Если вы решите, что вам нужно включить слияние с выбором вишни для связанных коммитов, у вас есть два варианта:

  1. (более сложный и неясный; также отбрасывает историю) вы можете указать, к какому из родителей следует обратиться.

    • Для этого используйте опцию -m. Например, git cherry-pick -m 1 fd9f578 будет использовать первый родительский элемент, указанный в слиянии, в качестве базы.

    • Также учтите, что когда вы выбираете коммит слияния, он сворачивает все изменения, внесенные в родительский элемент, который вы не указали, в -m в этот один коммит . Вы теряете всю их историю и собираете вместе все их различия. Ваш звонок.

  2. (проще и более знакомо; сохраняет историю) вы можете использовать git merge вместо git cherry-pick.

    • Как обычно с git merge, он попытается применить все коммиты, которые существуют в ветви, которую вы объединяете, и перечислить их индивидуально в вашем журнале git.
1 голос
/ 23 мая 2018

Упрощение метода @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
...