Со временем, когда git cherry-pick
научились применять несколько коммитов, различие действительно стало несколько спорным, но это можно назвать конвергентной эволюцией ;-)
Настоящее различие заключается в первоначальном намерении создать оба инструмента:
git rebase
Задача состоит в том, чтобы перенаправить серию изменений, которые разработчик имеет в своем частном репозитории, созданных для версии X некоторой восходящей ветки, на версию Y той же ветки (Y> X). Это эффективно меняет базу этой серии коммитов, отсюда и "перебазирование".
(Это также позволяет разработчику перенести серию коммитов на любую произвольную фиксацию, но это менее очевидное применение.)
git cherry-pick
предназначен для переноса интересного коммита с одной линии разработки на другую. Классический пример - перенос исправления безопасности, сделанного в нестабильной ветке разработки, в стабильную (обслуживаемую) ветку, где merge
нет смысла, так как это приведет к большому количеству нежелательных изменений.
С момента своего первого появления git cherry-pick
он может выбирать сразу несколько коммитов, один за другим.
Следовательно, возможно, наиболее разительное различие между этими двумя командами заключается в том, как они обрабатывают ветку, над которой работают: git cherry-pick
обычно приносит фиксацию откуда-то еще и применяет ее поверх вашей текущей ветки, записывая новую фиксацию, в то время как git rebase
берет текущую ветку и перезаписывает серия его собственных советов так или иначе фиксируется. Да, это сильно упрощенное описание того, что git rebase
можно делать, но оно сделано намеренно, чтобы попытаться понять общую идею.
Обновите, чтобы подробнее объяснить git rebase
обсуждаемый пример использования .
Учитывая эту ситуацию,
Книга утверждает:
Однако есть другой способ: вы можете взять патч изменения, который был внесен в C3, и повторно применить его поверх C4. В Git это называется перебазированием. С помощью команды rebase вы можете взять все изменения, которые были зафиксированы в одной ветке, и применить их к другой.
В этом примере вы запустите следующее:
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
«Загвоздка» здесь в том, что в этом примере ветвь «эксперимент» (подлежащая перебазированию) изначально была ответвлена от ветки «master», и, следовательно, она разделяет коммиты от C0 до C2 - фактически, «эксперимент» - это master "до C2 включительно плюс коммит C3 поверх него. (Это простейший случай; конечно, «эксперимент» может содержать несколько десятков коммитов поверх своей исходной базы.)
Теперь git rebase
предлагается переназначить «эксперимент» на текущую вершину «мастера», и он git rebase
выглядит следующим образом:
- Запускается,
git merge-base
чтобы увидеть, какая последняя фиксация используется как «экспериментальным», так и «главным» (другими словами, в чем смысл отклонения). Это C2.
- Сохраняет все коммиты, сделанные с момента переадресации; в нашем примере с игрушкой это просто C3.
- Перематывает ГОЛОВУ (которая указывает на конец фиксации «эксперимента» перед запуском операции), чтобы указать на вершину «мастера» - мы перемещаемся на него.
- Пытается применить каждый из сохраненных коммитов (как будто с
git apply
) по порядку. В нашем примере с игрушкой это всего лишь одна фиксация, C3. Допустим, его приложение произведет фиксацию C3 '.
- Если все прошло успешно, ссылка на «эксперимент» обновляется и указывает на фиксацию, полученную в результате применения последней сохраненной фиксации (в нашем случае C3 ').
А теперь вернемся к вашему вопросу. Как видите, здесь технически git rebase
действительно переносится серия коммитов от «эксперимента» до «вершины», так что вы можете с полным правом сказать, что действительно есть «другая ветвь» в процессе. Но суть в том, что фиксация подсказки из «эксперимента» оказалась новой фиксацией подсказки в «эксперименте», она просто изменила свою базу:
Опять же, технически вы можете сказать, что git rebase
здесь включены определенные коммиты от «мастера», и это абсолютно правильно.
С помощью Cherry-Pick исходные коммиты / ветки остаются и создаются новые. При использовании rebase вся ветка перемещается так, чтобы ветка указывала на воспроизведенные коммиты.
Допустим, вы начали с:
Rebase:
Ты получаешь:
Вишневый выбрать:
Ты получаешь:
больше информации о git содержится в этой книге (http://git-scm.com/book)
источник
topic
перебазирован поверхmaster
, он не содержал оставшихся коммитов, так в какой ветке они будут?git checkout topic
а затемgit reset --hard C'
после сбора вишен, то вы получите тот же результат, что и после ребазирования. Я спас себя от множества конфликтов слияния, используя выбор вишни вместо ребазирования, потому что общий предок был давно.git
-guru , но этоrebase
/cherry-pick
на всех деталях с ,git
что у меня было понимание проблемы.git checkout -b
, не имеющая к этому никакого отношенияgit cherry-pick
. Лучший способ объяснить , что вы пытаетесь сказать , будет «вы бежитеgit rebase
наtopic
ветви и передать егоmaster
; вы бежитеgit cherry-pick
наmaster
ветви и передать его (коммиты)topic
«.Сбор вишни для индивидуальных коммитов .
Когда вы выполняете ребазирование, он применяет все коммиты в истории к HEAD ветки, которые там отсутствуют.
источник
git cherry-pick foo~3..foo
и получить коммиты вершины дерева из "foo", выбранные один за другим.git am
его. В то время как вишневый выбор применяет фиксацию путем фиксации (возможно, путем создания почтового ящика с одним сообщением для каждого патча). Моя перебазировка не удалась, потому что создаваемому файлу почтового ящика не хватило места на диске, но выбор вишни с тем же диапазоном ревизий завершился успешно (и, похоже, работает быстрее).Короткий ответ:
Приведенные выше ответы хороши, я просто хотел привести пример, чтобы продемонстрировать их взаимосвязь.
Не рекомендуется заменять «git rebase» такой последовательностью действий, это просто «проверка концепции», которая, я надеюсь, помогает понять, как все работает.
Учитывая следующий репозиторий игрушек:
Скажем, у нас есть некоторые очень важные изменения (коммиты с №2 по №5) в мастере, которые мы хотим включить в наш test_branch_1. Обычно мы просто переключаемся на ветку и выполняем «git rebase master». Но поскольку мы делаем вид, что у нас есть только «git cherry-pick», мы делаем:
После всех этих операций наш график фиксации будет выглядеть так:
Как мы видим, коммиты №6 и №7 были применены против 7254931 (фиксация подсказки мастера). HEAD был перемещен и указывает на фиксацию, которая, по сути, является вершиной перебазированной ветки. Теперь все, что нам нужно сделать, это удалить старый указатель ветки и создать новый:
test_branch_1 теперь основан на последней позиции мастера. Готово!
источник
cherry-pick
может применять ряд коммитов, думаю, да. Хотя это немного странный способ делать что-то, ничто не мешает вам выбрать все коммиты в своей функциональной ветке поверхmaster
, а затем удалить функциональную ветку и воссоздать ее так, чтобы она указывала на кончикmaster
. Вы можете думать об этомgit rebase
как о последовательностиgit cherry-pick feature_branch
,git branch -d feature_branch
иgit branch feature_branch master
.Это обе команды для перезаписи коммитов одной ветки поверх другой: разница в том, какая ветвь - «ваша» (текущая извлеченная
HEAD
) или «их» (ветвь, переданная в качестве аргумента команде) - это база для этого переписывания.git rebase
берет начальную фиксацию и воспроизводит ваши коммиты как следующие за их (начальная фиксация).git cherry-pick
берет набор коммитов и воспроизводит их коммиты как следующие после ваших (вашихHEAD
).Другими слова, две команды, в своем основном поведении (игнорируя их расходящиеся характеристики, соглашение о вызовах, а также возможности улучшения), симметрично : проверить ветви
bar
и работаютgit rebase foo
сеты,bar
ветви одной и ту же историю, проверяя ветвиfoo
и работаетgit cherry-pick ..bar
установимfoo
до (изменения сfoo
, за которыми следуют изменения сbar
).Что касается именования, разницу между двумя командами можно запомнить в том, что каждая из них описывает то, что она делает с текущей веткой:
rebase
делает другую голову новой базой для ваших изменений, тогда какcherry-pick
выбирает изменения из другой ветки и помещает их поверх вашHEAD
(как вишня на мороженом).источник
Оба делают очень похожие вещи; основное концептуальное отличие (упрощенно) заключается в том, что:
rebase перемещает коммиты из текущей ветки в другую .
cherry-pick копирует коммиты из другой ветки в текущую .
Используя диаграммы, подобные ответу @Kenny Ho :
Учитывая это начальное состояние:
... и предполагая, что вы хотите, чтобы коммиты из
topic
ветки воспроизводились поверх текущейmaster
ветки, у вас есть два варианта:Использование перебазирования: сначала нужно
topic
выполнитьgit checkout topic
, а затем переместить ветку, выполнив командуgit rebase master
:Результат: ваша текущая ветка
topic
была перебазирована (перемещена) наmaster
. Филиал был обновлен, в то время как отрасль осталась на месте.topic
master
Используя вишневый выбор : сначала нужно
master
выполнитьgit checkout master
, а затем скопировать ветку, запустивgit cherry-pick topic~3..topic
(или, что то же самое,git cherry-pick B..G
), создав:Результат: коммиты из
topic
были скопированы вmaster
.master
Филиал был обновлен, в то время какtopic
отрасль осталась на месте.Конечно, здесь нужно было явно указать cherry-pick выбрать последовательность коммитов , используя обозначение диапазона
foo..bar
. Если бы вы просто передали имя ветки, как вgit cherry-pick topic
, он бы принял только фиксацию на конце ветки, что привело бы к:источник