Отсоединить (переместить) подкаталог в отдельный репозиторий Git
-
21-08-2019 - |
Вопрос
У меня есть Мерзавец репозиторий, который содержит несколько подкаталогов.Теперь я обнаружил, что один из подкаталогов не связан с другим и должен быть выделен в отдельный репозиторий.
Как я могу это сделать, сохраняя историю файлов в подкаталоге?
Я предполагаю, что я мог бы создать клон и удалить ненужные части каждого клона, но я полагаю, что это дало бы мне полное дерево при проверке более старой версии и т.д.Это могло бы быть приемлемо, но я бы предпочел иметь возможность притворяться, что у двух репозиториев нет общей истории.
Просто чтобы было понятно, у меня есть следующая структура:
XYZ/
.git/
XY1/
ABC/
XY2/
Но я бы хотел, чтобы вместо этого было вот это:
XYZ/
.git/
XY1/
XY2/
ABC/
.git/
ABC/
Решение
Обновить:Этот процесс настолько распространен, что команда git значительно упростила его с помощью нового инструмента, git subtree
.Смотрите здесь: Отсоединить (переместить) подкаталог в отдельный репозиторий Git
Вы хотите клонировать свой репозиторий, а затем использовать git filter-branch
пометить все, кроме подкаталога, который вы хотите использовать в вашем новом репозитории для сбора мусора.
Чтобы клонировать ваш локальный репозиторий:
git clone /XYZ /ABC
(Примечание:репозиторий будет клонирован с использованием жестких ссылок, но это не проблема, поскольку файлы с жесткими ссылками сами по себе изменяться не будут - будут созданы новые.)
Теперь давайте сохраним интересные ветви, которые мы также хотим переписать, а затем удалим источник, чтобы избежать нажатия туда и убедиться, что источник не будет ссылаться на старые коммиты:
cd /ABC for i in branch1 br2 br3; do git branch -t $i origin/$i; done git remote rm origin
или для всех удаленных филиалов:
cd /ABC for i in $(git branch -r | sed "s/.*origin\///"); do git branch -t $i origin/$i; done git remote rm origin
Теперь вы, возможно, захотите также удалить теги, которые не имеют никакого отношения к подпроекту;вы также можете сделать это позже, но вам, возможно, придется снова сократить ваше репо.Я этого не сделал и получил
WARNING: Ref 'refs/tags/v0.1' is unchanged
для всех тегов (поскольку все они не были связаны с подпроектом);кроме того, после удаления таких тегов будет освобождено больше места.Очевидноgit filter-branch
должна быть возможность переписать другие теги, но я не смог это проверить.Если вы хотите удалить все теги, используйтеgit tag -l | xargs git tag -d
.Затем используйте filter-branch и reset, чтобы исключить другие файлы, чтобы их можно было удалить.Давайте также добавим
--tag-name-filter cat --prune-empty
чтобы удалить пустые коммиты и переписать теги (обратите внимание, что для этого придется удалить их подпись):git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC -- --all
или, в качестве альтернативы, переписать только головную ветвь и игнорировать теги и другие ветви:
git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC HEAD
Затем удалите повторные записи резервных копий, чтобы пространство можно было действительно освободить (хотя теперь операция является разрушительной).
git reset --hard git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d git reflog expire --expire=now --all git gc --aggressive --prune=now
и теперь у вас есть локальный репозиторий git подкаталога ABC со всей его историей.
Примечание:Для большинства применений, git filter-branch
действительно, должен быть добавлен параметр -- --all
.Да, это действительно так --Космос-- all
.Это должны быть последние параметры для команды.Как обнаружил Matli, это позволяет сохранить ветви проекта и теги, включенные в новое репозиторий.
Редактировать:различные предложения из комментариев ниже были включены, чтобы убедиться, например, что репозиторий действительно уменьшен (что раньше было не всегда).
Другие советы
Простой Способ™
Оказывается, это настолько распространенная и полезная практика, что создатели git действительно упростили ее, но у вас должна быть более новая версия git (>= 1.7.11 мая 2012).Посмотрите на приложение о том, как установить последнюю версию git.Кроме того, есть пример из реального мира в Прохождение ниже.
Подготовьте старое репо
pushd <big-repo> git subtree split -P <name-of-folder> -b <name-of-new-branch> popd
Примечание:
<name-of-folder>
НЕ должно содержать начальных или завершающих символов.Например, папка с именемsubproject
ДОЛЖНО быть передано какsubproject
, НЕ./subproject/
Примечание для пользователей Windows: когда глубина вашей папки > 1,
<name-of-folder>
должен иметь разделитель папок в стиле *nix (/).Например, папка с именемpath1\path2\subproject
ДОЛЖНО быть передано какpath1/path2/subproject
Создайте новое хранилище
mkdir <new-repo> pushd <new-repo> git init git pull </path/to/big-repo> <name-of-new-branch>
Свяжите новый репозиторий с Github или где угодно еще
git remote add origin <git@github.com:my-user/new-repo.git> git push origin -u master
Очистка, при желании
popd # get out of <new-repo> pushd <big-repo> git rm -rf <name-of-folder>
Примечание:При этом все исторические ссылки остаются в репозитории.Смотрите Приложение ниже, если вы действительно обеспокоены тем, что ввели пароль, или вам необходимо уменьшить размер файла вашего
.git
папка.
...
Прохождение
Это те самые те же шаги, что и вышеописанные, но следуя моим точным шагам для моего репозитория вместо использования <meta-named-things>
.
Вот проект, который у меня есть для реализации модулей браузера JavaScript в node:
tree ~/Code/node-browser-compat
node-browser-compat
├── ArrayBuffer
├── Audio
├── Blob
├── FormData
├── atob
├── btoa
├── location
└── navigator
Я хочу разделить одну папку, btoa
, в отдельный репозиторий git
pushd ~/Code/node-browser-compat/
git subtree split -P btoa -b btoa-only
popd
Теперь у меня есть новая ветка, btoa-only
, который имеет коммиты только для btoa
и я хочу создать новый репозиторий.
mkdir ~/Code/btoa/
pushd ~/Code/btoa/
git init
git pull ~/Code/node-browser-compat btoa-only
Затем я создаю новое репозиторий на Github или bitbucket, или что угодно еще, и добавляю, что это origin
(кстати, "origin" - это просто соглашение, а не часть команды - вы могли бы назвать это "удаленный сервер" или как вам угодно)
git remote add origin git@github.com:node-browser-compat/btoa.git
git push origin -u master
Счастливого дня!
Примечание: Если вы создали репозиторий с README.md
, .gitignore
и LICENSE
, вам нужно будет сначала потянуть:
git pull origin -u master
git push origin -u master
Наконец, я захочу удалить папку из более крупного репозитория
git rm -rf btoa
...
Приложение
Последняя версия git для OS X
Чтобы получить последнюю версию git:
brew install git
Чтобы получить brew для OS X:
Последняя версия git в Ubuntu
sudo apt-get update
sudo apt-get install git
git --version
Если это не сработает (у вас очень старая версия ubuntu), попробуйте
sudo add-apt-repository ppa:git-core/ppa
sudo apt-get update
sudo apt-get install git
Если это все еще не сработает, попробуйте
sudo chmod +x /usr/share/doc/git/contrib/subtree/git-subtree.sh
sudo ln -s \
/usr/share/doc/git/contrib/subtree/git-subtree.sh \
/usr/lib/git-core/git-subtree
Спасибо rui.araujo за комментарии.
очистка вашей истории
По умолчанию удаление файлов из git на самом деле не удаляет их из git, оно просто фиксирует, что их там больше нет.Если вы действительно хотите удалить исторические ссылки (т. е.у вас есть зафиксированный пароль), вам нужно сделать это:
git filter-branch --prune-empty --tree-filter 'rm -rf <name-of-folder>' HEAD
После этого вы можете проверить, что ваш файл или папка вообще больше не отображаются в истории git
git log -- <name-of-folder> # should show nothing
Однако, вы не удается "протолкнуть" удаление на github и тому подобное.Если вы попытаетесь, вы получите сообщение об ошибке, и вам придется git pull
прежде чем ты сможешь git push
- а потом ты возвращаешься ко всему, что было в твоей истории.
Итак, если вы хотите удалить историю из "источника" - то есть удалить ее из github, bitbucket и т.д. - вам нужно удалить репозиторий и повторно загрузить сокращенную копию репозитория.Но подождите - это еще не все!- Если вы действительно хотите избавиться от пароля или чего-то подобного, вам нужно удалить резервную копию (см. Ниже).
создание .git
меньший
Вышеупомянутая команда delete history по-прежнему оставляет после себя кучу резервных копий файлов - потому что git слишком добр, помогая вам случайно не испортить ваш репозиторий.В конечном итоге потерянные файлы будут удалены в течение нескольких дней и месяцев, но они останутся там на некоторое время на случай, если вы поймете, что случайно удалили что-то, чего не хотели.
Так что, если ты действительно хочешь выбросьте мусор Для уменьшите размер клона из репо немедленно вам приходится делать все эти действительно странные вещи:
rm -rf .git/refs/original/ && \
git reflog expire --all && \
git gc --aggressive --prune=now
git reflog expire --all --expire-unreachable=0
git repack -A -d
git prune
Тем не менее, я бы рекомендовал не выполнять эти шаги, если вы не знаете, что вам это нужно - на всякий случай, если вы удалили не тот подкаталог, понимаете?Файлы резервных копий не должны клонироваться при запуске репозитория, они просто будут в вашей локальной копии.
Кредит
Ответ Павла создает новый репозиторий, содержащий /ABC, но не удаляет /ABC из /XYZ.Следующая команда удалит /ABC из /XYZ:
git filter-branch --tree-filter "rm -rf ABC" --prune-empty HEAD
Конечно, сначала протестируйте его в репозитории 'clone --no-hardlinks', а затем выполните команды reset, gc и prune, которые перечисляет Пол.
Я обнаружил, что для правильного удаления старой истории из нового репозитория вам нужно проделать еще немного работы после завершения filter-branch
шаг.
Выполните клонирование и фильтр:
git clone --no-hardlinks foo bar; cd bar git filter-branch --subdirectory-filter subdir/you/want
Удалите все ссылки на старую историю.“origin” отслеживал ваш клон, а “original” - это то место, где filter-branch сохраняет старые материалы:
git remote rm origin git update-ref -d refs/original/refs/heads/master git reflog expire --expire=now --all
Даже сейчас ваша история может застрять в файле packfile, к которому fsck не будет прикасаться.Разорвите его в клочья, создав новый файл пакета и удалив неиспользуемые объекты:
git repack -ad
Есть объяснение этого в руководство по эксплуатации фильтра-отвода.
Редактировать:Добавлен скрипт Bash.
Приведенные здесь ответы сработали для меня лишь частично;В кэше осталось много больших файлов.Что, наконец, сработало (после нескольких часов работы в #git на freenode):
git clone --no-hardlinks file:///SOURCE /tmp/blubb
cd blubb
git filter-branch --subdirectory-filter ./PATH_TO_EXTRACT --prune-empty --tag-name-filter cat -- --all
git clone file:///tmp/blubb/ /tmp/blooh
cd /tmp/blooh
git reflog expire --expire=now --all
git repack -ad
git gc --prune=now
В предыдущих решениях размер репозитория составлял около 100 МБ.В этом случае он сократился до 1,7 МБ.Может быть, это кому-нибудь поможет :)
Следующий скрипт bash автоматизирует эту задачу:
!/bin/bash
if (( $# < 3 ))
then
echo "Usage: $0 </path/to/repo/> <directory/to/extract/> <newName>"
echo
echo "Example: $0 /Projects/42.git first/answer/ firstAnswer"
exit 1
fi
clone=/tmp/${3}Clone
newN=/tmp/${3}
git clone --no-hardlinks file://$1 ${clone}
cd ${clone}
git filter-branch --subdirectory-filter $2 --prune-empty --tag-name-filter cat -- --all
git clone file://${clone} ${newN}
cd ${newN}
git reflog expire --expire=now --all
git repack -ad
git gc --prune=now
git filter-branch --prune-empty --subdirectory-filter <YOUR_SUBDIR_TO_KEEP> master
git push <MY_NEW_REMOTE_URL> -f .
Обновить:Модуль git-subtree был настолько полезен, что команда git перенесла его в ядро и сделала его git subtree
.Смотрите здесь: Отсоединить (переместить) подкаталог в отдельный репозиторий Git
для этого может быть полезно git-subtree
http://github.com/apenwarr/git-subtree/blob/master/git-subtree.txt (устарел)
http://psionides.jogger.pl/2010/02/04/sharing-code-between-projects-with-git-subtree/
Вот небольшая модификация для CoolAJ86's Ответ "The Easy Way™" для того, чтобы разделить несколько вложенных папок (допустим, sub1
и sub2
) в новый репозиторий git.
Простой способ™ (несколько вложенных папок)
Подготовьте старое репо
pushd <big-repo> git filter-branch --tree-filter "mkdir <name-of-folder>; mv <sub1> <sub2> <name-of-folder>/" HEAD git subtree split -P <name-of-folder> -b <name-of-new-branch> popd
Примечание:
<name-of-folder>
НЕ должно содержать начальных или завершающих символов.Например, папка с именемsubproject
ДОЛЖНО быть передано какsubproject
, НЕ./subproject/
Примечание для пользователей Windows: когда глубина вашей папки > 1,
<name-of-folder>
должен иметь разделитель папок в стиле *nix (/).Например, папка с именемpath1\path2\subproject
ДОЛЖНО быть передано какpath1/path2/subproject
.Более того, не используйтеmv
командовать , ноmove
.Заключительная нота: уникальным и большим отличием от базового ответа является вторая строка скрипта "
git filter-branch...
"Создайте новое хранилище
mkdir <new-repo> pushd <new-repo> git init git pull </path/to/big-repo> <name-of-new-branch>
Свяжите новый репозиторий с Github или где угодно еще
git remote add origin <git@github.com:my-user/new-repo.git> git push origin -u master
Очистка, при желании
popd # get out of <new-repo> pushd <big-repo> git rm -rf <name-of-folder>
Примечание:При этом все исторические ссылки остаются в репозитории.Смотрите Приложение в исходном ответе, если вы действительно обеспокоены тем, что ввели пароль, или вам нужно уменьшить размер файла вашего
.git
папка.
Исходный вопрос хочет, чтобы XYZ/ ABC/ (* файлы) превратились в ABC /ABC / (* файлы).После реализации принятого ответа для моего собственного кода я заметил, что он фактически изменяет XYZ / ABC / (* файлы) на ABC / (* файлы).На справочной странице ветви фильтра даже написано,
Результат будет содержать этот каталог (и только его). как корень его проекта."
Другими словами, это продвигает папку верхнего уровня "вверх" на один уровень.Это важное различие, потому что, например, в моей истории я переименовал папку верхнего уровня.Продвигая папки "вверх" на один уровень, git теряет непрерывность при фиксации, где я сделал переименование.
Тогда мой ответ на этот вопрос заключается в том, чтобы сделать 2 копии репозитория и вручную удалить папки, которые вы хотите сохранить в каждой.Справочная страница подтверждает это:
[...] избегайте использования [этой команды], если для решения вашей проблемы будет достаточно простого одиночного коммита
Чтобы добавить к Ответ Павла, я обнаружил, что для окончательного восстановления пространства мне нужно переместить HEAD в чистый репозиторий, и это уменьшает размер каталога .git/objects /pack .
т. е.
$ mkdir ...ABC.git $ cd ...ABC.git $ git init --bare
После обрезки gc также проделайте:
$ git push ...ABC.git HEAD
Тогда вы можете сделать
$ git clone ...ABC.git
и размер ABC/.git уменьшается
На самом деле, некоторые из трудоемких шагов (например,git gc) не нужны для очистки репозитория, т.е.:
$ git clone --no-hardlinks /XYZ /ABC $ git filter-branch --subdirectory-filter ABC HEAD $ git reset --hard $ git push ...ABC.git HEAD
Правильный способ сейчас заключается в следующем:
git filter-branch --prune-empty --subdirectory-filter FOLDER_NAME [first_branch] [another_branch]
На GitHub теперь даже есть небольшая статья о таких случаях.
Но обязательно сначала клонируйте свой исходный репозиторий в отдельный каталог (так как это приведет к удалению всех файлов и других каталогов, и вам, вероятно, придется с ними работать).
Итак, ваш алгоритм должен быть следующим:
- клонируйте ваше удаленное репозиторий в другой каталог
- используя
git filter-branch
остались только файлы в каком-нибудь подкаталоге, нажмите на новый удаленный - создайте фиксацию, чтобы удалить этот подкаталог из вашего исходного удаленного репозитория
Похоже, что большинство (все?) приведенных здесь ответов опираются на ту или иную форму git filter-branch --subdirectory-filter
и иже с ними.Это может сработать "в большинстве случаев", однако для некоторых случаев, например, когда вы переименовали папку, например:
ABC/
/move_this_dir # did some work here, then renamed it to
ABC/
/move_this_dir_renamed
Если вы используете обычный стиль фильтра git для извлечения "move_me_renamed", вы потеряете историю изменений файла, которые произошли с того момента, когда он был изначально move_this_dir (ссылка).
Таким образом, представляется, что единственный способ действительно сохранить ВСЕ история изменений (если у вас такой случай), по сути, заключается в копировании репозитория (создайте новый репозиторий, установите его в качестве источника), затем уничтожьте все остальное и переименуйте подкаталог в родительский следующим образом:
- Локально клонируйте многомодульный проект
- Филиалы - проверьте, что там есть:
git branch -a
- Выполните проверку в каждой ветви, которая будет включена в разделение, чтобы получить локальную копию на вашей рабочей станции:
git checkout --track origin/branchABC
- Создайте копию в новом каталоге:
cp -r oldmultimod simple
- Перейдите в новую копию проекта:
cd simple
- Избавьтесь от других модулей, которые не нужны в этом проекте:
git rm otherModule1 other2 other3
- Теперь остается только вложенный каталог целевого модуля
- Избавьтесь от вложенного каталога модуля, чтобы корневой каталог модуля стал корневым каталогом нового проекта
git mv moduleSubdir1/* .
- Удалить вложенный каталог relic:
rmdir moduleSubdir1
- Проверяйте изменения в любой момент:
git status
- Создайте новое репозиторий git и скопируйте его URL, чтобы указать на этот проект в нем:
git remote set-url origin http://mygithost:8080/git/our-splitted-module-repo
- Убедитесь, что это хорошо:
git remote -v
- Перенесите изменения в удаленное хранилище:
git push
- Перейдите в удаленное хранилище и проверьте, что все там есть
- Повторите это для любой другой необходимой ветви:
git checkout branch2
Из этого следует документ github "Разделение вложенной папки на новый репозиторий" шаги 6-11 для переноса модуля в новое хранилище.
Это не сэкономит вам места в вашей папке .git, но сохранит всю историю изменений для этих файлов даже при переименовании.И это может не стоить того, если не будет потеряно "много" истории и т.д.Но, по крайней мере, вы гарантированно не потеряете старые коммиты!
У меня была именно эта проблема, но все стандартные решения, основанные на git filter-branch, были чрезвычайно медленными.Если у вас небольшой репозиторий, то это может и не быть проблемой, это было для меня.Я написал другую программу фильтрации git на основе libgit2, которая в качестве первого шага создает ветви для каждой фильтрации основного репозитория, а затем отправляет их для очистки репозиториев в качестве следующего шага.В моем репозитории (500 МБ 100000 коммитов) стандартные методы git filter-branch заняли несколько дней.Моей программе требуется несколько минут, чтобы выполнить ту же фильтрацию.
Он имеет потрясающее название git_filter и живет здесь:
https://github.com/slobobaby/git_filter
на GitHub.
Я надеюсь, что это кому-то пригодится.
Как бы то ни было, вот как использовать GitHub на компьютере с Windows.Допустим, у вас есть клонированное репозиторий, находящееся в C:\dir1
.Структура каталогов выглядит следующим образом: C:\dir1\dir2\dir3
.Тот Самый dir3
каталог - это тот, который я хочу сделать новым отдельным репозиторием.
Гитхаб:
- Создайте свой новый репозиторий:
MyTeam/mynewrepo
Подсказка Bash:
$ cd c:/Dir1
$ git filter-branch --prune-empty --subdirectory-filter dir2/dir3 HEAD
Возвращенный:Ref 'refs/heads/master' was rewritten
(к вашему сведению:dir2/dir3 чувствительны к регистру.)$ git remote add some_name git@github.com:MyTeam/mynewrepo.git
git remote add origin etc
.не сработало, вернули "remote origin already exists
"$ git push --progress some_name master
Как я упомянутый выше, мне пришлось использовать обратное решение (удалив все коммиты, не затрагивающие мой dir/subdir/targetdir
), который, казалось, работал довольно хорошо, удаляя около 95% коммитов (по желанию).Однако остаются две небольшие проблемы.
Первый, filter-branch
проделал отличную работу по удалению коммитов, которые вводят или изменяют код, но, по-видимому, слияние коммитов находятся под его станцией в Gitiverse.
Это косметическая проблема, с которой я, вероятно, смогу смириться (говорит он ... медленно отступая, отводя глаза).
ВТОРОЙ те немногие коммиты, которые остались, в значительной степени ВСЕ дублированный!Похоже, я приобрел вторую, избыточную временную шкалу, которая охватывает практически всю историю проекта.Интересная вещь (которую вы можете видеть на картинке ниже) заключается в том, что не все мои три локальные ветки находятся на одной временной шкале (именно поэтому она, безусловно, существует, а не просто собирается мусор).
Единственное, что я могу себе представить, это то, что одним из удаленных коммитов был, возможно, единственный коммит слияния, который filter-branch
на самом деле удалил, и это создало параллельную временную шкалу, поскольку каждая теперь несвязанная цепочка брала свою собственную копию коммитов.(пожимаю плечами Где моя ТАРДиС?) Я почти уверен, что смогу исправить эту проблему, хотя я бы в самом деле хотелось бы понять, как это произошло.
В случае с crazy mergefest-O-RAMA я, скорее всего, оставлю его в покое, поскольку он так прочно закрепился в моей истории коммитов — угрожающий мне всякий раз, когда я приближаюсь — и, похоже, на самом деле не вызывает никаких некосметических проблем, и потому что в Tower.app он довольно симпатичный.
Используйте эту команду фильтра, чтобы удалить подкаталог, сохранив при этом ваши теги и ветви:
git filter-branch --index-filter \
"git rm -r -f --cached --ignore-unmatch DIR" --prune-empty \
--tag-name-filter cat -- --all
легкий путь
<Ол>git splits
. Я создал его в качестве расширения мерзавца, на основе решения jkeating в. Разделение каталогов в местное отделение
#change into your repo's directory
cd /path/to/repo
#checkout the branch
git checkout XYZ
#split multiple directories into new branch XYZ
git splits -b XYZ XY1 XY2
Создать пустой репозиторий где-нибудь. Мы будем считать, что мы создали пустой репозиторий под названием xyz
на GitHub, который имеет путь: git@github.com:simpliwp/xyz.git
Нажмите на новый репо.
#add a new remote origin for the empty repo so we can push to the empty repo on GitHub
git remote add origin_xyz git@github.com:simpliwp/xyz.git
#push the branch to the empty repo's master branch
git push origin_xyz XYZ:master
Clone вновь созданный удаленный репозиторий в новый локальный каталог
#change current directory out of the old repo
cd /path/to/where/you/want/the/new/local/repo
#clone the remote repo you just pushed to
git clone git@github.com:simpliwp/xyz.git
Я рекомендую Руководство GitHub по разделению вложенных папок в новый репозиторий.Шаги аналогичны следующим Ответ Павла, но я нашел их инструкции более понятными.
Я изменил инструкции таким образом, чтобы они применялись к локальному репозиторию, а не к тому, который размещен на GitHub.
Разделение вложенной папки на новый репозиторий
Откройте Git Bash.
Измените текущий рабочий каталог на тот, в котором вы хотите создать свой новый репозиторий.
Клонируйте репозиторий, содержащий вложенную папку.
git clone OLD-REPOSITORY-FOLDER NEW-REPOSITORY-FOLDER
- Измените текущий рабочий каталог на ваш клонированный репозиторий.
cd REPOSITORY-NAME
- Чтобы отфильтровать вложенную папку от остальных файлов в репозитории, выполните
git filter-branch
, предоставляющий эту информацию:
FOLDER-NAME
:Папка внутри вашего проекта, из которой вы хотели бы создать отдельный репозиторий.
- Подсказка:Пользователи Windows должны использовать
/
чтобы разграничить папки.BRANCH-NAME
:Ветвь по умолчанию для вашего текущего проекта, например,master
илиgh-pages
.git filter-branch --prune-empty --subdirectory-filter FOLDER-NAME BRANCH-NAME # Filter the specified branch in your directory and remove empty commits Rewrite 48dc599c80e20527ed902928085e7861e6b3cbe6 (89/89) Ref 'refs/heads/BRANCH-NAME' was rewritten
Возможно, вам понадобится что-то вроде "git reflog expire --expire=now --all" перед сборкой мусора, чтобы фактически очистить файлы.git filter-branch просто удаляет ссылки в истории, но не удаляет записи reflog, которые содержат данные.Конечно, сначала протестируйте это.
При этом использование моего диска резко сократилось, хотя мои начальные условия были несколько иными.Возможно, --subdirectory-filter отрицает эту необходимость, но я сомневаюсь в этом.
Ознакомьтесь с проектом git_split по адресу https://github.com/vangorra/git_split
Превратите каталоги git в их собственные репозитории в их собственном расположении.Никаких приколов с поддеревьями.Этот скрипт возьмет существующий каталог в вашем репозитории git и превратит этот каталог в свой собственный независимый репозиторий.Попутно он скопирует всю историю изменений для указанного вами каталога.
./git_split.sh <src_repo> <src_branch> <relative_dir_path> <dest_repo>
src_repo - The source repo to pull from.
src_branch - The branch of the source repo to pull from. (usually master)
relative_dir_path - Relative path of the directory in the source repo to split.
dest_repo - The repo to push to.
Поместите это в свой gitconfig:
reduce-to-subfolder = !sh -c 'git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter cookbooks/unicorn HEAD && git reset --hard && git for-each-ref refs/original/ | cut -f 2 | xargs -n 1 git update-ref -d && git reflog expire --expire=now --all && git gc --aggressive --prune=now && git remote rm origin'
Я уверен, что поддерево git - это все прекрасно, но все мои подкаталоги управляемого кода git, которые я хотел переместить, были в eclipse.Так что, если вы используете egit, это до боли просто.Возьмите проект, который вы хотите переместить, и нажмите команду-> отключить его, а затем команду-> предоставить общий доступ к нему в новом месте.По умолчанию будет предпринята попытка использовать старое местоположение репозитория, но вы можете снять флажок использовать существующий выбор и выбрать новое место для его перемещения.Да здравствует эгит.
Я нашел довольно простое решение, Идея состоит в том, чтобы скопировать репозиторий, а затем просто удалить ненужную часть.Вот как это работает:
1) Клонируйте репозиторий, который вы хотели бы разделить
git clone git@git.thehost.io:testrepo/test.git
2) Переместиться в папку git
cd test/
2) Удалите ненужные папки и зафиксируйте это
rm -r ABC/
git add .
enter code here
git commit -m 'Remove ABC'
3) Удалите ненужную папку (папки) истории форм с помощью BFG
cd ..
java -jar bfg.jar --delete-folders "{ABC}" test
cd test/
git reflog expire --expire=now --all && git gc --prune=now --aggressive
для нескольких папок вы можете использовать запятую
java -jar bfg.jar --delete-folders "{ABC1,ABC2}" metric.git
4) Убедитесь, что в истории нет файлов / папок, которые вы только что удалили
git log --diff-filter=D --summary | grep delete
5) Теперь у вас есть чистый репозиторий без ABC, поэтому просто вставьте его в новый источник
remote add origin git@github.com:username/new_repo
git push -u origin master
Вот и все.Вы можете повторить эти шаги, чтобы получить другой репозиторий,
просто удалите XY1, XY2 и переименуйте XYZ -> ABC на шаге 3
Вы можете легко попробовать https://help.github.com/enterprise/2.15/user/articles/splitting-a-subfolder-out-into-a-new-repository/
У меня это сработало.Проблемы, с которыми я столкнулся на этапах, приведенных выше, заключаются в следующем
в этой команде
git filter-branch --prune-empty --subdirectory-filter FOLDER-NAME BRANCH-NAME
Тот СамыйBRANCH-NAME
является мастересли последний шаг завершается неудачей при фиксации из-за проблемы с защитой, выполните следующие действия - https://docs.gitlab.com/ee/user/project/protected_branches.html