Поиск по сайту:

Как использовать поддерево Git для управления несколькими репозиториями проектов


Программисты часто повторно используют код. На самом деле, это один из основных принципов любой хорошей кодовой базы — «Не повторяйся» (DRY). Что делать, если вы хотите использовать общий проект внутри нескольких других репозиториев? Команда git subtree может помочь в этом.

Проблема повторного использования кода

Встраивание проектов в другие проекты представляет проблему; Проект 1 и проект 2 подключены к Git, но прямое использование общего подпроекта для них обоих — не лучший вариант дизайна. По сути, это разветвление подпроекта для его использования в двух местах, и будет невозможно поддерживать официальную версию подпроекта.

Есть несколько решений этой проблемы, каждое со своими недостатками.

Во-первых, самое очевидное решение — превратить подпроект в пакет и распространить его в диспетчере пакетов, таком как NPM или NuGet. Это очень хорошо работает для вещей, которые не часто обновляются или обслуживаются, и могут позволить себе распространять их среди своих потребителей в незаметных номерах версий. Однако, если вы регулярно меняете этот код, необходимость интегрировать, публиковать и извлекать новые версии проекта из стороннего источника просто не работает, а также прямой доступ к коду. Это также вводит сложности для местного развития.

Другое решение — использовать monorepo, один гигантский репозиторий для всего вашего кода. Это не так безумно, как вы думаете, и хорошо работает, если весь ваш код находится в одном домене; Google использует монорепозиторий для всего своего кода, а Microsoft использует его для всех поддерживаемых ими сборок .NET. Это решает проблему, потому что если вы измените код в подпроекте, он будет обновляться всякий раз, когда вы будете пересобирать. В Visual Studio это можно легко сделать с помощью ссылок на проекты.

Однако во многих случаях вы хотели бы получить лучшее из обоих миров — поддерживать его централизованно в виде пакета, но также разрешать прямое встраивание и редактирование в нескольких проектах. Для этого Git Subtree предоставляет решение.

Основная концепция довольно проста: у вас могут быть меньшие репозитории Git, а их основной поток связан с подрепозиторием, но встроенный в другой проект. Все изменения для проекта 1, проекта 2 и подпроекта отслеживаются в их собственных репозиториях.

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

Настройка поддерева Git

Если вы только что настроили пустой проект и собираетесь настроить поддеревья, вам нужно будет сделать первоначальную фиксацию, даже если она пуста, иначе Git выдаст ошибку о неоднозначном HEAD. Вы можете сделать пустой коммит с помощью следующей команды:

git commit --allow-empty -n -m "Initial commit."

Вы захотите добавить пульт для подпроекта и дать ему имя. Вы будете использовать это имя для ссылки на него:

git remote add -f SubTreeName https://github.com/user/project.git

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

git subtree add --prefix .Path/To/SubTree SubTreeName master --squash

Использование поддерева Git

Когда вам нужно извлечь, Git автоматически обновит только основной проект, поэтому вам придется получить удаленный проект, а затем использовать команду извлечения для конкретного поддерева. Это немного длинно, так как вам нужно передать префикс, но выполняет свою работу:

git fetch SubTreeName master
git subtree pull --prefix .Path/To/SubTree SubTreeName SubTreeName master --squash

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

Когда придет время внести свой вклад в восходящий поток, вам нужно будет использовать git subtree push:

git subtree push --prefix=.Path/To/SubTree SubTreeName master