Git поддерево и несколько каталогов
У меня есть довольно большой репозиторий git, в котором есть каталог, в котором я поддерживаю библиотечный код. Каталог содержит несколько подкаталогов.
repo
+--- lib
| +--- A
| +--- B
...
| +--- Z
Теперь предположим, что я хочу открыть исходные подкаталоги A,...,M
и сохранить подкаталоги N,...,Z
close sourced. Предположим также, что я хотел бы:
- Храните
A,...,M
в одном хранилище с открытым исходным кодом. Причина этого в том, что каталоги A,...,M
имеют взаимозависимости, и было бы путать их разделить на отдельные репозитории.
- Сохранять структуру моего закрытого хранилища источника. Например, я мог бы создавать подкаталоги
lib/pub
и lib/pvt
, но это имело бы каскадные эффекты, требующие изменения ссылок в другом месте или потребовало бы много символических ссылок (lib/A -> lib/pub/A
).
- У меня есть решение, похожее на
git subtree
, где я могу модифицировать код либо в моем закрытом исходном репозитории, либо в открытом исходном коде, и я могу легко синхронизировать изменения между двумя репозиториями.
Я искал решение как в stackoverflow, так и в google, но, похоже, не существует очевидного. Концептуально это то, что git subtree
должно быть в состоянии сделать, но оно работает только с одним подкаталогом.
Я просмотрел git-subtree
script с целью его изменения.
https://github.com/git/git/blob/master/contrib/subtree/git-subtree.sh
Мне кажется, что если я должен был изменить subtree_for_commit()
, я должен был бы убедить git subtree split
рассматривать больше, чем один каталог для разделения. Но моих знаний о git недостаточно, чтобы понять, что делает script, и изменять его, не нарушая ничего.
Если у вас есть решение для вышеупомянутой проблемы или любых других указателей при модификации git-subtree
, пожалуйста, дайте мне знать.
Ответы
Ответ 1
Разделение поддерева, смешанного с файлами из родительского проекта
Это, кажется, общий запрос, однако я не думаю, что существует простой ответ, когда папки смешаны вместе.
Общий метод, который я предлагаю разделить библиотеку, смешанную с другими папками, таков:
-
Создайте ветку с новым корнем для каталогов библиотек:
git subtree split -P lib/ -b temp-br
git checkout temp-br
-
Затем используйте что-то, чтобы перезаписать историю, чтобы удалить части, которые не являются частью библиотеки. Я не эксперт в этом, но я смог экспериментировать и нашел что-то вроде этого:
git filter-branch --tag-name-filter cat --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch N O P Q R S T U V W X Y Z' HEAD
Примечание. Возможно, вам придется удалить резервную копию, созданную ветвью фильтра, если вы выполните последовательные команды.
git update-ref -d refs/original/refs/heads/temp-br
-
Наконец, просто создайте новое репо для библиотеки и потяните все, что осталось:
cd <new-lib-repo>
git init
git pull <original-repo> temp-br
Ответ 2
Вот сценарий оболочки, основанный на git subtree
, он намного быстрее, чем решения, основанные на git filter-branch --tree-filter
; его побочный эффект - это несколько дополнительных коммитов git mv
и git merge
, которые будут добавлены к финальному HEAD
. Если вы согласны с этими дополнительными пустыми коммитами, попробуйте:
ids=0
lists=(\
"a/b" \
"c/d/e" \
)
# subtree each path
for dir in ${lists[@]}
do
echo git subtree split -P $dir -b split_dir_$ids
git subtree split -P $dir -b split_dir_$ids
((ids++))
done
# restore folder structure
for (( idx=0; idx < ${#lists[@]}; idx++ ))
do
git checkout split_dir_$idx
dir=${lists[$idx]}
mkdir -p $dir
dirPrefix=${$dir%%/*}
find . -maxdepth 1 ! -name $dirPrefix -and ! -name '\.*' \
-exec git mv {} $dir \;
done
# merge
git checkout split_dir_0
for (( idx=1; idx < ${#lists[@]}; idx++ ))
do
git merge -q split_dir_$idx
done
git push -u 'target remote' 'target branch'
Ответ 3
Используйте git subtree add
Смотрите Поддерево Git, разделяющее две директории, я думаю, что вы можете использовать эту технику для более чем двух каталогов, даже для нескольких репозиториев, т.е.
cd /repos/big-repo
# split out A..M branches
for N in {A..M}; do
git subtree split --prefix=lib/$N --branch=split-$N
done
# create new repo
mkdir /repos/am-repo
cd /repos/am-repo
git init
# commit something or git-subtree add will complain and fail
touch .gitignore; git add .; git commit -m "begin history revision"
# split-in A..M branches
for N in {A..M}; do
git subtree add --prefix=lib/$N ../big-repo split-$N
done
Ответ 4
Когда у вас есть как подкаталоги, так и файлы в каталоге src, вы хотите разбить на отдельный репозиторий, который позже станет подмодулем, ответов было мало. Предположим, вы хотите, чтобы dir2 и file2 переместились в новую репо srcpublic, а затем в исходное репо,
git mv src/file2 src/dir2; git разделение поддерева -P dir2 -b branch_dir2
В новом репо, поддерево pull/dir2 branch_dir2; git mv dir2/file2../
Новое репо:
srcpublic - file2, dir2
Оригинальное репо:
src - file1, file2, dir1, dir2
Когда есть десятки папок и файлов, это помогает помещать команды в script.