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

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

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

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

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

XYZ/
    .git/
    XY1/
    ABC/
    XY2/

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

XYZ/
    .git/
    XY1/
    XY2/
ABC/
    .git/
    ABC/

Ответы

Ответ 1

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


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

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

    git clone /XYZ /ABC
    

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

  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 git tag -l | xargs git tag -d.

  4. Затем используйте ветвь фильтра и сбросьте, чтобы исключить другие файлы, чтобы их можно было обрезать. Пусть также добавляет --tag-name-filter cat --prune-empty чтобы удалить пустые коммиты и переписать теги (обратите внимание, что это должно будет лишить их подпись):

    git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC -- --all
    

    или, альтернативно, только переписать ветвь HEAD и игнорировать теги и другие ветки:

    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 sub -d со всей сохраненной историей.

Примечание. Для большинства применений git filter-branch действительно имеет добавленный параметр -- --all. Да, действительно - - space - - all. Это должны быть последние параметры для команды. Как обнаружил Матли, это сохраняет ветки проекта и теги, включенные в новое репо.

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

Ответ 2

Простой способ & торговля;

Оказывается, это такая распространенная и полезная практика, что повелители 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, NOT ./subproject/

    Примечание для пользователей Windows:, когда глубина вашей папки > 1, <name-of-folder> должна иметь * nix style separator (/). Например, папка с именем 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 <[email protected]: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 (btw, "origin" - это просто соглашение, а не часть команды - вы можете назвать его "удаленным сервером", или как вам нравится)

git remote add origin [email protected]: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 - и затем вернетесь к тому, чтобы все было в вашей истории.

Итак, если вы хотите удалить историю из "origin", то есть удалить ее из github, bitbucket и т.д., вам нужно будет удалить репо и повторно наложить сокращенную копию репо. Но подождите - там больше! - Если вы действительно беспокоитесь о том, чтобы избавиться от пароля или что-то в этом роде, вам нужно обрезать резервную копию (см. Ниже).

создание .git меньше

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

Тем не менее, я бы рекомендовал не выполнять эти шаги, если вы не знаете, что вам нужно - на всякий случай, если вы обрезали неправильный подкаталог, знаете? Резервные файлы не должны клонироваться при нажатии на репо, они просто будут в вашей локальной копии.

Кредит

Ответ 3

Paul answer создает новый репозиторий, содержащий /ABC, но не удаляет /ABC изнутри/XYZ. Следующая команда удалит /ABC изнутри/XYZ:

git filter-branch --tree-filter "rm -rf ABC" --prune-empty HEAD

Конечно, сначала протестируйте его в репозитории 'clone --no-hardlinks' и следуйте ему с помощью команд reset, gc и prune, которые перечислены Paul.

Ответ 4

Ive обнаружил, что для правильного удаления старой истории из нового репозитория вам нужно сделать немного больше работы после шага filter-branch.

  • Сделайте клон и фильтр:

    git clone --no-hardlinks foo bar; cd bar
    git filter-branch --subdirectory-filter subdir/you/want
    
  • Удалите все ссылки на старую историю. "происхождение" отслеживало ваш клон, а "оригинал" - это то, где фильтр-ветвь сохраняет старый материал:

    git remote rm origin
    git update-ref -d refs/original/refs/heads/master
    git reflog expire --expire=now --all
    
  • Даже сейчас ваша история может застрять в пакетном файле, который fsck не коснется. Раздирайте его в клочья, создайте новый пакетный файл и удалите неиспользуемые объекты:

    git repack -ad
    

Существует объяснение этого в руководстве для ветки фильтра.

Ответ 5

Изменить: Bash script.

Ответы, приведенные здесь, работали частично для меня; В кеше осталось много больших файлов. Что, наконец, работало (после часа в # 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 script автоматизирует задачу:

!/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

Ответ 6

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

git filter-branch --prune-empty --subdirectory-filter <YOUR_SUBDIR_TO_KEEP> master
git push <MY_NEW_REMOTE_URL> -f .

Ответ 7

Обновление. Модуль 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/

Ответ 8

Вот небольшая модификация CoolAJ86 "Легкий способ и торговля" ; answer, чтобы разделить несколько подпапок (пусть sub1 и sub2) в новый репозиторий git.

The Easy Way & trade; (несколько подпапок)

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

    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, NOT ./subproject/

    Примечание для пользователей Windows:, когда глубина вашей папки > 1, <name-of-folder> должна иметь * nix style separator (/). Например, папка с именем path1\path2\subproject ДОЛЖНА быть передана как path1/path2/subproject. Кроме того, не используйте команду mv, а move.

    Конечная нота: уникальная и большая разница с базовым ответом - это вторая строка script "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 <[email protected]: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.

Ответ 9

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

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

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

I lost contiuity after filter-branch

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

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

Ответ 10

Чтобы добавить к Paul answer, я обнаружил, что в конечном итоге восстановить пространство, я должен нажать 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) не нужны с помощью push для очистки репозитория, то есть:

$ git clone --no-hardlinks /XYZ /ABC
$ git filter-branch --subdirectory-filter ABC HEAD
$ git reset --hard
$ git push ...ABC.git HEAD

Ответ 11

Правильный способ теперь следующий:

git filter-branch --prune-empty --subdirectory-filter FOLDER_NAME [first_branch] [another_branch]

GitHub теперь даже небольшая статья о таких случаях.

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

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

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

Ответ 12

Похоже, что большинство (всех?) ответов здесь опираются на некоторую форму git filter-branch --subdirectory-filter и ее ilk. Это может работать "чаще всего", однако для некоторых случаев, например, когда вы переименовали папку, например:

 ABC/
    /move_this_dir # did some work here, then renamed it to

ABC/
    /move_this_dir_renamed

Если вы создаете обычный стиль фильтра git для извлечения "move_me_renamed", вы потеряете историю изменений файла, которая произошла со спины, когда она была первоначально move_this_dir (ref).

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

  • локально локализовать проект с несколькими модулями
  • Филиалы - проверьте, что там: git branch -a
  • Выполните проверку каждой ветки, которая будет включена в разделение, чтобы получить локальную копию на вашей рабочей станции: git checkout --track origin/branchABC
  • Сделайте копию в новом каталоге: cp -r oldmultimod simple
  • Перейдите в новую копию проекта: cd simple
  • Избавьтесь от других модулей, которые не нужны в этом проекте:
  • git rm otherModule1 other2 other3
  • Теперь только субдир целевого модуля остается
  • Избавьтесь от поддиректора модуля, чтобы корень модуля стал новым корнем проекта
  • git mv moduleSubdir1/* .
  • Удалить реликвий subdir: 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 doc "Разделение вложенной папки в новый репозиторий" шаги 6-11, чтобы подтолкнуть модуль к новому репо.

Это не позволит вам сохранить какое-либо место в вашей папке .git, но оно сохранит всю историю изменений для этих файлов даже при переименовании. И это может не стоить того, если нет "большой" истории, потерянной и т.д. Но по крайней мере вы гарантированно не потеряете более старые коммиты!

Ответ 13

Для чего это стоит, вот как использовать GitHub на машине Windows. Скажем, у вас есть клонированное репо при проживании в C:\dir1. Структура каталогов выглядит так: C:\dir1\dir2\dir3. Каталог dir3 - это тот, который я хочу быть новым отдельным репо.

Github:

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

Bash Запрос:

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

  3. $ git remote add some_name [email protected]:MyTeam/mynewrepo.git
    git remote add origin etc. не работает, возвращается "remote origin already exists"

  4. $ git push --progress some_name master

Ответ 14

У меня была именно эта проблема, но все стандартные решения, основанные на ветки фильтра git, были чрезвычайно медленными. Если у вас есть небольшой репозиторий, это может быть не проблема, это было для меня. Я написал еще одну программу фильтрации git на основе libgit2, которая в качестве первого шага создает ветки для каждой фильтрации первичного репозитория, а затем подталкивает их к очистке репозиториев в качестве следующего шага. В моем репозитории (500 Мб 100000 коммитов) стандартные методы фильтрации с фильтрами git заняли несколько дней. Моя программа занимает минуты, чтобы сделать ту же фильтрацию.

У этого сказочного имени git_filter и живет здесь:

https://github.com/slobobaby/git_filter

на GitHub.

Я надеюсь, что это кому-то полезно.

Ответ 15

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

git filter-branch --index-filter \
"git rm -r -f --cached --ignore-unmatch DIR" --prune-empty \
--tag-name-filter cat -- --all

Ответ 16

Как я уже говорил , мне пришлось использовать обратное решение (удаление всех коммитов, не затрагивающих мой dir/subdir/targetdir), который, казалось, работал довольно хорошо, удаляя около 95% (по желанию). Однако есть два небольших вопроса.

FIRST, filter-branch выполнил работу по удалению коммитов, которые вводят или изменяют код, но, судя по всему, слияния находятся под его станцией в Gitiverse.

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

SECOND несколько оставшихся коммитов в значительной степени дублируются ВСЕ! Кажется, я приобрел вторую, лишнюю временную шкалу, охватывающую почти всю историю проекта. Интересная вещь (которую вы можете видеть из рисунка ниже) состоит в том, что мои три локальные ветки не все находятся на одной временной шкале (что, конечно же, почему она существует и не просто собирается мусором).

Единственное, что я могу себе представить, это то, что одним из удаленных коммитов было, пожалуй, одно единственное объединение, которое filter-branch действительно удалило, и это создало параллельную временную шкалу, поскольку каждая теперь невнесенная цепочка взяла свою собственную копию совершает. (пожал плечами Где мой ТАРДИ?) Я уверен, что смогу исправить эту проблему, хотя мне очень хотелось бы понять, как это произошло.

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

Ответ 17

Простой способ

  • установите git splits. Я создал его как расширение git, основанное на jkeating решении.
  • Разделите каталоги на локальную ветвь #change into your repo 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, у которого есть путь: [email protected]: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 [email protected]:simpliwp/xyz.git #push the branch to the empty repo master branch git push origin_xyz XYZ:master

  • Клонирование вновь созданного удаленного репо в новый локальный каталог
    #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 [email protected]:simpliwp/xyz.git

Ответ 18

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

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


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

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

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

  • Клонирование репозитория, содержащего подпапку.

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

Ответ 19

Вам может понадобиться что-то вроде "git reflog expire --expire = now - all" перед сборкой мусора, чтобы фактически очистить файлы. git фильтр-ветвь просто удаляет ссылки в истории, но не удаляет записи reflog, в которых хранятся данные. Конечно, сначала проверьте это.

Использование моего диска резко сократилось при этом, хотя мои начальные условия были несколько разными. Возможно, --subdirectory-filter отрицает эту потребность, но я сомневаюсь в этом.

Ответ 20

Посмотрите проект git_split на https://github.com/vangorra/git_split

Поверните каталоги git в свои собственные репозитории в своем собственном расположении. Нет поддерева смешного дела. Этот script будет использовать существующий каталог в вашем репозитории 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.

Ответ 21

Поместите это в свой 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'

Ответ 22

Я уверен, что git поддерево все прекрасно и прекрасно, но мои подкаталоги git управляемого кода, который я хотел переместить, были все в eclipse. Поэтому, если вы используете egit, это очень легко. Возьмите проект, который хотите переместить, и team- > отключите его, а затем team- > поделитесь им с новым местоположением. Он по умолчанию пытается использовать старое местоположение репо, но вы можете снять флажок существующего выбора и выбрать новое место для его перемещения. Все приветствуют egit.

Ответ 23

Вы можете легко попробовать 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

Ответ 24

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

1) Клонируйте репозиторий, который вы хотите разбить

git clone [email protected]: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 [email protected]:username/new_repo
git push -u origin master

Это. Вы можете повторить шаги, чтобы получить другой репозиторий,

просто удалите XY1, XY2 и переименуйте XYZ → ABC на шаге 3