Как извлечь подкаталог git и сделать из него подмодуль? - PullRequest
111 голосов
/ 28 мая 2009

Я начал проект несколько месяцев назад и сохранил все в главном каталоге. В моем основном каталоге "Project" есть несколько подкаталогов, содержащих разные вещи: Проект / документ содержит документ, написанный на LaTeX Project / sourcecode / RailsApp содержит мое приложение rails.

«Проект» GITified и было много коммитов как в «paper», так и в «RailsApp» каталоге. Теперь, поскольку я хотел бы использовать cruisecontrol.rb для моего "RailsApp", мне интересно, есть ли способ сделать подмодуль из "RailsApp" без потери истории.

Ответы [ 5 ]

115 голосов
/ 20 августа 2009

В настоящее время есть гораздо более простой способ сделать это, чем вручную, используя git filter-branch: git subtree

Установка

git clone https://github.com/apenwarr/git-subtree.git

cd git-subtree
sudo rsync -a ./git-subtree.sh /usr/local/bin/git-subtree

Или, если вы хотите справочные страницы и все

make doc
make install

Использование

Разделить большее на более мелкие куски:

# Go into the project root
cd ~/my-project

# Create a branch which only contains commits for the children of 'foo'
git subtree split --prefix=foo --branch=foo-only

# Remove 'foo' from the project
git rm -rf ./foo

# Create a git repo for 'foo' (assuming we already created it on github)
mkdir foo
pushd foo
git init
git remote add origin git@github.com:my-user/new-project.git
git pull ../ foo-only
git push origin -u master
popd

# Add 'foo' as a git submodule to `my-project`
git submodule add git@github.com:my-user/new-project.git foo

Для получения подробной документации (справочная страница), пожалуйста, прочитайте git-subtree.txt.

38 голосов
/ 30 мая 2009

Оформить заказ git filter-branch .

В разделе Examples страницы руководства показано, как извлечь подкаталог в собственный проект, сохраняя всю его историю и удаляя историю других файлов / каталогов (именно то, что вы ищу).

Переписать репозиторий так, чтобы он выглядел так, как если бы foodir/ был его корнем проекта, и отбросить всю другую историю:

   git filter-branch --subdirectory-filter foodir -- --all

Таким образом, вы можете, например, превратить подкаталог библиотеки в собственный репозиторий.
Обратите внимание на --, который отделяет опции filter-branch от параметров ревизии, и --all для перезаписи всех ветвей и тегов.

13 голосов
/ 30 мая 2009

Одним из способов сделать это является обратное - удалить все, кроме файла, который вы хотите сохранить.

По сути, создайте копию хранилища, затем используйте git filter-branch, чтобы удалить все, кроме файла / папок, которые вы хотите сохранить.

Например, у меня есть проект, из которого я хочу извлечь файл tvnamer.py в новый репозиторий:

git filter-branch --tree-filter 'for f in *; do if [ $f != "tvnamer.py" ]; then rm -rf $f; fi; done' HEAD

Использует git filter-branch --tree-filter для прохождения каждого коммита, запуска команды и повторной отправки содержимого каталогов. Это чрезвычайно разрушительно (поэтому вы должны делать это только с копией вашего хранилища!) И может занять некоторое время (около 1 минуты в хранилище с 300 коммитами и около 20 файлами)

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

for f in *; do
    if [ $f != "tvnamer.py" ]; then
        rm -rf $f;
    fi;
done

Самая большая очевидная проблема заключается в том, что он оставляет все сообщения о коммитах, даже если они не связаны с оставшимся файлом. Сценарий git-remove-empty-commits , исправляет это ..

git filter-branch --commit-filter 'if [ z$1 = z`git rev-parse $3^{tree}` ]; then skip_commit "$@"; else git commit-tree "$@"; fi'

Вам необходимо использовать аргумент -f force, снова запустить filter-branch с любым значением в refs/original/ (что в основном является резервной копией)

Конечно, это никогда не будет идеальным, например, если в ваших сообщениях о коммитах упоминаются другие файлы, но он настолько близок, насколько позволяет git current (насколько я знаю в любом случае).

Опять же, запускайте это только для копии вашего репозитория! - но в итоге, чтобы удалить все файлы, кроме "thisismyfilename.txt":

git filter-branch --tree-filter 'for f in *; do if [ $f != "thisismyfilename.txt" ]; then rm -rf $f; fi; done' HEAD
git filter-branch -f --commit-filter 'if [ z$1 = z`git rev-parse $3^{tree}` ]; then skip_commit "$@"; else git commit-tree "$@"; fi'
4 голосов
/ 18 февраля 2019

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

Сначала перейдите в Git Bash к корню git-репо, который нужно разделить. В моем примере это ~/Documents/OriginalRepo (master)

# move the folder at prefix to a new branch
git subtree split --prefix=SubFolderName/FolderToBeNewRepo --branch=to-be-new-repo

# create a new repository out of the newly made branch
mkdir ~/Documents/NewRepo
pushd ~/Documents/NewRepo
git init
git pull ~/Documents/OriginalRepo to-be-new-repo

# upload the new repository to a place that should be referenced for submodules
git remote add origin git@github.com:myUsername/newRepo.git
git push -u origin master
popd

# replace the folder with a submodule
git rm -rf ./SubFolderName/FolderToBeNewRepo
git submodule add git@github.com:myUsername/newRepo.git SubFolderName/FolderToBeNewRepo
git branch --delete --force to-be-new-repo

Ниже приведена копия выше с заменой настраиваемых имен и использованием https. Корневая папка теперь ~/Documents/_Shawn/UnityProjects/SoProject (master)

# move the folder at prefix to a new branch
git subtree split --prefix=Assets/SoArchitecture --branch=so-package

# create a new repository out of the newly made branch
mkdir ~/Documents/_Shawn/UnityProjects/SoArchitecture
pushd ~/Documents/_Shawn/UnityProjects/SoArchitecture
git init
git pull ~/Documents/_Shawn/UnityProjects/SoProject so-package

# upload the new repository to a place that should be referenced for submodules
git remote add origin https://github.com/Feddas/SoArchitecture.git
git push -u origin master
popd

# replace the folder with a submodule
git rm -rf ./Assets/SoArchitecture
git submodule add https://github.com/Feddas/SoArchitecture.git
git branch --delete --force so-package
3 голосов
/ 28 мая 2009

Если вы хотите перенести некоторое подмножество файлов в новый репозиторий, но сохранить историю, вы в итоге получите совершенно новую историю. Это будет работать следующим образом:

  1. Создать новый репозиторий.
  2. Для каждой ревизии вашего старого репозитория объедините изменения вашего модуля с новым репозиторием. Это создаст «копию» вашей существующей истории проекта.

Автоматизировать это должно быть довольно просто, если вы не против написать небольшой, но волосатый сценарий. Просто, да, но тоже больно. Люди делали переписывание истории в Git в прошлом, вы можете сделать это для поиска.

В качестве альтернативы: клонируйте репозиторий и удалите бумагу в клон, удалите приложение в оригинале. Это займет одну минуту, это гарантированно сработает, и вы сможете вернуться к более важным вещам, чем пытаться очистить свою историю мерзавцев. И не беспокойтесь о месте на жестком диске, занятом избыточными копиями истории.

...