Мы работаем над проектами, но мы используем много кода между проектами и имеем много библиотек, которые содержат наш общий код. По мере того, как мы реализуем новые проекты, мы находим больше способов выделить общий код и поместить его в библиотеки. Библиотеки зависят друг от друга, а проекты зависят от библиотек. Каждый проект и все библиотеки, используемые в этом проекте, должны использовать одну и ту же версию всех библиотек, на которые они ссылаются. Если мы выпустим часть программного обеспечения, нам придется исправлять ошибки и, возможно, добавлять новые функции в течение многих лет, а иногда и десятилетий. У нас около дюжины библиотек, изменения часто затрагивают более двух, и несколько команд работают над несколькими проектами параллельно, внося параллельные изменения во все эти библиотеки.
Недавно мы перешли на git и создали репозитории для каждой библиотеки и каждого проекта. Мы используем stash в качестве общего репозитория, делаем новые вещи в функциональных ветках, затем делаем запросы на извлечение и объединяем их только после просмотра.
Многие из проблем, с которыми нам приходится сталкиваться в проектах, требуют от нас внесения изменений в несколько библиотек и специфический код проекта. Они часто включают изменения интерфейсов библиотеки, некоторые из которых несовместимы. (Если вам кажется, что это звучит странно: мы взаимодействуем с оборудованием и скрываем определенное оборудование за общими интерфейсами. Почти каждый раз, когда мы интегрируем оборудование другого производителя, мы сталкиваемся со случаями, которые наши текущие интерфейсы не ожидали, и поэтому должны их усовершенствовать.) Например, представьте проект с P1
использованием библиотек L1
, L2
и L3
. L1
также использует L2
и L3
, и L2
использует L3
также. Граф зависимостей выглядит так:
<-------L1<--+
P1 <----+ ^ |
<-+ | | |
| +--L2 |
| ^ |
| | |
+-----L3---+
Теперь представьте, что функция для этого проекта требует изменений P1
и L3
изменения интерфейса L3
. Теперь добавьте проекты P2
и P3
в смесь, которая также ссылается на эти библиотеки. Мы не можем позволить себе переключить их на новый интерфейс, выполнить все тесты и развернуть новое программное обеспечение. Так какая альтернатива?
- реализовать новый интерфейс в
L3
- сделать запрос на получение
L3
и дождаться обзора - объединить изменения
- создать новый выпуск
L3
- начните работать над этой функцией
P1
, сделав ссылку наL3
ее новую версию, затем внедрите эту функцию вP1
ветку функций - сделайте запрос на удаление, проверьте это и объедините
(Я только что заметил, что забыл переключиться L1
и L2
на новый релиз. И я даже не знаю, куда это вставить, потому что это должно было бы быть сделано параллельно с P1
...)
Это утомительный, подверженный ошибкам и очень длительный процесс для реализации этой функции, он требует независимых проверок (что делает проверку намного сложнее), вообще не масштабируется и, вероятно, выведет нас из бизнеса, потому что мы настолько увязнуть в процессе, что мы ничего не сделаем.
Но как мы используем ветвление и тегирование для создания процесса, который позволяет нам реализовывать новые функции в новых проектах без лишних затрат?
Ответы:
Вроде бы выкладываю здесь очевидное, но, возможно, стоит упомянуть об этом.
Как правило, репозитории git разрабатываются для каждой библиотеки / проекта, потому что они, как правило, независимы. Вы обновляете свой проект, а остальное вас не волнует. Другие проекты, зависящие от этого, просто обновят свою библиотеку, когда сочтут нужным.
Однако ваш случай кажется сильно зависимым от коррелированных компонентов, поэтому одна функция обычно влияет на многие из них. И целое должно быть упаковано как связка. Поскольку реализация функции / изменения / ошибки часто требует одновременной адаптации множества различных библиотек / проектов, возможно, имеет смысл поместить их все в один репозиторий.
Есть сильные преимущества / недостатки этого.
Преимущества:
Недостатки:
Вам решать, стоит ли цена выгоды.
РЕДАКТИРОВАТЬ:
Это будет работать так:
feature_x
feature_y
иfeature_z
может быть добавлено тоже. Это становится объединением "кросс-команды". Вот почему это серьезный недостаток.Просто для справки: я думаю, что в большинстве случаев это плохая идея, и ее следует делать осторожно, потому что недостаток слияния обычно выше, чем тот, который вы получаете при управлении зависимостями / правильном отслеживании функций.
источник
:-/
Более того, даже те, кто (и кто настаивал на переходе на git), не знают, как совместить наш процесс разработки с git. Вздох. Боюсь, это будет несколько трудных месяцев, пока все не станет гладким. Спасибо, в любом случае, ваш самый / единственный полезный ответ до сих пор.Решение, которое вы ищете, представляет собой инструмент управления зависимостями в координации с подмодулями git.
Инструменты, такие как:
Вы можете использовать эти инструменты для определения зависимостей проекта.
Вы можете требовать, чтобы субмодуль был по крайней мере версии > 2.xx или обозначал диапазон версий, которые совместимы = 2.2. * Или меньше, чем конкретная версия <2.2.3
Всякий раз, когда вы выпускаете новую версию одного из пакетов, вы можете пометить его номером версии, таким образом вы можете вставить эту конкретную версию кода во все другие проекты.
источник
подмодули
Вы должны попробовать git submodules , как предлагается в одном комментарии.
Когда проект
P1
относится к трем подмодулямL1
,L2
иL3
, на самом деле сохраняет ссылку на конкретные фиксаций во всех трех хранилищах: это те рабочие версии каждой библиотеки для этого проекта .Таким образом, несколько проектов могут работать с несколькими подмодулями:
P1
может ссылаться на старую версию библиотеки, вL1
то время как проектP2
использовал новую версию.Что происходит при доставке новой версии
L3
?L3
L2
работуL3
, совершить, ...L1
работу с новымиL2
, ...P1
работу с новыми версиями всех библиотек:P1
«s локальной рабочей копииL1
,L2
иL3
, fetche изменения вы заинтересованы.git add L1 L2 L3
зафиксировать новую ссылку на модулиP1
, проверить, просмотреть, вытащить запрос, объединить ...методология
Да, это требует независимых проверок, потому что вы меняете:
Вы были бы разорены, потому что доставляете дерьмо? (Может и нет). Если да, то вам нужно выполнить тесты и просмотреть изменения.
С помощью соответствующих инструментов git (даже
gitk
) вы можете легко увидеть, какие версии библиотек использует каждый проект, и вы можете независимо обновлять их в соответствии с вашими потребностями. Подмодули идеально подходят для вашей ситуации и не замедляют процесс.Может быть, вы можете найти способ автоматизировать часть этого процесса, но большинство из вышеперечисленных шагов требует человеческого мозга. Самый эффективный способ сократить время - обеспечить легкое развитие ваших библиотек и проектов . Если ваша кодовая база может корректно обрабатывать новые требования, тогда проверки кода будут проще и занимают мало времени.
(Изменить) еще одна вещь, которая может помочь вам, это сгруппировать обзоры кода. Вы фиксируете все изменения и ждете, пока вы не распространите эти изменения во всех библиотеках и проектах, которые их используют, прежде чем отправлять запросы на извлечение (или прежде чем позаботиться о них). Вы заканчиваете тем, что делаете больший обзор для всей цепочки зависимостей. Может быть, это поможет вам сэкономить время, если каждое локальное изменение невелико.
источник
Итак, я понимаю, что для P1 вы хотите изменить интерфейс L3, но вы хотите, чтобы другие P2 и P3, которые зависят от интерфейса L3, изменились сразу. Это типичный случай обратной совместимости. Есть хорошая статья об этой сохраняющей обратной совместимости
Есть несколько способов решить эту проблему:
ИЛИ ЖЕ
источник
Если я правильно понимаю вашу проблему:
Таким образом, цель в том, чтобы вы могли сделать P1 и L1 за один раз, а затем через месяц сделать L2 и L3 за один раз.
В мире Java это тривиальный и, возможно, стандартный способ работы:
Таким образом, вы можете иметь код на локальном диске для L3, который не будет компилироваться, если он компилируется с копией P1 в другом каталоге на вашем диске; к счастью, это не так. Java может сделать это напрямую, потому что рассказы о компиляции / компоновке помещаются в скомпилированные файлы jar, а не в исходный код.
Я не знаю ранее существовавшего широко используемого решения этой проблемы для мира C / C ++, и я думаю, что вы вряд ли захотите переключать языки. Но что-то может быть легко взломано вместе с make-файлами, которые сделали эквивалентную вещь:
Вы даже можете использовать поддержку C / C ++ в maven , хотя большинство разработчиков C будут смотреть на вас странно, если вы это сделаете ...
источник
:)
Существует простое решение: разрезать ветки релизов по всему репозиторию, объединять все исправления со всеми активно поставляемыми релизами (это легко сделать в ясном случае в git).
Все альтернативы создадут ужасный беспорядок со временем и с ростом проекта.
источник