Git стратегия резервного копирования исправлений в старые ветки (вишня-выбор против слияния)
В нашей команде мы работаем следующим образом:
- У нас есть только ветвь
master
в нашем репозитории GitHub, она нестабильна - думает, что ее туда нажимают; для стабильных выпусков мы используем теги (для разработки мы используем частные вилки на GitHub)
- мы выпускаем новую небольшую версию каждые 3 недели, в которой содержатся исправления и новые функции (скажем, 1.2.4, 1.2.5, 1.2.6...)
- мы также должны поддерживать каждую младшую старую версию в течение ограниченного времени (несколько месяцев), поэтому, когда кто-то использует 1.2.4, а самая новая версия - 1.2.7, и они находят ошибку, они могут просить нас исправить ошибку на ветке, которую они используют. Затем мы выпускаем версию патча 1.2.4A.
- исправления являются весьма исключительными. Обычно мы делаем не более 1-2 патчей для младшего выпуска. Для большинства выпусков мы не делаем патчи.
Вопрос в том, какая лучшая стратегия исправить ошибку на главном и старом ветки одновременно?
Я могу думать о двух основных стратегиях:
-
Исправьте ошибку на master
, затем проверьте v1.2.4
, затем cherry-pick соответствующую фиксацию (предположим, что исправление является одной фиксацией, которая всегда выполняется) и пометьте полученное коммит как v1.2.4A
.
-
Оформить заказ v1.2.4
, исправить ошибку и зафиксировать, пометить фиксацию как v1.2.4A
и включить ее в master
, выполнить слияние.
Я скорее одобряю первую версию (вишневый сбор), но я хотел бы услышать другие комментарии о плюсах и минусах.
Конечно, все может усложниться, когда коммиты в середине вносят некоторые существенные изменения, которые могут привести к тому, что невозможно создать фиксацию, которая будет работать как в 1.2.4, так и в master (например, при изменении имени какой-либо функции или более сложных вещей). Но более распространенная ситуация заключается в том, что исправление может быть перенесено без проблем.
Преимущества сбора вишни у мастера:
-
Я думаю, что история более "съедобна" с использованием вишни. Рассмотрим это:
| <- bugfix done on master
|
|
| <- v1.2.7
...
|
|
|
|
|
|
|
|
|
| - <- v.1.2.4A (cherry-picked from master)
| /
| <- v1.2.4
vs this:
| <- bugfix merged to master
|\
| \
| |
| | <- v1.2.7
...
| |
| |
| |
| |
| |
| |
| |
| |
| |
| - <- v.1.2.4A (direct bugfix)
| /
| <- v1.2.4
Подумайте о том, что между ними есть десятки коммитов. Рассмотрите возможность использования нескольких патчей параллельно. Половина экрана будет загрязнена.
-
Скажем, я исправил проблему на v1.2.4
, но через несколько дней кто-то попросит меня запланировать на v1.2.3
. Cherry-pick - самый разумный способ сделать это.
Есть ли какие-то преимущества слияния в нашем случае, которые я забыл? Я понимаю, что он сохраняет связь между двумя коммитами лучше, чем выбор вишни, но мы храним документацию о релизах, и все это также отслеживается там.
Ответы
Ответ 1
В проектах с открытым исходным кодом, над которыми я работал, консенсус, похоже, заключается в том, что исправления должны сначала приземлиться на мастер, протестировать их и только после этого вернуться к более старым версиям. Вы можете видеть это в том, как ядро Linux делает стабильные версии, например: разработчики представляют патчи для mainline, но также назначают их для включения в стабильную.
Когда вы выбрали вишню в этой ситуации, вы, вероятно, захотите использовать флаг -x
:
При записи фиксации добавьте строку, в которой говорится: "(вишня выбрана from commit...)" в исходное сообщение фиксации, чтобы укажите, какие из этих изменений были выбраны из вишни. Это сделано только для черешни без конфликтов.... [Если] вы выбираете вишню между двумя видимыми видимыми ветвями (например, backporting исправление для ветки обслуживания для более старой версии от ветвь разработки), добавление этой информации может быть полезно.
Ответ 2
Ваша стратегия 2, сначала исправление ошибки в предыдущей ветки освобождения, например. v1.2.4
, а затем слияние этого изменения в ваш соединитель развития предлагается gitworkflows (7):
Правило: ветки раздела
Создайте боковую ветвь для каждой темы (функция, исправление,...). Откроем его на самой старой ветке интеграции, которую вы в конечном итоге захотите объединить. [выделено мной]
Многое может быть сделано очень естественно:
Чтобы получить свойство /bugfix в ветку интеграции, просто слейте его. Если тема развивается еще тем временем, снова сливайтесь. (Обратите внимание, что вам не обязательно сначала объединять его с самой старой ветвью интеграции. Например, сначала вы можете объединить исправление, дать ему некоторое время тестирования и слить в maint, когда вы знаете, что он стабилен.)
Одна из причин, по которой это имеет тенденцию работать хорошо, заключается в том, что, по моему опыту, материал добавляется чаще, чем он удаляется, поэтому, внося изменения в более старую ветку, вы избегаете зависимости от каких-либо новых функций и т.д., которые могут быть доступны в соединительной линии разработки.
Однако вам нужно подумать о том, какую ветку вы нацеливаете на исправление, когда вы делаете это изменение, вместо того, чтобы просто делать это на хозяине, а затем решать, где его объединить.
Обе стратегии жизнеспособны, и каждый из них имеет преимущества.