Отсоединить (переместить) подкаталог в отдельный репозиторий Git

StackOverflow https://stackoverflow.com/questions/359424

Вопрос

У меня есть Мерзавец репозиторий, который содержит несколько подкаталогов.Теперь я обнаружил, что один из подкаталогов не связан с другим и должен быть выделен в отдельный репозиторий.

Как я могу это сделать, сохраняя историю файлов в подкаталоге?

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

Просто чтобы было понятно, у меня есть следующая структура:

XYZ/
    .git/
    XY1/
    ABC/
    XY2/

Но я бы хотел, чтобы вместо этого было вот это:

XYZ/
    .git/
    XY1/
    XY2/
ABC/
    .git/
    ABC/
Это было полезно?

Решение

Обновить:Этот процесс настолько распространен, что команда git значительно упростила его с помощью нового инструмента, git subtree.Смотрите здесь: Отсоединить (переместить) подкаталог в отдельный репозиторий Git


Вы хотите клонировать свой репозиторий, а затем использовать git filter-branch пометить все, кроме подкаталога, который вы хотите использовать в вашем новом репозитории для сбора мусора.

  1. Чтобы клонировать ваш локальный репозиторий:

    git clone /XYZ /ABC
    

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

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

    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
    
  3. Теперь вы, возможно, захотите также удалить теги, которые не имеют никакого отношения к подпроекту;вы также можете сделать это позже, но вам, возможно, придется снова сократить ваше репо.Я этого не сделал и получил WARNING: Ref 'refs/tags/v0.1' is unchanged для всех тегов (поскольку все они не были связаны с подпроектом);кроме того, после удаления таких тегов будет освобождено больше места.Очевидно git filter-branch должна быть возможность переписать другие теги, но я не смог это проверить.Если вы хотите удалить все теги, используйте git tag -l | xargs git tag -d.

  4. Затем используйте 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
    
  5. Затем удалите повторные записи резервных копий, чтобы пространство можно было действительно освободить (хотя теперь операция является разрушительной).

    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.Кроме того, есть пример из реального мира в Прохождение ниже.

  1. Подготовьте старое репо

    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

  2. Создайте новое хранилище

    mkdir <new-repo>
    pushd <new-repo>
    
    git init
    git pull </path/to/big-repo> <name-of-new-branch>
    
  3. Свяжите новый репозиторий с Github или где угодно еще

    git remote add origin <git@github.com:my-user/new-repo.git>
    git push origin -u master
    
  4. Очистка, при желании

    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:

http://brew.sh

Последняя версия 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 шаг.

  1. Выполните клонирование и фильтр:

    git clone --no-hardlinks foo bar; cd bar
    git filter-branch --subdirectory-filter subdir/you/want
    
  2. Удалите все ссылки на старую историю.“origin” отслеживал ваш клон, а “original” - это то место, где filter-branch сохраняет старые материалы:

    git remote rm origin
    git update-ref -d refs/original/refs/heads/master
    git reflog expire --expire=now --all
    
  3. Даже сейчас ваша история может застрять в файле 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

Вот небольшая модификация для CoolAJ86's Ответ "The Easy Way™" для того, чтобы разделить несколько вложенных папок (допустим, sub1и sub2) в новый репозиторий git.

Простой способ™ (несколько вложенных папок)

  1. Подготовьте старое репо

    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..."

  2. Создайте новое хранилище

    mkdir <new-repo>
    pushd <new-repo>
    
    git init
    git pull </path/to/big-repo> <name-of-new-branch>
    
  3. Свяжите новый репозиторий с Github или где угодно еще

    git remote add origin <git@github.com:my-user/new-repo.git>
    git push origin -u master
    
  4. Очистка, при желании

    popd # get out of <new-repo>
    pushd <big-repo>
    
    git rm -rf <name-of-folder>
    

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

Исходный вопрос хочет, чтобы XYZ/ ABC/ (* файлы) превратились в ABC /ABC / (* файлы).После реализации принятого ответа для моего собственного кода я заметил, что он фактически изменяет XYZ / ABC / (* файлы) на ABC / (* файлы).На справочной странице ветви фильтра даже написано,

Результат будет содержать этот каталог (и только его). как корень его проекта."

Другими словами, это продвигает папку верхнего уровня "вверх" на один уровень.Это важное различие, потому что, например, в моей истории я переименовал папку верхнего уровня.Продвигая папки "вверх" на один уровень, git теряет непрерывность при фиксации, где я сделал переименование.

I lost contiuity after filter-branch

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

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

Итак, ваш алгоритм должен быть следующим:

  1. клонируйте ваше удаленное репозиторий в другой каталог
  2. используя git filter-branch остались только файлы в каком-нибудь подкаталоге, нажмите на новый удаленный
  3. создайте фиксацию, чтобы удалить этот подкаталог из вашего исходного удаленного репозитория

Похоже, что большинство (все?) приведенных здесь ответов опираются на ту или иную форму 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 (ссылка).

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

  1. Локально клонируйте многомодульный проект
  2. Филиалы - проверьте, что там есть: git branch -a
  3. Выполните проверку в каждой ветви, которая будет включена в разделение, чтобы получить локальную копию на вашей рабочей станции: git checkout --track origin/branchABC
  4. Создайте копию в новом каталоге: cp -r oldmultimod simple
  5. Перейдите в новую копию проекта: cd simple
  6. Избавьтесь от других модулей, которые не нужны в этом проекте:
  7. git rm otherModule1 other2 other3
  8. Теперь остается только вложенный каталог целевого модуля
  9. Избавьтесь от вложенного каталога модуля, чтобы корневой каталог модуля стал корневым каталогом нового проекта
  10. git mv moduleSubdir1/* .
  11. Удалить вложенный каталог relic: rmdir moduleSubdir1
  12. Проверяйте изменения в любой момент: git status
  13. Создайте новое репозиторий git и скопируйте его URL, чтобы указать на этот проект в нем:
  14. git remote set-url origin http://mygithost:8080/git/our-splitted-module-repo
  15. Убедитесь, что это хорошо: git remote -v
  16. Перенесите изменения в удаленное хранилище: git push
  17. Перейдите в удаленное хранилище и проверьте, что все там есть
  18. Повторите это для любой другой необходимой ветви: 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 каталог - это тот, который я хочу сделать новым отдельным репозиторием.

Гитхаб:

  1. Создайте свой новый репозиторий: MyTeam/mynewrepo

Подсказка Bash:

  1. $ cd c:/Dir1
  2. $ git filter-branch --prune-empty --subdirectory-filter dir2/dir3 HEAD
    Возвращенный: Ref 'refs/heads/master' was rewritten (к вашему сведению:dir2/dir3 чувствительны к регистру.)

  3. $ git remote add some_name git@github.com:MyTeam/mynewrepo.git
    git remote add origin etc.не сработало, вернули "remote origin already exists"

  4. $ 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

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

Я изменил инструкции таким образом, чтобы они применялись к локальному репозиторию, а не к тому, который размещен на GitHub.


Разделение вложенной папки на новый репозиторий

  1. Откройте Git Bash.

  2. Измените текущий рабочий каталог на тот, в котором вы хотите создать свой новый репозиторий.

  3. Клонируйте репозиторий, содержащий вложенную папку.

git clone OLD-REPOSITORY-FOLDER NEW-REPOSITORY-FOLDER
  1. Измените текущий рабочий каталог на ваш клонированный репозиторий.

cd REPOSITORY-NAME
  1. Чтобы отфильтровать вложенную папку от остальных файлов в репозитории, выполните 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/

У меня это сработало.Проблемы, с которыми я столкнулся на этапах, приведенных выше, заключаются в следующем

  1. в этой команде git filter-branch --prune-empty --subdirectory-filter FOLDER-NAME BRANCH-NAME Тот Самый BRANCH-NAME является мастер

  2. если последний шаг завершается неудачей при фиксации из-за проблемы с защитой, выполните следующие действия - https://docs.gitlab.com/ee/user/project/protected_branches.html

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top