В чем разница между git merge - сквош и git cherry-pick?
Если я работаю в стандартном рабочем процессе с основными функциями, в чем будет разница между разделением ветви функций на мастер и выбором вишни на мастер?
Примеры веток:
m1 -- m2 master
\-- f1 -- f2 feature
Я думаю, что оба имеют одинаковый выход, т.е.
m1 -- m2 -- -- -- m3 master
\-- f1 -- f2 feature
1 ответ
Есть два важных различия между merge --squash
а также cherry-pick
:
1. Вишня выбирает только один коммит
То есть, если у вас есть ситуация, которую вы описали выше, и вы (на master
) сделать git cherry-pick feature
Полученная ветка будет выглядеть так:
m1 -- m2 -- f2’ master
\-- f1 -- f2 feature
Это означает, что изменения от f1
не присутствуют на мастере (и сбор вишни может быть неудачным, если f2
зависит от них.
2. Сбор вишни создает коммит
merge --squash
не сразу фиксирует, а создает сводку всех изменений и готовит их к фиксации. По сути, это патч ваших полных изменений ветки, git diff m1..feature
показал бы.
На моей машине быстрый тест дал такой вывод:
$ test git:(master) git merge --squash testbranch
Squash commit -- not updating HEAD
Automatic merge went well; stopped before committing as requested
Важным моментом здесь является "не обновлять HEAD", что означает "я не передал то, что сделал". Второе предложение на самом деле гораздо удобнее для пользователя...
Эта функция удобна, если вы хотите разрабатывать пошагово (совершая все маленькие шаги, которые привели к решению, например, с фиксацией после каждого успешного запуска теста. В этом случае ваша история, вероятно, будет загромождена сотнями коммиты в одну строку. Так что, вероятно, лучше время от времени делать коммит-сквош-коммит (например, после того, как вы разработали один бит функциональности).
Выбор вишни позволяет применить изменение, внесенное другим коммитом в вашу текущую ветку.
Слияние со сжатием (с последующим фиксированием) делает то же самое, что и слияние (в отношении результирующего рабочего каталога и индекса, а не истории).
Вот пример (некоторые выходные данные git не показаны).
Настроить
$ git init
$ echo sahred file > shared-file.txt
$ git add .
$ git commit -m 'added shared-file.txt in master branch'
$ git checkout -b dev
$ touch dev.txt
$ git add .
$ git commit -m 'added dev.txt in dev branch'
$ echo shared file > shared-file.txt
$ git add .
$ git commit -m 'fixed typo in shared-file.txt in dev branch'
$ git checkout master
Теперь у нас есть филиал dev
с дополнительным файлом (dev.txt
) и где опечатка в shared-file.txt
фиксированный. Мы вернулись кmaster
ветка для сравнения сбора вишен и слияния.
Сбор вишни
$ git cherry-pick dev
$ git log --oneline --graph
* 8019b05 (HEAD -> master) fixed typo in shared-file.txt in dev branch
* 7dbd3aa added shared-file.txt in master branch
$ ls
shared-file.txt
$ cat shared-file.txt
shared file
Как видите, после выбора изменения последняя фиксация вdev
введена ветка (исправление опечатки в shared-file.txt
) но дополнительный файл dev.txt
не был перенесен, потому что он не был создан в последней фиксации в dev
ветвь.
Теперь мы отменяем выбор и сравниваем с результатом слияния.
Слияние (с раздавливанием и фиксацией)
$ git reset HEAD~1 --hard # undo cherry-pick
$ git merge dev --squash
$ git commit -m 'merged dev'
$ git log --oneline --graph
* 01dd755 (HEAD -> master) merged dev
* 7dbd3aa added shared-file.txt in master branch
$ ls
dev.txt shared-file.txt
$ cat shared-file.txt
shared file
Как видите, и опечатка была исправлена, и dev.txt
был перенесен. Это связано с тем, что слияние со сжатием (с последующим фиксированием) совпадает с обычным слиянием двух коммитов в отношении результирующего рабочего каталога и индекса (но, конечно, не истории).