cherry-pick
реализовано в виде слияния, при этом база слияния является родительским элементом в вводимом cmomit. В случаях, когда нет конфликтов слияния, это должно иметь точно такой же эффект, что и создание и применение патча как у вас (но см. ответ Торека для некоторого предостережения, где am
теоретически может сделать неправильную вещь).
Но, осуществляя слияние, cherry-pick
может попытаться более изящно обрабатывать случаи, когда изменения будут конфликтовать. (На самом деле, опция -3
, которую вы дали am
, говорит о том, что при необходимости она должна делать то же самое, если в патче достаточно контекста, чтобы можно было это сделать. Я вернусь к эта точка в конце ...)
Когда вы применяете патч, по умолчанию, если он изменяет кусок кода, который не совпадает с коммитом, в котором вы его применяете, как это было в родительском коммите, из которого он был сгенерирован, то применение завершится неудачно. Но подход cherry-pick
/ merge рассмотрит, каковы эти различия, и создаст из них конфликт слияния - так что у вас есть шанс разрешить конфликт и продолжить.
Как часть обнаружения конфликта, cherry-pick
делает обнаружение переименования. Так, например, скажем, у вас есть
o -- x -- x -- A <--(master)
\
B -- C -- D <--(feature)
и вы cherry-pick
фиксируете C
на master
. Предположим, в o
вы создали file.txt
, а в A
у вас есть изменения для file.txt
. Но фиксация B
перемещает file.txt
в my-old-file.txt
, а фиксация C
изменяет my-old-file.txt
.
Изменение на my-old-file.txt
в C
может конфликтовать с изменением на file.txt
в A
; но чтобы увидеть такую возможность, git должен выполнить обнаружение переименования, чтобы выяснить, что file.txt
и my-old-file.txt
- это «одно и то же».
Вы можете знать, что у вас нет такой ситуации, но git не знает, пока не попытается обнаружить переименования. Я не уверен, почему это заняло бы много времени в этом случае; по моему опыту это обычно не так, но в репо с множеством добавленных и удаленных путей (между B
и C
или A
в нашем примере) это может быть.
Когда вы генерируете и применяете патч вместо этого, пытается применить патч при условии, что конфликта нет. Только если это столкнется с проблемой (и тогда, только потому, что вы указали опцию -3
), оно вернется к выполнению слияния с обнаружением конфликта. Он может пропустить все это - и любое потенциальное обнаружение переименования - до тех пор, пока его первая попытка применяется чисто.
Обновление - Как отмечено в комментариях к вопросу, вы также можете отключить обнаружение переименования, если это не помогает и работает медленно. Если вы используете это, когда фактически происходит переименование, которое «имеет значение» для слияния, это может вызвать конфликты, когда обнаружение переименования разрешит их. Хотя я не думаю, что это должно, я не могу исключить, что он может также просто вычислить неверный результат слияния и спокойно применить его - вот почему я редко использую эту опцию.
Для стратегии слияния по умолчанию опция -X no-renames
отключит обнаружение переименования. Вы можете передать эту опцию на cherry-pick
.
Согласно комментарию Торека, обнаружение переименования должно быть проблемой с am
. Тем не менее, я могу подтвердить, что он может правильно обрабатывать случай, когда объединение работает только с обнаружением переименования. Я вернусь к тому, чтобы попытаться понять все тонкости этого когда-нибудь, когда не пятничный полдень.