Я пытаюсь понять практическое различие между сбором вишни и слиянием одной фиксации, если таковая имеется. Чтобы быть более точным, приведите следующую простую ситуацию:
-O <- master
\
A <- develop
Есть ли практическая разница между сбором вишни и слиянием единственного коммита A в master?
Многие ответы здесь сосредоточены на общей разнице, когда разработка на несколько коммитов опережает мастер (где различие ясно, что сборка вишни обрабатывает одну фиксацию, а процесс сквош-слияния все возвращается к общему предку).
Что я пытаюсь понять, так это то, есть ли какая-либо причина предпочесть сквош-фиксацию в этой конкретной ситуации, а не более простую IMO-выборку вишни?
Или, может быть, чтобы сделать это более общим, в ситуации, когда разработка просто опережает мастер (т.е. где возможна быстрая перемотка вперед):
-O <- master
\
A-B-C <- develop
Есть ли разница между сбором вишен A, B и C (в таком порядке) и последующим раздавливанием их на мастере и последовательностью git merge --squash
-> разрешить конфликты -> git commit
?
Мое наблюдение до сих пор состоит в том, что сквош-слияние часто сообщает о конфликтах слияния для простейшего изменения, чего не происходит при выборе вишни. Например, это тривиальное изменение в A (от O) сообщается как конфликт слияния при слиянии сквоша, но не при выборе вишни:
<<<<<<< HEAD
allow(subject).to receive(:some_method).and_return(some_result)
=======
allow(controller).to receive(:some_method).and_return(some_result)
>>>>>>> 3s/checkout-page/develop
После разрешения конфликтов состояние рабочего директора, конечно же, остается прежним.
Кажется, что сбор вишен легче и менее проблематичен в краткосрочной перспективе, но мне интересно, есть ли последствия в будущем.
Я не наблюдаю разницы в немедленных результатах, но иногда отчеты о слиянии сквоша конфликтуют с отчетами о выборе вишни, поэтому есть разница в обработке, и это также заставляет меня задуматься о возможных последствиях в будущем.
Вы можете добавить это и, вместо перефразирования, фактический код, который вы запускали, чтобы продемонстрировать разницу.
Я рекомендую установить merge.conflictStyle
на diff3
, чтобы при конфликте вы видели, что было в коммите базы слияния, а также что было в diff из базы слияния в HEAD
и что было в diff из базы слияния к их совершению. В этом случае это может показать вам, что фиксация, которую вы считали базой слияния, на самом деле не является базой слияния.
Глупая заметка: если у вас включен rerere
, конфликты, разрешенные в первый раз, будут автоматически разрешены во второй раз. Проверьте свою конфигурацию git.
Сообщения фиксации по умолчанию будут отличаться.
Кроме этого, если граф фиксации - это то, что вы нарисовали здесь:
...--H--I--J <-- master (HEAD)
\
K <-- develop
эффект слияния или выбора вишни будет таким же, потому что фактическая база слияния master
и develop
— это фиксация J
. Чтобы увидеть это в действии, используйте git rev-parse
и git merge-base
:
$ git rev-parse master
<some hash ID appears>
$ git rev-parse develop
<another hash ID appears>
$ git merge-base --all master develop
<the hash ID from the rev-parse master command appears again>
Это слияние или вишневый выбор никогда не будет иметь конфликтов. Причина в том, что родителем K
является J
, а текущим коммитом является J
, поэтому база слияния / Cherry-Pick-Parent является текущим коммитом, а один из двух diff пуст.
Теперь предположим, что график выглядит так:
...--H--I--J <-- master (HEAD)
\
K <-- develop
На этот раз база слияния будет зафиксирована H
. Результат снова должен быть одинаковым для обеих операций, как база слияния master
(текущая фиксация J
) и develop
, но на этот раз могут возникнуть конфликты слияния, поскольку две стороны различия будут сравнивать H
-vs-J
для «наши» изменения и H
-vs-K
для «их» изменений. Если мы и они коснемся одних и тех же строк одного и того же файла или коснутся строк, которые примыкают к какому-то одному файлу, мы получим конфликт слияния.
Многие ответы здесь сосредоточены на общей разнице, когда разработка на несколько коммитов опережает мастер...
Правильно: в этом случае у нас есть что-то вроде, скажем:
...--H--I--J <-- master (HEAD)
\
K--L <-- develop
Здесь коммит выбора вишни L
заставляет Git выполнить трехстороннее слияние между содержимым K
(в качестве базы слияния), содержимым J
(в качестве «нашего» коммита) и содержимым L
(в качестве «их» коммита). " совершить). Поэтому мы различаем K
и master
(т. е. J
), чтобы увидеть, что мы изменили, и K
и L
, чтобы увидеть, что они изменили. Затем Git объединяет эти различия и применяет объединенные изменения к содержимому K
, чтобы получить выборку L'
.
Напротив, git merge --squash
находит фиксацию H
в качестве базы слияния, сравнивая H
и J
, чтобы найти наши изменения, и H
и L
, чтобы найти их. Затем Git объединяет эти изменения — которые, вероятно, представляют собой два разных набора изменений, отличных от наборов вишни, — и применяет объединенные изменения к снимку в H
, а не к снимку в K
.
«эффект слияния или выбора вишни будет одинаковым, потому что фактическая база слияния мастера и разработки — это фиксация J». Но почему git merge --squash
иногда сообщает о конфликтах, а выбор вишни — нет? (Спасибо, кстати, за быстрый и подробный ответ.)
Создайте повторяемый пример, например, небольшой сценарий оболочки, который создает репозиторий, делает несколько коммитов и настраивает все так, чтобы это произошло. Тогда мы сможем повторить это и посмотреть, произойдет ли это в наших собственных версиях Git, потому что этого точно не должно быть. :-)
torek, с вашим комментарием к моему вопросу выше («В этом случае это может показать вам, что фиксация, которую вы считали базой слияния, на самом деле не является базой слияния» - и, конечно же, это было так), я считаю, что мой вопрос ответил. Спасибо за отличную разработку!
Если вы сделаете и то, и другое, какие различия вы заметите?