Подмодули: основные идеи, рабочие процессы и советы
Николя Паолуччи
Консультант по разработке
Использование подмодулей при разработке в Git позволяет включать в базу кода другие проекты: их история хранится в отдельном месте, но синхронизируется с вашей. Это удобный способ решения проблем с зависимостями и библиотеками от поставщиков. Как и в случае со многими другими вопросами, касающимися git
, насчет этого подхода есть разные мнения. Чтобы умело им пользоваться, нужно немного его изучить. О подмодулях и так уже полным-полно хорошей, подробной
информации, поэтому пересказывать ее я не буду. Вместо этого я поделюсь кое-какими интересными приемами, позволяющими использовать эту функцию максимально эффективно.
Содержание
Связанные материалы
Перемещение полного репозитория Git
СМ. РЕШЕНИЕ
Изучите Git с помощью Bitbucket Cloud
Основная идея
Для начала кратко объясню главную особенность подмодулей, чтобы вам проще было с ними работать.
Подмодули отслеживаются по отдельному коммиту, указанному в родительском проекте, а не по ветке, ссылке или какой-либо другой символьной отсылке.
Они никогда не обновляются автоматически при обновлении репозитория, указанного в подмодуле, — только при обновлении самого родительского проекта. В упомянутой ранее главе Pro Git об этом сказано очень четко:
Когда вы вносите изменения и делаете коммиты в подкаталог [подмодуля], в вышестоящем проекте отмечается, что указатель HEAD изменился, и записывается тот коммит, над которым вы работаете в данный момент; таким образом, когда другие клонируют этот проект, они могут точно воссоздать это окружение.
Или другими словами:
[…] подмодули git […] статичны. Очень статичны. С помощью подмодулей отслеживаются отдельные коммиты git. Не ветки, не ссылки — один-единственный коммит. Добавьте коммиты в подмодуль — в родительском проекте об этом не узнают. Понаделайте форков для модуля — подмодуля git это никак не коснется. У вас есть отдельный удаленный репозиторий, в котором вы указываете на отдельный коммит. Пока вы не обновите родительский проект, ничего не изменится.
Возможные рабочие процессы
В свете этой особенности становится очевидно, что для одних рабочих процессов подмодули
подходят хорошо, а для других плохо. Можно предложить как минимум три сценария, в которых подмодули станут разумным выбором:
-
Компонент или подпроект изменяются слишком быстро, или предстоящие изменения могут нарушить работу API. В этом случае можно заблокировать код для конкретного коммита в целях безопасности.
-
У вас есть компонент, который обновляется довольно редко, и вы хотите отслеживать его в качестве зависимости поставщика (например, я поступаю так со своими плагинами vim).
-
Вы делегируете выполнение части проекта другим лицам и хотите интегрировать их работу в определенное время или в конкретном релизе. Это полезно только в том случае, когда обновления происходят не слишком часто.
Спасибо finch за хорошее объяснение этих сценариев.
А теперь — полезные советы
Мощная инфраструктура подмодулей позволяет эффективно разделять и интегрировать базы кода. Однако для некоторых простых операций нет удобных процедур или хорошей поддержки пользовательского интерфейса командной строки.
Если вы используете подмодули git в своем проекте, вы либо уже сталкивались с такими операциями, либо еще столкнетесь и будете вынуждены снова и снова искать решение. Давайте я сэкономлю вам немного времени на поисках: добавьте эту страницу с помощью Instapaper, Evernote или старых добрых закладок в браузере (:D:D) — ее вам хватит надолго.
Итак, вот что я для вас подготовил.
Как заменить подмодуль git собственным форком
Бывает, вы начинаете использовать чей-то проект в качестве подмодуля, а через некоторое время обнаруживаете, что его надо немного переиначить и настроить под себя, то есть вам нужно сделать форк этого проекта и заменить им подмодуль. Как это делается?
Подмодули хранятся в файле .gitmodules
:
$ cat .gitmodules [submodule "ext/google-maps"] path = ext/google-maps url = git://git.naquadah.org/google-maps.git
Достаточно отредактировать URL-адрес в текстовом редакторе, а затем выполнить следующую команду:
$ git submodule sync
Она обновит файл .git/config
, который содержит копию этого списка подмодулей (можно и просто отредактировать соответствующий раздел [submodule]
в .git/config
вручную).
Как удалить подмодуль?
Это требуется довольно часто, а процедура несколько запутанная. Чтобы удалить подмодуль:
1. Удалите соответствующую строку из файла .gitmodules
.
2. Удалите соответствующий раздел из файла .git/config
.
3. Выполните команду git rm --cached путь_к_подмодулю
(без завершающей косой черты).
4. Сделайте коммит и удалите теперь не отслеживаемые файлы подмодулей.
Как снова интегрировать подмодуль в проект?
Другими словами, как из подмодуля git сделать не подмодуль? Если вам нужно просто поместить его код в основной репозиторий, достаточно удалить упоминание подмодуля и заново добавить его файлы:
1. Удалите ссылку на подмодуль из индекса, но сохраните файлы:
git rm --cached submodule_path (no trailing slash)
2. Удалите файл .gitmodules или, если у вас остались другие подмодули, отредактируйте его, удалив нужный подмодуль из списка:
git rm .gitmodules
3. Удалите папку метаданных .git (не забудьте создать ее резервную копию):
rm -rf submodule_path/.git
4. Добавьте подмодуль
в индекс основного репозитория:
git add submodule_path git commit -m "remove submodule"
ПРИМЕЧАНИЕ. Описанная выше процедура уничтожает историю подмодуля. Если вы хотите сохранить для подмодулей согласованную историю, потребуются более затейливые действия с командой merge. Дополнительную информацию можно найти в этом досконально разобранном вопросе на Stack Overflow.
Как игнорировать изменения в подмодулях
Иногда подмодули
могут создавать изменения
сами по себе. Например, если вы используете подмодули
Git для отслеживания плагинов vim, они могут создавать или изменять локальные файлы, такие как справочные теги (helptags
). К сожалению, команда git status будет подсовывать вам эти изменения, даже если они совсем вас не интересуют и вы не собираетесь вносить их в коммит.
Решить эту проблему очень просто. Откройте файл .gitmodules
в корневом каталоге репозитория и добавьте ignore = dirty
для каждого подмодуля, который нужно игнорировать, например:
[submodule ".vim/bundle/msanders-snipmate"] path = .vim/bundle/msanders-snipmate url = git://github.com/msanders/snipmate.vim.git ignore = dirty
Спасибо Нильсу за отличное объяснение.
Опасная зона! Подводные камни при работе с удаленными репозиториями
Как нам напоминают в руководстве по подмодулям Git на kernel.org, при работе с удаленными репозиториями необходимо учитывать несколько важных моментов.
Во-первых, всегда публикуйте изменения подмодуля перед публикацией изменений в вышестоящем проекте, который ссылается на него. Это очень важно, поскольку в противном случае у других пользователей могут возникнуть проблемы с клонированием репозитория.
Во-вторых, обязательно делайте коммит всех изменений перед выполнением команды git submodule update
, поскольку она перезаписывает имеющиеся изменения!
Заключение
Вооружившись этими заметками, вы справитесь со многими рабочими процессами, часто возникающими при использовании подмодулей. В следующей статье я напишу об альтернативах команде git submodule
.
Подпишитесь на меня (@durdn) и замечательную команду @Bitbucket, чтобы осваивать новые навыки работы с распределенными системами управления версиями.
Поделитесь этой статьей
Следующая тема
Рекомендуемые статьи
Добавьте эти ресурсы в закладки, чтобы изучить типы команд DevOps или получать регулярные обновления по DevOps в Atlassian.