하위 디렉토리를 별도의 Git 저장소로 분리(이동)
Git 저장소는 여러 개의 하위 디렉토리를 포함하고 있습니다.이제 하위 디렉토리 중 하나가 다른 디렉토리와 관련이 없으므로 다른 저장소에 분리해야 합니다.
서브디렉토리에 파일의 이력을 보관 유지한 채 어떻게 하면 좋을까요?
클론을 만들어 각 클론의 불필요한 부분을 제거할 수 있지만 오래된 리비전 등을 체크할 때는 완전한 트리를 얻을 수 있을 것입니다.이는 허용될 수 있지만 두 리포지토리에 공유 이력이 없는 것으로 가정할 수 있으면 좋겠습니다.
확실히 하기 위해서, 저는 다음과 같은 구조를 가지고 있습니다.
XYZ/
.git/
XY1/
ABC/
XY2/
하지만 대신 이렇게 하고 싶어요.
XYZ/
.git/
XY1/
XY2/
ABC/
.git/
ABC/
쉬운 방법™
이것은 Git의 오버로드에 의해 매우 쉽게 할 수 있을 정도로 일반적이고 유용한 방법이지만, Git의 새로운 버전(>= 2012년 5월 1.7.11일)이 필요합니다.최신 Git 설치 방법은 부록을 참조하십시오.또, 다음의 실사에서는, 실제의 예를 소개합니다.
이전 보고서를 준비합니다.
cd <big-repo> git subtree split -P <name-of-folder> -b <name-of-new-branch>
<name-of-folder>
선행 또는 후행 문자를 포함할 수 없습니다.를 들어, " " " 라는 이름의 입니다.subproject
로서 must must must must as as as as as must must라고 해야 합니다.subproject
../subproject/
Windows 사용자용 주의사항:폴더 깊이가 1을 넘으면<name-of-folder>
*nix style 폴더 구분 기호(/)가 있어야 합니다.를 들어, " " " 라는 이름의 입니다.path1\path2\subproject
로서 must must must must as as as as as must must라고 해야 합니다.path1/path2/subproject
새 보고서 작성
mkdir ~/<new-repo> && cd ~/<new-repo> git init git pull </path/to/big-repo> <name-of-new-branch>
새로운 레포와 GitHub 또는 기타 장소에 링크
git remote add origin <git@github.com:user/new-repo.git> git push -u origin master
「 」의
<big-repo>
필요한 경우git rm -rf <name-of-folder>
주의: 그러면 모든 이력 참조가 저장소에 남습니다.실제로 비밀번호를 커밋한 것이 걱정되거나 파일 크기를 줄여야 하는 경우 아래 부록을 참조하십시오..git
더입니니다다
워크스루
위의 절차와 동일하지만 다음 절차를 사용하여 저장소의 정확한 절차를 수행합니다.<meta-named-things>
.
다음은 노드에 JavaScript 브라우저 모듈을 구현하기 위한 프로젝트입니다.
tree ~/node-browser-compat
node-browser-compat
├── ArrayBuffer
├── Audio
├── Blob
├── FormData
├── atob
├── btoa
├── location
└── navigator
하고 싶습니다.btoa
의 Git
cd ~/node-browser-compat/
git subtree split -P btoa -b btoa-only
인 제 i a 。btoa-only
은 '커밋'btoa
새 저장소를 만들고 싶습니다.
mkdir ~/btoa/ && cd ~/btoa/
git init
git pull ~/node-browser-compat btoa-only
뭐 것에 Bitbucket, BitHub, Bitbucket으로 합니다.origin
git remote add origin git@github.com:node-browser-compat/btoa.git
git push -u origin master
해피데이!
주의: 다음을 사용하여 레포(repo:README.md
,.gitignore
★★★★★★★★★★★★★★★★★」LICENSE
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , .
git pull origin master
git push origin master
마지막으로 더 큰 리포에서 폴더를 제거하고 싶습니다.
git rm -rf btoa
부록
최신 Git on macOS
Homebrew를 사용하여 Git의 최신 버전을 얻으려면:
brew install git
Ubuntu의 최신 Git
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 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 등에서 이력을 삭제하는 것을 의미하는 "origin"에서 이력을 삭제하려면 repo를 삭제하고 repo의 가지치기된 복사본을 다시 푸시해야 합니다.하지만 더 있습니다!- 비밀번호 등의 삭제가 걱정된다면 백업을 삭제해야 합니다(아래 참조).
★★★의 .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
즉, 이러한 순서는, 필요한 경우가 아니면 실행하지 않는 것이 좋습니다.서브 디렉토리를 잘못 삭제했을 경우를 대비해서입니다.repo를 푸시할 때 백업 파일이 복제되지 않아야 합니다. 백업 파일은 로컬 복사본에 있을 뿐입니다.
신용 거래
- http://psionides.eu/2010/02/04/sharing-code-between-projects-with-git-subtree/
- git에서 영구적으로 디렉터리 제거
- http://blogs.atlassian.com/2013/05/alternatives-to-git-submodule-git-subtree/
- 내 git repo에서 참조되지 않은 blob을 제거하는 방법
업데이트: 이 과정은 매우 일반적이기 때문에 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
서브프로젝트와 무관한 태그도 삭제할 수 있습니다.나중에 삭제할 수도 있지만 repo를 다시 삭제해야 할 수도 있습니다.나는 그렇게 하지 않고 받았다.
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
이제 ABC 서브디렉토리의 로컬 git 저장소가 있고 모든 이력이 보존되어 있습니다.
, 「」: 「」는,git filter-branch
추가된 파라미터가 .-- --all
네, 그거는 정말 all
명령어의 마지막 파라미터여야 합니다.Matli가 발견한 바와 같이 새로운 리포트에 포함된 프로젝트 브랜치 및 태그가 유지됩니다.
편집: 예를 들어 저장소를 실제로 축소할 수 있도록 하기 위해 아래 코멘트의 다양한 제안이 통합되었습니다(이전에는 항상 그랬던 것은 아닙니다).
Paul의 답변은 /ABC를 포함하는 새 저장소를 생성하지만 /XYZ 내에서 /ABC를 제거하지는 않습니다.다음 명령어는 /XYZ 내에서 /ABC를 삭제합니다.
git filter-branch --tree-filter "rm -rf ABC" --prune-empty HEAD
물론 먼저 'clone --no-hardlinks' 저장소에서 테스트한 후 Paul이 나열한 reset, gc 및 prune 명령을 사용하여 테스트합니다.
새 저장소에서 오래된 이력을 올바르게 삭제하려면 다음 작업을 조금 더 수행해야 합니다.filter-branch
discloss.disclosed.
클론 및 필터를 수행합니다.
git clone --no-hardlinks foo bar; cd bar git filter-branch --subdirectory-filter subdir/you/want
이전 이력에 대한 모든 참조를 제거합니다."clone"은 클론을 추적하고 "original"은 필터 필터가 오래된 데이터를 저장하는 곳입니다.
git remote rm origin git update-ref -d refs/original/refs/heads/master git reflog expire --expire=now --all
지금도 Fsck가 터치하지 않는 팩 파일에 기록이 남아 있을 수 있습니다.완전히 분해하여 새 팩 파일을 만들고 사용되지 않는 개체를 삭제합니다.
git repack -ad
이에 대한 설명은 filter-branch 매뉴얼에 기재되어 있습니다.
" " 를 실행하고 git filter-branch
의 " " " 를 사용합니다.git
)2.22+
아마도?)이 새로운 툴 git-filter-repo를 사용하라고 되어 있습니다.이 도구는 확실히 나에게 일을 단순화시켜 주었다.
filter-repo를 사용한 필터링
를 작성하는 XYZ
: rep번번번번 번 rep rep 。
# create local clone of original repo in directory XYZ
tmp $ git clone git@github.com:user/original.git XYZ
# switch to working in XYZ
tmp $ cd XYZ
# keep subdirectories XY1 and XY2 (dropping ABC)
XYZ $ git filter-repo --path XY1 --path XY2
# note: original remote origin was dropped
# (protecting against accidental pushes overwriting original repo data)
# XYZ $ ls -1
# XY1
# XY2
# XYZ $ git log --oneline
# last commit modifying ./XY1 or ./XY2
# first commit modifying ./XY1 or ./XY2
# point at new hosted, dedicated repo
XYZ $ git remote add origin git@github.com:user/XYZ.git
# push (and track) remote master
XYZ $ git push -u origin master
전제조건: * 리모트 XYZ repo는 푸시 전에 신규로 비어 있었습니다.
필터링 및 이동
저 같은 경우에는 좀 더 일관된 구조를 위해 디렉토리를 몇 개 옮기고 싶었습니다.처음에는 그렇게 간단하게 뛰었는데filter-repo
에 " "가"가 계속됩니다.git mv dir-to-rename
'더 ' 더 잘 알 수 을 알게 되었습니다.--path-rename
으로 수정한 것을 , 마지막으로 수정한 것을 보는 것이 좋습니다.5 hours ago
했습니다.last year
(GitHub UI) repo.
대신...
git filter-repo --path XY1 --path XY2 --path inconsistent
git mv inconsistent XY3 # which updates last modification time
난 결국 도망쳤지...
git filter-repo --path XY1 --path XY2 --path inconsistent --path-rename inconsistent:XY3
Notes:
- Git Rev News 블로그 투고는 또 다른 리포필터링 툴을 만든 이유를 잘 설명해 주었다고 생각합니다.
- 처음에 원래 저장소의 대상 repo 이름과 일치하는 하위 디렉토리를 만든 다음 필터링하는 경로를 시도했습니다.
git filter-repo --subdirectory-filter dir-matching-new-repo-name
하기 위해서 은 아직 깨닫지--path
여러 번 지정할 수 있기 때문에 소스 레포에 서브 디렉토리를 작성할 필요가 없습니다.)내가 역사를 발전시키는데 실패했다는 걸 알았을 때 누군가가 소스 리포에 전념했기 때문에, 나는 그냥 그것을 사용했다.git reset commit-before-subdir-move --hard
그clone
.--force
filter-repo
명령어를 사용하여 약간 변경된 로컬클론에서 동작하도록 합니다.
git clone ...
git reset HEAD~7 --hard # roll back before mistake
git filter-repo ... --force # tell filter-repo the alterations are expected
- 이 확장 패턴에 대해 몰랐기 때문에 설치 중에 당황했습니다.
git
최종적으로는 git-filter-repo를 복제하여 에 심볼릭 링크했습니다.$(git --exec-path)
:
ln -s ~/github/newren/git-filter-repo/git-filter-repo $(git --exec-path)
편집: Bash 스크립트가 추가되었습니다.
여기에 제시된 답변은 부분적으로만 유효했습니다. 많은 대용량 파일이 캐시에 남아 있었습니다.최종적으로 동작한 것 (#git on 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
이전 솔루션에서는 저장소 크기가 약 100MB였습니다.이것은 1.7MB로 줄였습니다.아마 도움이 될 거예요:)
다음 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 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-interree는 이 경우에 도움이 될 수 있습니다.
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/
여기 쿨에 대한 작은 수정 사항이 있습니다.여러 개의 하위 폴더를 분할하기 위한 AJ86의 "The Easy Way™" 답변(예:sub1
★★★★★★★★★★★★★★★★★」sub2
저장소로 을 받다
Easy Way™(하위 폴더 추가)
이전 보고서를 준비합니다.
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
로서 must must must must as as as as as must must라고 해야 합니다.subproject
../subproject/
Windows 사용자용 주의사항: 폴더 깊이가1을 넘으면
<name-of-folder>
*nix style 폴더 구분 기호(/)가 있어야 합니다.를 들어, " " " 라는 이름의 입니다.path1\path2\subproject
로서 must must must must as as as as as must must라고 해야 합니다.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/(*files)를 ABC/ABC/(*files)로 합니다.자신의 코드에 대해 승인된 답변을 구현한 후 XYZ/ABC/(*files)가 실제로 ABC/(*files)로 변경된다는 것을 알게 되었습니다.'필터 브랜치맨' 페이지에는 이렇게도 써있어요
결과에는 그 디렉토리(그것만)가 프로젝트 루트로 포함됩니다."
즉, 최상위 폴더를 한 단계 위로 승격합니다.이것은 중요한 차이입니다. 예를 들어, 제 이력에서는 최상위 폴더의 이름을 바꾸었습니다.폴더를 "위로" 승격하면 git은 내가 이름을 바꾼 커밋에서 연속성을 잃습니다.
이 질문에 대한 답변은 저장소의 복사본을 2개 만들고 각각 보관할 폴더를 수동으로 삭제하는 것입니다.man 페이지에는 다음과 같은 정보가 표시됩니다.
[...] 간단한 단일 커밋으로 문제를 해결할 수 있다면 [이 명령어]를 사용하지 마십시오.
Paul의 답변에 덧붙이자면 궁극적으로 공간을 회복하기 위해서는 HEAD를 깨끗한 저장소로 푸시해야 하며, 그러면 .git/objects/pack 디렉토리의 크기가 작아진다는 것을 알게 되었습니다.
예.
$mkdir...ABC.git$ cd...ABC.git$git init --개요
gc 플루닝 후 다음 작업도 수행합니다.
$g push...ABC.git 헤드
그럼 넌 할 수 있어
$g 클론...ABC.git
ABC/.git의 사이즈가 작아졌습니다.
실제로 저장소 청소에는 시간이 많이 걸리는 단계(git gc 등)가 필요하지 않습니다.
$git 클론 --하드링크 없음 /XYZ /ABC$git filter-branch --subdirectory-filter ABC HEAD$git reset --hard$g push...ABC.git 헤드
대부분의 은, 「의」에 하고 있는 것 .git filter-branch --subdirectory-filter
그리고 그것은 비슷합니다.의 경우 있을 수 예를 폴더 "대부분"입니다. 를 들어 과 같습니다.
ABC/
/move_this_dir # did some work here, then renamed it to
ABC/
/move_this_dir_renamed
일반 git 필터 스타일을 사용하여 "move_this_dir_renamed"를 추출하면 "move_this_dir"(ref)일 때 발생한 파일 변경 이력이 손실됩니다.
따라서 모든 변경 이력을 실제로 유지하는 유일한 방법은 기본적으로 저장소를 복사하고(새로운 repo를 생성하여 원본으로 설정), 다른 모든 것을 nuke하여 서브디렉토리의 이름을 다음과 같이 부모에게 변경하는 것입니다.
- 다중 모듈 프로젝트를 로컬로 복제
- -.
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 repo를 만들고 URL을 복사하여 이 프로젝트를 가리킵니다.
git remote set-url origin http://mygithost:8080/git/our-splitted-module-repo
- 확인합니다.
git remote -v
- 을 리모트 (「Remote repo까지 푸시 합니다.
git push
- 리모트 레포에 접속하여 모든 것이 갖추어져 있는지 확인합니다.
- 합니다.
git checkout branch2
이 절차에서는 github 문서 "하위 폴더를 새 저장소로 분할" 단계 6-11에 따라 모듈을 새 저장소로 푸시합니다.
이렇게 해도 .git 폴더에 공간이 절약되지는 않지만 이름을 바꾸더라도 해당 파일의 모든 변경 이력은 유지됩니다.그리고 잃어버린 역사가 "많이" 있지 않다면 이것은 가치가 없을지도 모른다.하지만 적어도 당신은 오래된 커밋을 잃지 않을 것이 보장된다!
현재 적절한 방법은 다음과 같습니다.
git filter-branch --prune-empty --subdirectory-filter FOLDER_NAME [first_branch] [another_branch]
GitHub은 이제 그러한 사례에 대한 작은 기사도 가지고 있다.
다만, 원래의 레포는 반드시 다른 디렉토리에 클론 해 주세요(모든 파일이나 다른 디렉토리가 삭제되기 때문에, 그것들을 조작할 필요가 있습니다.
따라서 알고리즘은 다음과 같습니다.
- 원격 보고서를 다른 디렉터리로 복제
- 를 사용합니다.
git filter-branch
서브디렉토리 new 로 이동 - create commit을 생성하여 원래 리모트리포에서 이 서브디렉토리를 삭제합니다.
하위 폴더를 새 저장소로 분할하는 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 filter-branch에 근거한 표준 솔루션은 모두 매우 느렸습니다.저장소가 작으면 문제없을지도 모르지만, 그건 제 몫이었습니다.저는 libgit2에 기반한 git 필터링 프로그램을 하나 더 작성했습니다.첫 번째 단계는 프라이머리 저장소의 필터링마다 브랜치를 만들고 다음 단계는 클린 저장소로 푸시하는 것입니다.내 저장소(500Mb 100000 커밋)에서는 표준 git 필터 브랜치 메서드가 며칠이 걸렸습니다.프로그램이 동일한 필터링을 수행하는 데 몇 분 정도 걸립니다.
git_filter라는 멋진 이름을 가지고 있으며 여기에 있습니다.
https://github.com/slobobaby/git_filter
GitHub에 있습니다.
누군가에게 도움이 됐으면 좋겠어요.
태그와 브랜치를 유지하면서 서브 디렉토리를 삭제하려면 다음 filter 명령을 사용합니다.
git filter-branch --index-filter \
"git rm -r -f --cached --ignore-unmatch DIR" --prune-empty \
--tag-name-filter cat -- --all
Windows hub GitHub windows windows windows 。 리포에 해 보겠습니다.C:\dir1
구조는 C:\dir1\dir2\dir3
. 。dir3
디렉토리는 새로운 개별 리포트가 되고 싶은 디렉토리입니다.
Github:
- .
MyTeam/mynewrepo
배시 프롬프트:
$ 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
위에서 언급했듯이, 저는 역방향 솔루션을 사용해야 했습니다(모든 커밋을 삭제한 후,dir/subdir/targetdir
(원하는 대로) 커밋의 약 95%를 삭제해도 꽤 효과가 있는 것 같습니다.그러나 두 가지 작은 문제가 남아 있습니다.
일단은filter-branch
코드를 도입하거나 수정하는 커밋을 삭제하는 작업을 대폭 수행했지만, Gitiverse의 스테이션 아래에 머지 커밋이 있는 것 같습니다.
이것은 내가 감수할 수 있는 외관상의 문제일 것이다(그는 말한다)시선을 피한 채 천천히 뒤로 물러난다.)
둘째, 남아 있는 몇 안 되는 커밋은 거의 모두 중복됩니다.저는 프로젝트의 전체 역사에 걸쳐 있는 두 번째 중복 타임라인을 획득한 것 같습니다.흥미로운 것은(아래 그림에서 알 수 있듯이) 3개의 로컬 지점이 모두 같은 타임라인 상에 있는 것은 아니라는 것입니다(그 때문에, 확실히 존재해, 단지 쓰레기 수집이 아닌 것이 아닙니다.
가 상상할 수 있는 된 커밋 중 단일 커밋은 「」 「」 「」 「」 「」 「」 「」 「」 「」 「」 「」입니다.filter-branch
실제로 삭제가 이루어졌고, 이제 병합된 각 스트랜드가 커밋의 복사본을 가져옴에 따라 병렬 타임라인이 생성되었습니다.내 타디스 어딨어?저는 이 문제를 해결할 수 있다고 확신하지만, 어떻게 된 일인지 정말 알고 싶습니다.
미친 mergefest-O-RAMA의 경우, 저는 그것을 내버려 둘 것입니다. 왜냐하면 그것은 제 약속 이력에 확고히 자리 잡고 있기 때문입니다(제가 가까이 올 때마다 저를 위협하고 있습니다). 실제로 외관상의 문제를 일으키고 있는 것 같지도 않고 타워어플리케이션에서 매우 예쁘기 때문입니다.
더 쉬운 방법
- 설치. jkeyating의 솔루션을 기반으로 git 확장자로 만들었습니다.
를 로 분할하다
#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레포하다빈 (repo)를 .
xyz
에서 GitHub 경로 : 로로 、 git on 、 on :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
가비지 컬렉션 전에 파일을 실제로 클리어하기 위해 "filter reflog expirate --filter=now --all"과 같은 것이 필요할 수 있습니다.git filter-filter-filter는 이력 내의 참조만 삭제하지만 데이터를 보관하고 있는 reflog 엔트리는 삭제되지 않습니다.물론 이것부터 테스트해 보세요.
초기 상태는 다소 달랐지만, 이 작업을 통해 디스크 사용량이 크게 감소했습니다.아마도 --subdirectory-filter는 이러한 요구를 부정할 수 있지만, 저는 그렇게 생각하지 않습니다.
https://github.com/vangorra/git_split에서 git_filename 프로젝트를 확인하세요.
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 관리 코드의 서브 디렉토리는 모두 일식이었습니다.그래서 만약 당신이 이기트를 사용한다면, 고통스러울 정도로 쉽다.이동할 프로젝트를 가져와서 팀-> 연결을 끊고 팀-> 새 위치로 공유합니다.기본적으로 이전 repo 위치를 사용하려고 하지만 기존 사용 선택 항목을 선택 취소하고 새 위치를 선택하여 이동할 수 있습니다.모두 기립하라.
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를 따릅니다.
매우 간단한 솔루션을 찾았습니다.저장소를 복사한 후 불필요한 부품만 제거하면 됩니다.동작은 다음과 같습니다.
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
바로 그겁니다.이 단계를 반복하여 다른 저장소를 가져올 수 있습니다.
순서 3에서 XY1, XY2를 삭제하고 XYZ -> ABC 이름을 변경하기만 하면 됩니다.
이 훌륭한 기사 원본 참조는 이해하기 쉬웠다.접근할 수 없게 될 경우를 대비해서 여기에 문서화합니다.
1. 현재 저장소 준비
$ cd path/to/repository
$ git subtree split -P my-folder -b my-folder
Created branch 'my-folder'
aecbdc3c8fe2932529658f5ed40d95c135352eff
폴더 이름은 저장소 루트부터 시작하는 상대 경로여야 합니다.
2. 새로운 저장소 작성
$ cd my-folder
$ git init
Initialized empty Git repository in /Users/adamwest/Projects/learngit/shop/my-folder/.git/
$ git add .
$ git commit -m "initial commit"
[master (root-commit) 192c10b] initial commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file
여기서는 새 폴더에 CD를 넣고 새 저장소를 초기화하고 내용을 커밋하기만 하면 됩니다.
3. 새로운 리모트 저장소 추가 및 푸시
$ git remote add origin git@github.com:robertlyall/my-folder.git
$ git push origin -u master
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 199 bytes | 199.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To github.com:robertlyall/my-folder.git
* [new branch] master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
여기에 GitHub에서 리모트로 새로운 저장소를 추가하고 첫 번째 커밋을 푸시합니다.
4. 메인 저장소에서 폴더를 제거하고 를 누릅니다.
$ cd ../
$ git rm -rf my-folder
rm 'my-folder/file'
$ git commit -m "Remove old folder"
[master 56aedbe] remove old folder
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 my-folder/file
$ git push
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Delta compression using up to 4 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 217 bytes | 217.00 KiB/s, done.
Total 2 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To github.com:robertlyall/shop.git
74dd8b3..56aedbe master -> master
마지막으로 Rooot 디렉토리로 돌아가서 폴더를 메인저장소에서 삭제한 후 변경을 커밋하고 푸시합니다.메인 저장소에 폴더가 있지만 여러 프로젝트에서 재사용할 수 있는 완전히 다른 저장소에 링크되어 있습니다.
언급URL : https://stackoverflow.com/questions/359424/detach-move-subdirectory-into-separate-git-repository
'programing' 카테고리의 다른 글
새로운 기준 자동 계수 메커니즘은 어떻게 작동합니까? (0) | 2023.04.10 |
---|---|
실행 시 값으로 strings.xml에 플레이스 홀더를 지정할 수 있습니까? (0) | 2023.04.10 |
Microsoft Office Excel에서 'c:\inetpub\wwwroot\' 파일에 액세스할 수 없습니다.타임시트\App_Data\템플릿xlsx' (0) | 2023.04.10 |
서버와의 접속은 정상적으로 확립되었지만, 로그인 프로세스중에 에러가 발생했습니다.(에러 번호: 233) (0) | 2023.04.10 |
인스턴스 멤버를 형식에 사용할 수 없습니다. (0) | 2023.04.10 |