Git cherry-pick говорит: "... 38c74d - это слияние, но опция no -m была дана"

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

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

Что 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 ...

Ответ 1

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

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

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

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

Ответ 2

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

Ответ 3

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

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

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

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

объяснение

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

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

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

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

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

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

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

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

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

Ответ 4

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

Ответ 5

-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 означает использование DE, а git cherry-pick E -m 2 означает использование BCE.