Git: Как отделить библиотеку от проекта? фильтр-ветвь, поддерево?
Итак, у меня есть проект с более крупным (закрытый исходный код), и в контексте этого проекта я создаю библиотеку, которая также может быть полезной в других местах. Я полагаю, что
Теперь я хочу отделить библиотеку от своего собственного проекта, который может стать открытым исходным кодом на github или аналогичном. Конечно, библиотека (и ее история там) не должна содержать следов нашего проекта.
git -subtree кажется здесь решением, но он не подходит.
Мой макет каталога похож на этот (так как это проект Java):
- фехтование (git workdir)
- ЦСИ
- де
- fencing_game
- транспорт (моя библиотека)
- протокол (часть библиотеки)
- фехтование (часть основного проекта, связанного с библиотекой)
- клиент (часть основного проекта, связанного с библиотекой)
- сервер (часть основного проекта, связанного с библиотекой)
- клиент (часть основного проекта)
- сервер (часть основного проекта)
- ... (часть основного проекта)
- другие файлы и каталоги (система сборки, веб-сайт и т.д. - часть основного проекта)
После разделения я хочу, чтобы макет каталога библиотеки выглядел так (включая любые файлы непосредственно в жирных каталогах):
- my-library (имя будет определено)
- ЦСИ
- де
- fencing_game
- транспорт (моя библиотека)
- протокол (часть библиотеки)
История также должна содержать только часть основной истории проекта, которая затрагивает эту часть репозитория.
Первый взгляд показал мне git-subtree split --prefix=src/de/fencing_ame/transport
, но это будет
- дайте мне дерево, внедренное в
transport
(которое не будет компилироваться) и
- включают каталоги
transport/client
, transport/server
и transport/fencing
.
Первая точка может быть уменьшена с помощью git subtree add --prefix=src/de/fencing_ame/transport <commit>
на принимающей стороне, но я не думаю, что git -subtree может многое сделать против экспорта также этих подкаталогов. (Идея состоит в том, чтобы просто иметь возможность делиться полным деревом здесь).
Нужно ли здесь использовать git filter-branch
?
После разделения я хочу иметь возможность импортировать библиотеку в свой основной проект, используя git -subtree или git -submodule в отдельном подкаталоге, а не там, где он сейчас. Я представляю макет таким образом
- фехтование (git workdir)
- ЦСИ
- де
- fencing_game
- транспорт (пустой)
- фехтование (часть основного проекта, связанного с библиотекой)
- клиент (часть основного проекта, связанного с библиотекой)
- сервер (часть основного проекта, связанного с библиотекой)
- клиент (часть основного проекта)
- сервер (часть основного проекта)
- ... (часть основного проекта)
- моя библиотека
- ЦСИ
- де
- fencing_game
- транспорт (моя библиотека)
- протокол (часть библиотеки)
- другие файлы и каталоги (система сборки, веб-сайт и т.д. - часть основного проекта)
Что было бы самым безболезненным способом сделать это? Существуют ли другие инструменты, чем git -subtree и git -filter-branch для этой цели?
Ответы
Ответ 1
Я думаю, что у вас есть реальный спелеолог. Если вы просто хотите отделить "протокол", вы можете сделать это с помощью "git разделов поддерева..." или "git filter-branch..."
git filter-branch --subdirectory-filter
fencing-game/src/de/fencing_game/transport/protocol -- --all
Но если у вас есть файлы на транспорте, а также транспорт/протокол, он начинает становиться волосатым.
Я написал несколько специальных инструментов, чтобы сделать это для проекта, в котором я был. Они нигде не публикуются, но вы можете сделать что-то подобное с reposurgeon.
Ответ 2
Разделение поддерева, смешанного с файлами из родительского проекта
Это, кажется, общий запрос, однако я не думаю, что существует простой ответ, когда папки смешаны вместе.
Общий метод, который я предлагаю разделить библиотеку, смешанную с другими папками, таков:
-
Создайте ветку с новым корнем для библиотеки:
git subtree split -P src/de/fencing_game -b temp-br
git checkout temp-br
# -or-, if you really want to keep the full path:
git checkout -b temp-br
cd src/de/fencing_game
-
Затем используйте что-то, чтобы перезаписать историю, чтобы удалить части, которые не являются частью библиотеки. Я не эксперт в этом, но я смог экспериментировать и нашел что-то вроде этого:
git filter-branch --tag-name-filter cat --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch client server otherstuff' HEAD
# also clear out stuff from the sub dir
cd transport
git filter-branch --tag-name-filter cat --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch fencing client server' HEAD
Примечание. Возможно, вам потребуется удалить резервную копию, созданную ветвью фильтра между последовательными командами.
git update-ref -d refs/original/refs/heads/temp-br
-
Наконец, просто создайте новое репо для библиотеки и потяните все, что осталось:
cd <new-lib-repo>
git init
git pull <original-repo> temp-br
Я рекомендую, чтобы ваш конечный путь библиотеки был больше похож на /transport/protocol
вместо полного пути родительского проекта, поскольку это похоже на привязку к проекту.
Ответ 3
Проблема здесь в том, что нет хорошего разделения того, что есть и не является частью вашей библиотеки. Я бы настоятельно рекомендовал, чтобы решение было реорганизовано, а затем вы можете просто включить библиотеку в качестве подмодуля.
Если повторное использование этой библиотеки будет только в том же репо другими разработчиками, просто отслеживайте эти изменения на отдельной ветке и не беспокойтесь о дополнительных репозиториях.
Ответ 4
Будет ли история проекта быть только для вашей выгоды или для людей на github?
Если история только для вашей выгоды, есть простой способ использования трансплантатов. В принципе, просто создайте новый репозиторий для github, удалив все проприетарный код. Теперь у вас есть репозиторий с открытым исходным кодом с открытым кодом, который вы можете нажать на github. В вашей локальной копии репозитория с открытым исходным кодом вы можете перенести историю с собственного репо на репозиторий с открытым исходным кодом.
Выполнение этого способа означает, что вы (или любой, у кого есть доступ к собственному репо), имеют возможность увидеть полную историю, но широкая публика увидит код только с того момента, когда вы открываете его.
Что такое .git/info/grafts для?
Ответ 5
Я сделал что-то подобное, но разделил несколько разделов вещей на совершенно отдельный репо на зашифрованном разделе (/secure/tmp/newrepo), поэтому они не были доступны для вора ноутбука.
Я написал оболочку script, а затем сделал:
git filter-branch --tree-filter '~/bin/tryit/secure/tmp/newrepo личное личное' - 95768021ff00216855868d12556137115b2789610..HEAD(SHA избегает коммитов до того, как какой-либо каталог выйдет из строя)
#!/bin/sh
# to be used with e.g:
# git filter-branch --tree-filter '~/bin/tryit /secure/tmp/newrepo personal private'
# Don't do it on any repository you can't repeatedly do:
# rm -rf foo ; git clone /wherever/is/foo
# when it breaks
SRC=`pwd`
DEST=$1
shift
MSG=/dev/shm/msg.txt
TAR=/dev/shm/tmp.tar
LIST=/dev/shm/list.txt
LOG=/dev/shm/log
DONE=''
echo $GIT_AUTHOR_DATE >> $LOG
git show --raw $GIT_COMMIT > $MSG
for A in $*
do
if [ -d $A ]
then
DONE=${DONE}x
tar -cf $TAR $A
tar -tf $TAR > ${LIST}
cat ${LIST} >> ${LOG}
rm -rf ${A}
cd ${DEST}
tar -xf $TAR
else
echo $A non-existant >> ${LOG}
fi
cd $SRC
done
if [ -z "${DONE}" ]
then
echo Empty >>$LOG
else
cd ${DEST}
unset GIT_INDEX_FILE
unset GIT_DIR
unset GIT_COMMIT
unset GIT_WORK_TREE
touch foo
git add .
git commit -a -F ${MSG} >> ${LOG}
fi
exit 0
Для ваших целей вы, вероятно, захотите иметь другую спецификацию для tar (например, --exclude =), а затем использовать cat ${LIST} | xargs rm, чтобы удалить материал только в tar, но, надеясь, это не слишком сложно.
Неисправный материал и выход 0 важны, поскольку ветвь фильтра устанавливает их в исходное репо (не то, что вы хотите!), и умрет, если sh передает ненужный код выхода из последней команды в вашем script.