Git cherry pick и целостность данных
Учитывая, что две ветви разошлись, и конкретная фиксация от одной ветви (и не от всего) должна быть представлена другой, git cherry pick достигает именно этого.
Через некоторое время возникает необходимость полностью объединить две ветви. Как git узнает, что у него уже есть коммит, который был выбран вишней в прошлом, чтобы он не вводил его заново?
2 ответа
Вы можете прочитать
Git Cherry-pick против Merge Workflow для хорошего сравнения между merge и cherry-pick, особенно в том, что cherry-pick не хранит родительский идентификатор, и, следовательно, не будет знать, что у него уже есть коммит, который был выбран вишней в прошлом, так что он не будет вводить это снова.
а также
http://davitenio.wordpress.com/2008/09/27/git-merge-after-git-cherry-pick-avoiding-duplicate-commits/ о том, как избежать дублирования коммитов в этом случае, используя rebase
,
В статье "Как избежать дублирования", упомянутой в ответе Тонио, говорится:
Представьте, что у нас есть основная ветка и ветка b:
o---X <-- master
\
b1---b2---b3---b4 <-- b
Теперь нам срочно нужны коммиты b1 и b3 в master, а не остальные коммиты в b. Итак, что мы делаем, это проверяем основную ветку и коммиты cherry-pick b1 и b3:
$ git checkout master
$ git cherry-pick “b1’s SHA”
$ git cherry-pick “b3’s SHA”
Результат будет:
o---X---b1'---b3' <-- master
\
b1---b2---b3---b4 <-- b
Допустим, мы делаем еще один коммит на master и получаем:
o---X---b1'---b3'---Y <-- master
\
b1---b2---b3---b4 <-- b
Если бы мы теперь слили ветку b в master:
$ git merge b
Мы получили бы следующее:
o---X---b1'---b3'---Y--- M <-- master
\ /
b1----b2----b3----b4 <-- b
Это означает, что изменения, внесенные b1 и b3, появятся дважды в истории. Чтобы избежать этого, мы можем сделать ребаз вместо слияния:
$ git rebase master b
Что даст:
o---X---b1'---b3'---Y <-- master
\
b2---b4 <-- b
В заключение:
$ git checkout master
$ git merge b
дает нам:
o---X---b1'---b3'---Y---b2---b4 <-- master, b
(после этой темы)
ОП добавляет в комментарии:
Но все же кажется, что я не совсем понимаю, как работает rebase... Я имею в виду, даже после перебазирования разве не должны появляться выбранные вишни коммиты?
№ git commit
Страница man явно упоминает:
Если вышестоящая ветвь уже содержит внесенные вами изменения (например, из-за того, что вы отправили по почте исправление, которое было применено в восходящем потоке), то этот коммит будет пропущен.
Например, запустив git rebase master в следующей истории (в которой A и A вводят одинаковый набор изменений, но имеют разную информацию о коммитере):
A---B---C topic
/
D---E---A'---F master
приведет к:
B'---C' topic
/
D---E---A'---F master
Вы можете определить, присутствует ли коммит на мастере с помощью git cherry master
(если вы на topic
ветка).