Git вложенные подмодули и зависимости - PullRequest
46 голосов
/ 14 сентября 2009

Допустим, у меня есть четыре проекта с именами Core , A , B , Super . Дерево зависимостей выглядит так:

Super ---> Core
       |-> A -> Core
       |-> B -> Core

Я хочу, чтобы каждый проект был автономным, то есть я хочу иметь возможность извлекать и компилировать каждый проект самостоятельно (каждый, конечно, со своими зависимостями).

Я думал о том, чтобы сопоставить каждый проект с репозиторием, а затем передать зависимости с подмодулями, но я вижу следующие проблемы с этим подходом:

  1. При проверке Super со всеми его зависимостями я бы получил три копии Core .
  2. Поскольку подмодули полностью независимы, каждая из этих трех копий может указывать на разные ревизии Core , и это будет беспорядок.

Итак ... Я что-то упустил? Я неправильно понял подмодули git или неправильно их использовал? Есть ли другое решение этой проблемы (кроме использования бинарных зависимостей)?

Ответы [ 6 ]

14 голосов
/ 14 сентября 2009

Вы только что обнаружили отсутствие переопределенных зависимостей с подмодулями Git:

Если Super зависит от Core, его зависимость от Core должна "переопределять" те, которые A и B имеют с Core.

Единственный способ эмулировать это создать ваш Супер проект, как вы,
и для удаления подмодуля Core из A и B.
(то есть Super теперь зависит от A 'и B', A 'означает A без ядра, B' означает B без ядра)

7 голосов
/ 14 сентября 2009

git-репозитории должны быть достаточно атомарными в том смысле, что каждый репозиторий является отдельной сущностью для определенной цели. Какова цель супер-проекта, кроме объединения проектов A и B? Если не существует ничего уникального (то есть файлов, которые не находятся ни в A, B, ни в Core), то это довольно избыточно.

РЕДАКТИРОВАТЬ: Поскольку подмодули git особенно болезненны в одном месте, где я работал, мы создали нашу собственную систему зависимостей, которая отслеживает зависимые репозитории через текстовые файлы. Мы настроили его так, чтобы он всегда отслеживал заголовок ветви, а не конкретный коммит.

Мы смогли настроить все наши проекты, как если бы они были частью Супер проекта, как это:

Super
|-A
|-B
|-Core

Проекты будут ссылаться друг на друга, используя относительные пути, например ../A/include.h. Проверка репо A не будет работать, вам придется создать еще одно «супер» репо для работы только на A:

AWorking
|-A
|-Core

РЕДАКТИРОВАТЬ Другая причина такого поведения в git состоит в том, что он не может отслеживать вещи, которые находятся выше корневого каталога репо (то есть выше папки, содержащей папку .git), что определенно потребуется, если хотите, чтобы ваши суперпроекты и подпроекты ссылались на одни и те же репозитории.

6 голосов
/ 08 августа 2011

Я думаю, что проблема заключается в несоответствии между дизайном Git и проблемой, которую вы хотите решить.

Git хорош для отслеживания деревьев. Отношения зависимости между проектами могут (и, вероятно, могут) сформировать График. Дерево - это граф, но граф не обязательно является деревом. Поскольку ваша проблема заключается в том, как эффективно представлять график, дерево - не лучший инструмент для работы.

Вот подход, который может работать:

В git-проекте есть каталог .gitmodules, в который записываются «подсказки», в которых указывается, от каких проектов может зависеть коммит, где их можно найти и по какому пути в проекте они будут вставлены. (http://osdir.com/ml/git/2009-04/msg00746.html)

Вы можете добавить скрипт, который считывает эту информацию из набора проектов, сопоставляет подсказки, найденные в файле .gitmodules каждого проекта, с местами в файловой системе, где эти проекты были фактически размещены, а затем добавляет символические ссылки из путей где git ожидает извлечения субмодулей для фактических расположений файловой системы соответствующих проектов.

Этот подход использует символические ссылки, чтобы вырваться из формы дерева и построить график. Если мы будем записывать ссылки непосредственно в репозитории git, у нас будут относительные пути, специфичные для нашей локальной установки, записанные в отдельных проектах, и проекты не будут «полностью независимыми», как вы хотели. Следовательно, скрипт для динамического построения символических ссылок.

Я думаю, что этот подход может мешать git нежелательным образом, так как мы выбрали пути, где он ожидает найти что-то одно, и вместо этого поместили что-то другое. Может быть, мы могли бы .gitignore пути символической ссылки. Но теперь мы дважды пишем эти пути и нарушаем СУХОЙ. На данный момент мы также довольно далеко от притворства использовать подмодули. Мы можем записать зависимости в другом месте каждого проекта и оставить файл .gitmodules для того, что ожидает git. Итак, мы создадим наш собственный файл, скажем, .dependencies, и каждый проект может указать там свои зависимости. Наш скрипт тут же будет искать и создавать свои символические ссылки.

Хм, думаю, я только что описал специальную систему управления пакетами с собственным облегченным форматом пакетов:)

Мне кажется, что предложение megamic хорошо подходит для использования подмодулей git. Мы имеем дело только с отслеживанием набора здесь, а не графика, и набор легко вписывается в дерево. Дерево глубиной в один уровень по сути является родительским узлом и набором дочерних узлов.

Как вы указали, это не полностью решает проблему, указанную в вашем вопросе. Мы можем выделить два разных типа информации «это работает с нами», в которой мы, вероятно, заинтересованы: 1. Заявление из версии проекта (предположительно автором проекта), в котором говорится: «Мне нужна версия X проекта Y» 2. Заявление, используемое вашей собственной установкой сборки: «Я успешно протестировал всю нашу систему, используя этот набор версий проекта»

ответ megamic решен (2), но для (1) мы все еще хотим, чтобы проекты сообщали нам, каковы их зависимости. Затем мы можем использовать информацию из (1) для вычисления тех наборов версий, которые мы в итоге запишем как (2). Это достаточно сложная проблема, чтобы гарантировать собственный инструмент, который возвращает нас к системам управления пакетами:)

Насколько я знаю, большинство хороших инструментов управления пакетами созданы для пользователей определенного языка или операционной системы. Смотрите Bundler для пакетов 'gem' в мире ruby ​​и подходите для пакетов '.deb' в мире Debian.

Если кто-нибудь знает хорошее, не зависящее от языка, не зависящее от ОС решение для этого, которое хорошо подходит для программных проектов «полиглот» (http://blog.heroku.com/archives/2011/8/3/polyglot_platform/), я был бы очень заинтересован! Я должен опубликовать это как вопрос.

2 голосов
/ 22 апреля 2012

Небольшая служебная задача, превращающая общие подмодули в клонов с использованием жестких ссылок, может работать.

Вы можете прочитать мое полное решение здесь: https://stackoverflow.com/a/10265084/84283

2 голосов
/ 09 февраля 2012

Я думаю, что вы можете управлять согласованностью следующим образом: определите «ссылочную» ветвь или серию тегов с одинаковыми именами во всех ваших «базовых» библиотеках (примечание: в вашем примере есть только одна «базовая» библиотека) ). Затем поручите разработчикам подпроектов (A, B, ...) регулярно обновляться до базовой версии «Core», как только они смогут.

Перед запуском сборки легко убедитесь, что «Ядра» последовательно используются в А, В, С, ..., выполнив эти три команды в чистой, рекурсивной «Супер» проверке верхнего уровня:

# 1.  Switch to the reference version (= "Force" consistency where need be)
git submodule foreach --recursive 'git checkout [origin/]reference || true'

# 2a. Show which inconsistencies you just forced; terse output
git status -s; git submodule foreach --recursive git status -s 2>/dev/null

# 2b. Same but verbose output
git submodule; git submodule foreach --recursive git submodule

# 3. Switch back to versions individually defined by sub-projects 
git submodule update --recursive

Команда 2a «Краткий вывод» выше показывает, какие подпроекты не используют «базовую» версию Core.

Вы можете легко расширить подход, чтобы показывать различия, форсировать обновления или делать любые другие вещи, которые вам нравятся.

0 голосов
/ 14 сентября 2009

Я бы не пытался сопоставлять дерево зависимостей с подмодулями - по причинам, которые вы уже обнаружили.

Субмодули отслеживают данную ревизию данной ветки, поэтому они полезны для создания моментального снимка согласованного набора модулей.

Итак, если ваш проект требует, чтобы определенный набор версий различных модулей отслеживался как одно целое, вы можете сгруппировать их вместе как подмодули. Затем вы можете пометить разные наборы модулей в разных версиях, чтобы получить историю проекта, где каждый тег показывает, какие версии каких модулей были совместимы в определенный момент времени.

 tags/
     release1/ 
           |-> A@1.0
           |-> B@1.1
           |-> C@1.2
     release2/
           |-> A@2.0
           |-> B@1.3
           |-> C@1.5

По крайней мере, так, как я их понимаю, хотя, как и большинство вещей с Git, возможно, в этом есть гораздо больше, чем это. Что касается управления зависимостями, все, что я могу сказать, - это найти другой путь, это не то, для чего Git с или без субмодулей был разработан, насколько я понимаю.

...