Вы можете нарисовать эту часть по частям с помощью функций drawLine()
и drawArc()
из Canvas
.
Обновление: этот процесс настолько распространен, что команда git сделала это намного проще с помощью нового инструмента git subtree
. См. Здесь: Подкаталог Detach (перемещение) в отдельный репозиторий 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
. --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
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
. Да, это действительно - space - all
. Это должны быть последние параметры для команды. Поскольку Мэтли обнаружил, это удерживает ветви проекта и теги, включенные в новое репо.
Изменить: различные предложения из комментариев ниже были включены, чтобы убедиться, например, что хранилище фактически сокращено (что не было всегда раньше).
Похоже, что большинство (все?) ответов здесь опираются на некоторую форму 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 ).
Таким образом, кажется, что единственный способ действительно сохранить все история (если ваш случай подобен этому), по сути, копировать репозиторий (создать новое репо, установить его как начало), затем уничтожить все остальное и переименовать подкаталог родительскому элементу следующим образом:
git branch -a
git checkout --track origin/branchABC
cp -r oldmultimod simple
cd simple
git rm otherModule1 other2 other3
git mv moduleSubdir1/* .
rmdir moduleSubdir1
git status
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, но оно сохранит всю историю изменений для этих файлов даже переименования. И это может не стоить того, если нет «большой» истории, потерянной и т. Д. Но по крайней мере вам гарантировано не потерять более старые коммиты!
Используйте эту команду фильтра, чтобы удалить подкаталог, сохраняя ваши теги и ветви:
git filter-branch --index-filter \
"git rm -r -f --cached --ignore-unmatch DIR" --prune-empty \
--tag-name-filter cat -- --all
git splits
. Я создал его как расширение git, основанное на решении 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
#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
git filter-branch --index-filter "git rm -r -f --cached --ignore-unmatch ABC" --prune-empty HEAD
, и он будет намного быстрее. индексный фильтр работает с индексом, тогда как древовидный фильтр должен проверять и выполнять все для каждой фиксации .
– fmarc
17 September 2009 в 20:58
--index-filter
, вы также можете сделать это git rm -q -r -f
, чтобы каждый вызов не печатал строку для каждого удаляемого файла.
– Eric Naeseth
12 October 2011 в 20:55
git subtree
по-прежнему входит в папку «contrib» и по умолчанию не установлен на всех дистрибутивах. github.com/git/git/blob/master/contrib/subtree
– onionjake
2 August 2013 в 15:06
ABC/
, но новое репо не содержит самой папки ABC/
, как задал вопрос. Как бы вы это сделали?
– woojoo666
8 October 2014 в 13:14
git splits
)
– M.M
12 May 2015 в 05:58
sub1
и sub2
папки не существовали с исходной версией, мне пришлось изменить сценарий --tree-filter
следующим образом: "mkdir <name-of-folder>; if [ -d sub1 ]; then mv <sub1> <name-of-folder>/; fi"
. Для второй команды filter-branch
я заменил & lt; sub1 & gt; с & lt; sub2 & gt ;, опустил создание & lt; имя-папки & gt ;, и включил -f
после filter-branch
, чтобы переопределить предупреждение существующей резервной копии.
– pglezen
11 February 2016 в 20:38
Поместите это в свой 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'
Для чего это стоит, вот как использовать GitHub на машине Windows. Допустим, у вас есть клонированное репо, проживающее в C:\dir1
. Структура каталогов выглядит так: C:\dir1\dir2\dir3
. Каталог dir3
является тем, кем я хочу стать новым отдельным репо.
Github:
MyTeam/mynewrepo
Bash Prompt:
$ cd c:/Dir1
$ git filter-branch --prune-empty --subdirectory-filter dir2/dir3 HEAD
Возврат: Ref 'refs/heads/master' was rewritten
(fyi: 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
Это уже не так сложно, вы можете просто использовать команду git filter-branch на клоне вашего репо, чтобы отбросить подкаталоги, которые вам не нужны, а затем нажать на новый пульт.
git filter-branch --prune-empty --subdirectory-filter <YOUR_SUBDIR_TO_KEEP> master
git push <MY_NEW_REMOTE_URL> -f .
The result will contain that directory (and only that) as its project root.
, и действительно, это то, что вы получите, т. Е. Исходная структура проекта не сохраняется.
– NicBright
2 June 2017 в 13:11
Я обнаружил, что для правильного удаления старой истории из нового репозитория вам нужно сделать немного больше работы после шага 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
git repack -ad
Существует объяснение этого в руководстве для фильтра ветвп .
git gc --aggressive --prune=now
все еще отсутствует, не так ли?
– Albert
11 July 2012 в 21:14
git gc --aggressive --prune=now
уменьшил большую часть нового репо
– Tomek Wyderka
2 April 2013 в 10:01
Оригинальный вопрос хочет, чтобы XYZ / ABC / (* файлы) стали ABC / ABC / (* файлами). После выполнения принятого ответа для моего собственного кода я заметил, что он фактически изменяет XYZ / ABC / (* файлы) в ABC / (* файлы). Страница man filter-branch даже говорит:
Результат будет содержать этот каталог (и только это) в качестве его корня проекта . "
blockquote >Другими словами, он продвигает папку верхнего уровня «вверх» на один уровень. Это важное различие, потому что, например, в моей истории я переименовал папку верхнего уровня. Продвигая папки «вверх» на один уровень , git теряет непрерывность в commit, где я сделал переименование.
[/g1]
Тогда мой ответ на вопрос состоит в том, чтобы сделать 2 копии репозитория и вручную удалите папку (ы), которую вы хотите сохранить в каждой странице. man-страница поддерживает меня следующим образом:
[...] избегать использования [этой команды], если достаточно простого синтаксиса для исправления вашей проблемы
blockquote>
targetdir
была переименована в какой-то момент, а git filter-branch
просто назвала ее днем, удалив все коммиты, сделанные до переименования! Шокирующий, учитывая, насколько адепт Git отслеживает такие вещи и даже перемещает отдельные куски контента!
– Jay Allen
31 May 2013 в 10:25
git rm
принимает несколько аргументов, поэтому нет причин запускать его для каждого файла / папки: BYEBYE="dir/subdir2 dir2 file1 dir/file2"; git filter-branch -f --index-filter "git rm -q -r -f --cached --ignore-unmatch $BYEBYE" --prune-empty -- --all
– Jay Allen
31 May 2013 в 10:26
Правильный способ теперь следующий:
git filter-branch --prune-empty --subdirectory-filter FOLDER_NAME [first_branch] [another_branch]
GitHub теперь даже имеет малую статью о таких случаях.
Но обязательно клонируйте свое первоначальное репо, чтобы сначала отделить каталог (так как он удалит все файлы и другие каталоги, и вам, вероятно, придется работать с ними).
Итак, ваш алгоритм должен быть:
git filter-branch
только файлы слева под некоторым подкаталогом, нажмите на новый пульт Изменить: добавлен скрипт 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, были очень медленными. Если у вас есть небольшой репозиторий, это может быть не проблема, это было для меня. Я написал еще одну программу фильтрации git на основе libgit2, которая в качестве первого шага создает ветви для каждой фильтрации первичного репозитория, а затем выталкивает их для очистки репозиториев в качестве следующего шага. В моем хранилище (500 Мб 100000 коммитов) стандартные методы фильтрации фильтров git занимали дни. Моя программа занимает несколько минут, чтобы выполнить ту же фильтрацию.
У этого сказочного имени git_filter и живет здесь:
https://github.com/slobobaby/git_filter
на GitHub.
Надеюсь, это кому-то полезно.
Я рекомендую руководство GitHub по разделению подпапок в новый репозиторий . Шаги похожи на ответ Paul , но я понял, что их инструкции легче понять.
Я изменил инструкции, чтобы они применились к локальному репозиторию, а не к размещенному на нем 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
If you create a new clone of the repository, you won't lose any of your Git history or changes when you split a folder into a separate repository.
. Однако согласно комментариям ко всем ответам здесь сценарии filter-branch
и subtree
приводят к потере истории везде, где был переименован подкаталог. Есть ли что-то, что можно сделать для решения этой проблемы?
– Adam
30 October 2017 в 12:53
Я уверен, что поддерева git прекрасна и прекрасна, но мои подкаталоги git-кода, которые я хотел переместить, были в затмении. Поэтому, если вы используете egit, это очень легко. Возьмите проект, который хотите переместить, и team-> отключите его, а затем team-> поделитесь им с новым местоположением. Он по умолчанию пытается использовать старое местоположение репо, но вы можете снять флажок существующего выбора и выбрать новое место для его перемещения. Все приветствуют.
Вам может понадобиться что-то вроде «git reflog expire --expire = now -all» перед сборкой мусора, чтобы фактически очистить файлы. git filter-branch просто удаляет ссылки в истории, но не удаляет записи reflog, которые хранят данные. Конечно, сначала проверьте это.
Использование моего диска резко сократилось при этом, хотя мои начальные условия были несколько разными. Возможно, фильтр subdirectory отрицает эту потребность, но я сомневаюсь.
Проверьте проект 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.
--no-hardlinks
? Удаление одного жесткого диска не повлияет на другой файл. Объекты Git тоже неизменяемы. Только если вы измените права владельца / файла, вам понадобится--no-hardlinks
. – vdboor 1 February 2010 в 10:58filter-branch
является--prune-empty
, чтобы удалить теперь - пустые коммиты. – Seth Johnson 12 September 2011 в 03:31-- --all
. Я также выполнилgit remote rm origin
иgit tag -l | xargs git tag -d
перед командойgit filter-branch
. Это уменьшило мой каталог.git
с 60 до 300K. Обратите внимание, что мне нужно было запустить обе эти команды, чтобы получить уменьшение размера. – saltycrane 17 November 2011 в 23:18