Git Subtree
Как уже упоминалось на нашей предыдущей странице, Git Submodule полезен для определённых случаев. Для отслеживания зависимостей программного обеспечения многие разработчики предпочитают Git Subtree.
Что такое Git Subtree
Git Subtree — это альтернатива Git Submodule. Он позволяет вкладывать один репозиторий в другой в виде подкаталога. Это один из способов отслеживать историю зависимостей программного обеспечения. Но subtree не следует путать с submodule. В отличие от submodule, subtree не требуют файлов .gitmodules или gitlink'ов в репозитории. Subtree — это просто подкаталог, в который можно коммитить, создавать ветки и выполнять слияния вместе с вашим проектом.
Зачем использовать Git Subtree
Плюсы
- Поддерживается Git 1.7.10 и более поздними версиями.
- Простое управление рабочим процессом.
- Код подпроекта доступен после завершения суперпроекта.
- Для использования
git subtreeне требуется новых знаний Git. - Не добавляет новых файлов метаданных (например,
.gitmodules). - Позволяет изменять содержимое без отдельной копии репозитория зависимости.
Минусы
- Требуется изучить новую стратегию слияния.
- Сложный процесс внесения изменений обратно в upstream для подпроектов.
- Код суперпроекта и подпроекта смешан в одном репозитории.
Как использовать Git Subtrees
Предположим, что есть внешний проект, и вы хотите добавить его в свой репозиторий.
Например, чтобы добавить расширение vim в репозиторий, где хранится ваша настройка vim, выполните следующее:
git subtree add --prefix .vim/bundle/example https://github.com/Example/vim-example.git master --squashЭто свернёт всю историю проекта vim-example в вашу папку .vim/bundle/example, записав SHA-1 ветки master на тот момент для будущего использования. В результате будут выведены следующие два коммита:
commit 6d7054b3acea64e2e31f4d6fb2e3be12e5865e87
Merge: 87fa91e ef86deb
Author: Ann Smith<[email protected]m>
Date: Tue Jun 10 13:37:03 2016 +0200
Merge commit 'fe67ddf158faccff4082d78a25c45d8cd93e8ba8' as '.vim/bundle/example'
commit fe67ddf158faccff4082d78a25c45d8cd93e8ba8
Author: Ann Smith<[email protected]m>
Date: Tue May 12 13:37:03 2015 +0200
Squashed '.vim/bundle/example/' content from commit b999b09
git-subtree-dir: .vim/bundle/example
git-subtree-split: b999b09cd9d69f359fa5668e81b09dcfde455ccaЧтобы обновить подпапку до последней версии дочернего репозитория, выполните следующее:
git subtree pull --prefix .vim/bundle/example https://github.com/Example/vim-example.git master --squashОднако git subtree хранит идентификаторы коммитов подпроекта, а не ссылки в метаданных. Найдите символическое имя, связанное с коммитом:
git ls-remote https://github.com/Example/vim-example.git | grep <commit-sha>Замените <commit-sha> на фактический хеш коммита.
Перебазирование после Git Subtree
Чтобы выполнить перебазирование репозитория, содержащего subtree, используйте режим --interactive команды git rebase. Вы можете удалить или свернуть merge-коммиты subtree, а затем выполнить git rebase --continue. Учтите, что переписывание истории требует повторного выполнения git subtree add или git subtree pull после этого. Имейте в виду, что переписывание истории может вызвать конфликты слияния при перебазировании subtree, поскольку структура коммитов изменяется.
OPTIONS
| -q, --quiet | Подавляет ненужные сообщения о результате в stderr. |
|---|---|
| -d, --debug | Выводит дополнительные отладочные сообщения в stderr. |
-P <prefix>, --prefix=<prefix> | Определяет путь в репозитории к subtree, которым вы хотите управлять. Это обязательно для всех команд. |
-m <message>, --message=<message> | Указывает <message> как сообщение коммита для merge-коммита. Действительно только для add, merge и pull. |
Использование Git Subtree без отслеживания удалённого репозитория
Добавьте git subtree в указанную папку prefix. Используйте флаг --squash, чтобы сохранить всю историю подпроекта в основном репозитории:
git subtree add --prefix .vim/bundle/vim-double-upon https://hostname.org/example/vim-plugins.git master --squashКоманда выполняет fetch и сворачивает историю. Обычно вывод показывает ход fetch, а затем подтверждение добавления:
git fetch https://hostname.org/example/vim-plugins.git master
warning: no common commits
remote: Counting objects: 325, done.
remote: Compressing objects: 100% (145/145), done.
remote: Total 325 (delta 101), reused 313 (delta 89)
Receiving objects: 100% (325/325), 61.47 KiB, done.
Resolving deltas: 100% (110/110), done.
From https://hostname.org/vim-plugins.git
* branch master -> FETCH_HEAD
Added dir '.vim/bundle/vim-double-upon'Это создаёт merge-коммит, сворачивая всю историю подпроекта в один:
3bca0ad [4 minutes ago] (HEAD, stree) Merge commit 'fa2f5dc4f1b94356bca8a440c786a94f75dc0a45' as '.vim/bundle/vim-double-upon' [John Brown]
fa2f5dc [4 minutes ago] Squashed '.vim/bundle/vim-double-upon/' content from commit 13189ec [John Brown]Чтобы обновить код плагина из upstream-репозитория, выполните git subtree pull:
git subtree pull --prefix .vim/bundle/vim-double-upon https://hostname.org/example/vim-plugins.git master --squashЧтобы внести изменения обратно в upstream-репозиторий, извлеките историю subtree с помощью git subtree split:
git subtree split --prefix .vim/bundle/vim-double-upon -b split-branch
git push split-branchЭто создаёт новую ветку, содержащую только историю subtree, которую затем можно отправить в upstream-репозиторий.
Чтобы сделать команды короче, добавьте подпроект как удалённый репозиторий.
Добавление подпроекта как удалённого репозитория
Добавление как remote сокращает процесс:
git remote add -f vim-double-upon https://hostname.org/example/vim-plugins.gitДобавьте subtree:
git subtree add --prefix .vim/bundle/vim-double-upon vim-double-upon master --squashОбновите подпроект так:
git fetch vim-double-upon master
git subtree pull --prefix .vim/bundle/vim-double-upon vim-double-upon master --squashGit Subtree — это альтернатива submodule. В то время как submodule помещают другой проект в каталог и синхронизируют удалённый репозиторий, Git Subtree хранит подпроект как обычный каталог. Внесение изменений обратно в upstream-репозиторий требует использования git subtree split для извлечения истории подпроекта, поскольку прямая двусторонняя синхронизация нативно не поддерживается.
Practice
What are the features and usage of Git subtree?