git: Как отделить библиотеку от проекта?фильтр-ветка, поддерево? - PullRequest
23 голосов
/ 19 июня 2011

Итак, у меня большой проект (с закрытым исходным кодом), и в контексте этого проекта я создал библиотеку, которая также может быть полезна в других местах.

Теперь я хочу разделить библиотеку в своем собственном проекте, который мог бы стать открытым исходным кодом на github или подобном. Конечно, библиотека (и ее история там) не должна содержать следов нашего проекта.

git-subtree кажется здесь решением, но оно не совсем подходит.

Моя структура каталогов выглядит примерно так (поскольку это проект Java):

  • фехтовальная игра (git workdir)
    • ЦСИ
      • де
        • fencing_game
          • транспорт (моя библиотека)
            • протокол (часть библиотеки)
            • Ограждение (часть основного проекта, взаимодействующего с библиотекой)
            • клиент (часть основного проекта, взаимодействующего с библиотекой)
            • сервер (часть основного проекта, взаимодействующая с библиотекой)
          • клиент (часть основного проекта)
          • сервер (часть основного проекта)
          • ... (часть основного проекта)
    • другие файлы и каталоги (система сборки, сайт и т. П. - часть основного проекта)

После разделения я хочу, чтобы макет каталога библиотеки выглядел следующим образом (включая любые файлы непосредственно в полужирных каталогах):

  • my-library (имя будет уточнено)
    • ЦСИ
      • де
        • fencing_game
          • транспорт (моя библиотека)
            • протокол (часть библиотеки)

История также должна содержать только часть истории основного проекта, которая касается этой части хранилища.

Первый взгляд показал мне git-subtree split --prefix=src/de/fencing_ame/transport, но это будет

  1. дайте мне дерево с корнями в transport (которое не будет компилироваться) и
  2. включает каталоги 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 для этой цели?

Ответы [ 5 ]

3 голосов
/ 07 марта 2014

Разделение поддерева, смешанного с файлами из родительского проекта

Это, кажется, распространенный запрос, однако я не думаю, что есть простой ответ,когда папки смешиваются вместе, как это.

Общий метод, который я предлагаю выделить из библиотеки, смешанной с другими папками, таков:

  1. Создать ветку с новым корнем для библиотеки:

    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
    
  2. Затем используйте что-нибудь, чтобы переписать историю, чтобы удалить части, которые не являются частью библиотеки.Я не эксперт в этом, но я смог поэкспериментировать и нашел что-то вроде этого:

    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
    
  3. Наконец, просто создайте новое хранилище для библиотеки и извлеките все, что осталось:

    cd <new-lib-repo>
    git init
    git pull <original-repo> temp-br
    

Я рекомендуюваш окончательный путь к библиотеке будет больше похож на /transport/protocol, а не на полный путь родительского проекта, так как он как бы связан с проектом.

3 голосов
/ 20 сентября 2011

Я думаю, у тебя есть кое-что на самом деле. Если вы просто хотите отделить «протокол», вы можете сделать это с помощью «git subtree split ...» или «git filter-branch ...»

git filter-branch --subdirectory-filter fencing-game/src/de/fencing_game/transport/protocol -- --all

Но если у вас есть файлы как в транспортном, так и в транспортном протоколе / протоколе, он начинает становиться волосатым.

Я написал несколько пользовательских инструментов, чтобы сделать это для проекта, над которым я работал. Они нигде не публикуются, но вы можете сделать нечто подобное с reposurgeon .

2 голосов
/ 19 июня 2011

Проблема здесь в том, что нет хорошего разделения того, что является и не является частью вашей библиотеки. Я настоятельно рекомендую реорганизовать решение, и тогда вы можете просто включить библиотеку в качестве подмодуля.

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

1 голос
/ 04 января 2012

Я сделал нечто похожее, но разделил несколько каталогов на совершенно отдельный репо на зашифрованном разделе (/ secure / tmp / newrepo), чтобы они не были доступны для воров ноутбуков. Я написал сценарий оболочки, а затем сделал: git filter-branch --tree-filter '~ / bin / tryit / secure / tmp / newrepo personal private' - 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 передаст ненулевой код выхода из последней команды в вашем скрипте.

1 голос
/ 19 июня 2011

Будет ли история проекта только для вашей выгоды или для пользы людей на github?

Если история только для вашей выгоды, есть простой способ использования трансплантатов. По сути, просто создайте новый репозиторий для github, удалив весь проприетарный код. Теперь у вас есть репозиторий с открытым исходным кодом только с открытым кодом, который вы можете отправить на github. В вашей локальной копии репо с открытым исходным кодом вы можете перенести историю из проприетарного репо в репо с открытым исходным кодом.

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

Для чего нужны .git / info / grafts?

...