git: Как отделить библиотеку от проекта? фильтр-ветка, поддерево?

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

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

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

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

  • fencing-game (git workdir)
    • src
      • de
        • fencing_game
          • transport (my library)
            • protocol (part of the library)
            • ограждение (часть основного проекта, связанная с библиотекой)
            • клиент (часть основного проекта, взаимодействующая с библиотекой)
            • сервер (часть основного проекта, взаимодействующая с библиотекой)
          • клиент (часть основного проекта)
          • сервер (часть основного проекта)
          • ... (часть основного проекта)
    • другие файлы и каталоги (система сборки, веб-сайт и т. д. - часть основного проекта)

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

  • my-library (name to be determined)
    • src
      • de
        • fencing_game
          • transport (my library)
            • protocol (part of the library)

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

Первый взгляд показал мне 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, в отдельном подкаталоге, а не там, где он сейчас. Я так представляю макет

  • fencing-game (git workdir)
    • src
      • de
        • fencing_game
          • transport (empty)
            • fencing (part of the main project interfacing with the library)
            • клиент (часть основного проекта, взаимодействующая с библиотекой)
            • сервер (часть основного проекта, взаимодействующая с библиотекой)
          • клиент (часть основного проекта)
          • сервер (часть основного проекта)
          • ... (часть основного проекта)
    • my-library
      • src
        • de
          • fencing_game
            • transport (my library)
              • protocol (part of the library)
    • другие файлы и каталоги (система сборки, веб-сайт и т. д. - часть основного проекта)
What would be the most pain-free way to do this? Are there other tools than git-subtree and git-filter-branch for this goal?


person Paŭlo Ebermann    schedule 19.06.2011    source источник
comment
Как видно из названий пакетов, основным проектом является fencing-game. Библиотека - это моя собственная реализация RPC.   -  person Paŭlo Ebermann    schedule 19.06.2011
comment
Я всегда знаю, что я не первый, кто сталкивается с проблемой :)   -  person Zlatko    schedule 18.11.2011


Ответы (5)


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

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

Но если у вас есть файлы в транспорте, а также в транспорте / протоколе, это начинает раздражать.

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

person phord    schedule 20.09.2011

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

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

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

  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
    

    Примечание: вам может потребоваться удалить резервную копию, созданную filter-branch между последовательными командами.

    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, а не на полный путь к родительскому проекту, поскольку он кажется отчасти привязанным к проекту.

person johnb003    schedule 07.03.2014

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

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

person Adam Dymitruk    schedule 19.06.2011
comment
Я могу легко реорганизовать свои каталоги, но это не сработает для истории. - person Paŭlo Ebermann; 19.06.2011
comment
Вероятно, не стоит прилагать усилия для сохранения истории до рефакторинга. Если это не так, вы можете использовать ветвь фильтра, чтобы упорядочить предыдущие изменения. - person Adam Dymitruk; 19.06.2011
comment
Решение вопроса «Как разделить проект и сохранить историю» не в том, что оно, вероятно, не стоит усилий, учитывая ценность истории в целом и легкость, с которой Git отслеживает ее. - person Dietrich Epp; 19.06.2011
comment
Справедливо. Ваша структура требует времени, чтобы сделать это. Ветвь фильтра - это способ придать ей форму. Потребуется дополнительная работа по редактированию истории проекта и истории библиотеки, чтобы обе они работали хорошо, при этом один из них с самого начала был подмодулем другого - git может только так много. - person Adam Dymitruk; 19.06.2011

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

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

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

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

person John Douthat    schedule 19.06.2011
comment
Будет ли история проекта использоваться только для вас или для пользователей github? - На данный момент я не знаю, будет ли моя библиотека вообще полезна. Но я думаю, что всегда было бы полезно оглянуться назад, чтобы увидеть, как возник какой-то фрагмент кода. - person Paŭlo Ebermann; 19.06.2011
comment
графты предназначены для сшивания истории до и после, а не для объединения проектов. - person phord; 20.09.2011
comment
Прививки предназначены для замены родителя коммита без изменения SHA коммита. Ни больше ни меньше. - person John Douthat; 21.09.2011

Я сделал что-то подобное, но разделил несколько каталогов с материалами в совершенно отдельное репо на зашифрованном разделе (/ 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 важны, поскольку filter-branch устанавливает их в исходное репо (а не то, что вы хотите!) И умрет, если sh передает ненулевой код выхода из последней команды в вашем скрипте.

person Community    schedule 04.01.2012