etc./StackOverFlow

하위 디렉토리를 별도의 Git 저장소로 분리(이동)

청렴결백한 만능 재주꾼 2021. 12. 28. 01:51
반응형

질문자 :matli


여러 하위 디렉토리가 포함된 Git 리포지토리가 있습니다. 이제 하위 디렉토리 중 하나가 다른 디렉토리와 관련이 없고 별도의 저장소로 분리되어야 한다는 것을 발견했습니다.

하위 디렉토리 내에서 파일의 기록을 유지하면서 이 작업을 수행하려면 어떻게 해야 합니까?

나는 클론을 만들고 각 클론의 원하지 않는 부분을 제거할 수 있다고 생각하지만 이것이 이전 버전 등을 체크아웃할 때 완전한 트리를 제공할 것이라고 생각합니다. 이것은 받아들일 수 있지만, 두 개의 리포지토리에 공유 기록이 없습니다.

명확하게하기 위해 다음과 같은 구조가 있습니다.

 XYZ/ .git/ XY1/ ABC/ XY2/

하지만 대신 다음을 원합니다.

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


쉬운 방법™

이것은 Git의 대군주들이 정말 쉽게 만들었지만, 최신 버전의 Git(>= 2012년 5월 1.7.11일)이 있어야 하는 매우 일반적이고 유용한 방법이라는 것이 밝혀졌습니다. 최신 Git 설치 방법 은 부록 을 참조하세요. 또한 아래 연습실제 예가 있습니다.

  1. 이전 리포지토리 준비

     cd <big-repo> git subtree split -P <name-of-folder> -b <name-of-new-branch>

참고: <name-of-folder> 는 선행 또는 후행 문자를 포함할 수 없습니다. 예를 들어, subproject 라는 폴더는 ./subproject/가 아닌 subproject 로 전달 ./subproject/

Windows 사용자를 위한 참고 사항: 폴더 깊이가 > 1인 경우 <name-of-folder> 에는 *nix 스타일 폴더 구분 기호(/)가 있어야 합니다. 예를 들어 path1\path2\subproject path1/path2/subproject 로 전달되어야 합니다.

  1. 새 리포지토리 만들기

     mkdir ~/<new-repo> && cd ~/<new-repo> git init git pull </path/to/big-repo> <name-of-new-branch>
  2. 새 리포지토리를 GitHub 또는 어디에나 연결합니다.

     git remote add origin <git@github.com:user/new-repo.git> git push -u origin master
  3. 원하는 경우 <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

지금, 새로운 지점을 가지고 btoa-only 단지에 대한 커밋이 있는지, btoa 나는 새 저장소를 만들려고합니다.

 mkdir ~/btoa/ && cd ~/btoa/ git init git pull ~/node-browser-compat btoa-only

다음으로 GitHub 또는 Bitbucket 또는 무엇이든 새 리포지토리를 만들고 origin

 git remote add origin git@github.com:node-browser-compat/btoa.git git push -u origin master

행복한 날!

참고: README.md , .gitignoreLICENSE 사용하여 리포지토리를 만든 경우 먼저 다음을 가져와야 합니다.

 git pull origin master git push origin master

마지막으로 더 큰 저장소에서 폴더를 제거하고 싶습니다.

 git rm -rf btoa

부록

macOS의 최신 Git

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 push git pull 해야 합니다. 그런 다음 기록에 있는 모든 것을 갖게 됩니다.

따라서 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

즉, 필요한 경우가 아니면 이러한 단계를 수행하지 않는 것이 좋습니다. 리포지토리를 푸시할 때 백업 파일이 복제되어서는 안 되며 로컬 복사본에만 있을 것입니다.

신용 거래


coolaj86

업데이트 : 이 프로세스는 너무 일반적이어서 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

    또는 HEAD 분기만 다시 작성하고 태그 및 기타 분기를 무시하려면:

     git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC HEAD
  5. 그런 다음 백업 reflog를 삭제하여 공간을 진정으로 회수할 수 있도록 합니다(지금은 작업이 파괴적이지만).

     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가 발견했듯이 이것은 프로젝트 분기와 태그를 새 리포지토리에 포함된 상태로 유지합니다.

편집: 예를 들어 저장소가 실제로 축소되었는지 확인하기 위해 아래 주석의 다양한 제안이 통합되었습니다(이전에는 항상 그런 것은 아님).


Community Wiki

Paul의 답변 은 /ABC가 포함된 새 저장소를 생성하지만 /XYZ 내에서 /ABC를 제거하지는 않습니다. 다음 명령은 /XYZ 내에서 /ABC를 제거합니다.

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

물론 먼저 'clone --no-hardlinks' 저장소에서 테스트하고 Paul이 나열한 reset, gc 및 prune 명령을 따르십시오.


pgs

새 저장소에서 이전 기록을 적절하게 삭제하려면 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. 지금도 fsck가 건드리지 않는 팩 파일에 기록이 남아 있을 수 있습니다. 조각으로 찢어 새 팩 파일을 만들고 사용하지 않는 개체를 삭제합니다.

     git repack -ad

filter-branch 매뉴얼에 이에 대한 설명이 있습니다.


Josh Lee

편집: Bash 스크립트가 추가되었습니다.

여기에 제공된 답변은 저에게 부분적으로만 효과가 있었습니다. 많은 대용량 파일이 캐시에 남아 있었습니다. 마침내 효과가 있었던 것(freenode의 #git에서 몇 시간 후):

 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

Simon A. Eugster

이것은 더 이상 복잡하지 않습니다. 리포지토리의 복제본에서 git filter-branch 명령을 사용하여 원하지 않는 하위 디렉터리를 컬링한 다음 새 원격으로 푸시할 수 있습니다.

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

jeremyjjbrown

최신 버전의 git ( 2.22+ git filter-branch 를 실행할 때 이 새 도구 git-filter-repo 를 사용하라고 되어 있습니다. 이 도구는 확실히 나를 위해 일을 단순화했습니다.

filter-repo로 필터링

원래 질문에서 XYZ 저장소를 만드는 명령:

 # 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 저장소는 푸시 전에 새롭고 비어 있었습니다.

필터링 및 이동

제 경우에는 보다 일관된 구조를 위해 몇 개의 디렉토리를 옮기고 싶었습니다. 처음에는 git mv dir-to-rename filter-repo 명령을 실행 --path-rename 옵션을 사용하여 약간 "더 나은" 기록을 얻을 수 있다는 것을 알았습니다. 새 리포지토리에서 이동된 파일에 대해 5 hours ago 마지막으로 수정된 것을 보는 대신에 원래 리포지토리의 수정된 시간과 일치하는 last year

대신에...

 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
노트:
  • Git Rev News 블로그 게시물이 또 다른 repo-filtering 도구를 만드는 이유를 잘 설명했다고 생각했습니다.
  • 처음에는 원본 저장소의 대상 저장소 이름과 일치하는 하위 디렉터리를 만든 다음 필터링 git filter-repo --subdirectory-filter dir-matching-new-repo-name ). 이 명령은 해당 하위 디렉터리를 복사된 로컬 저장소의 루트로 올바르게 변환했지만 하위 디렉터리를 만드는 데 사용한 커밋 3개만 기록했습니다. --path 가 여러 번 지정될 수 있다는 것을 깨닫지 못했다. 따라서 소스 리포지토리에 하위 디렉터리를 만들 필요가 없습니다.) 누군가가 소스 리포지토리에 커밋했기 때문에 내가 이력을 이월 clone 명령 다음에 git reset commit-before-subdir-move --hard 를 사용하고 filter-repo --force 를 추가하여 약간 수정된 로컬 클론에서 작동하도록 했습니다.
 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)

lpearson

업데이트 : 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/


D W

다음은 여러 하위 폴더 (예: sub1sub2 )를 새 git 저장소로 분할하기 위해 CoolAJ86"The Easy Way™" 답변 을 약간 수정한 것입니다.

Easy Way™(여러 하위 폴더)

  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 로 전달 ./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 폴더 의 파일 크기를 줄여야 하는 경우 원래 답변의 부록을 참조하십시오.


Anthony O.

원래 질문은 XYZ/ABC/(*files)가 ABC/ABC/(*files)가 되기를 원합니다. 내 자신의 코드에 대해 허용된 답변을 구현한 후 실제로 XYZ/ABC/(*files)를 ABC/(*files)로 변경하는 것으로 나타났습니다. filter-branch man 페이지는 다음과 같이 말합니다.

결과에는 해당 디렉토리(및 해당 디렉토리만) 가 프로젝트 루트로 포함 됩니다."

즉, 최상위 폴더를 한 수준 "위로" 승격합니다. 예를 들어 내 기록에서 최상위 폴더의 이름을 변경했기 때문에 이는 중요한 차이점입니다. 폴더를 한 수준 위로 "위로" 올리면 git은 내가 이름을 바꾼 커밋에서 연속성을 잃습니다.

필터 분기 후 연속성을 잃었습니다.

질문에 대한 내 대답은 저장소의 복사본을 2개 만들고 각각에 보관하려는 폴더를 수동으로 삭제하는 것입니다. 매뉴얼 페이지는 다음과 같이 나를 뒷받침합니다.

[...] 간단한 단일 커밋으로 문제를 해결하기에 충분하다면 [이 명령]을 사용하지 마십시오.


MM.

Paul의 답변에 추가하려면 궁극적으로 공간을 복구하려면 HEAD를 깨끗한 저장소로 푸시해야 하며 .git/objects/pack 디렉토리의 크기를 줄여야 합니다.

$ mkdir ...ABC.git
$ cd ...ABC.git
$ git init --bare

gc prune 후에 다음도 수행합니다.

$ 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

Case Larsen

이제 올바른 방법은 다음과 같습니다.

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

GitHub에는 이제 그러한 경우에 대한 작은 기사도 있습니다.

그러나 원본 저장소를 먼저 별도의 디렉토리에 복제해야 합니다(모든 파일과 기타 디렉토리를 삭제하고 작업해야 할 가능성이 높기 때문입니다).

따라서 알고리즘은 다음과 같아야 합니다.

  1. 원격 저장소를 다른 디렉토리에 복제
  2. git filter-branch 사용하여 일부 하위 디렉토리 아래에 파일만 남겨두고 새 원격으로 푸시
  3. 원래 원격 저장소에서 이 하위 디렉토리를 제거하기 위한 커밋 생성

Oleksandr Shapovalov

하위 폴더를 새 저장소로 분할하는 방법에 대한 GitHub의 가이드를 권장합니다. 단계는 Paul의 답변 과 유사하지만 지침을 더 쉽게 이해할 수 있습니다.

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

Stevoisiak

여기에 있는 답변의 대부분(모두?)은 git filter-branch --subdirectory-filter 및 해당 ilk 형식에 의존하는 것으로 보입니다. 이것은 "대부분의 경우" 작동할 수 있지만, 예를 들어 폴더 이름을 변경한 경우와 같이 일부 경우에는 다음과 같이 작동할 수 있습니다.

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

"move_this_dir_renamed"를 추출하기 위해 일반적인 git 필터 스타일을 수행하면 처음 "move_this_dir"( ref )일 때 발생한 파일 변경 기록을 잃게 됩니다.

따라서 모든 변경 기록을 실제로 유지하는 유일한 방법(귀하의 경우가 이와 같은 경우)은 본질적으로 저장소를 복사한 다음(새 저장소를 만들고 원본으로 설정) 다른 모든 것을 핵으로 만드는 것입니다. 다음과 같이 하위 디렉토리의 이름을 상위로 바꿉니다.

  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. rmdir moduleSubdir1 삭제: rmdir moduleSubdir1
  12. 언제든지 변경 사항 확인: git status
  13. 새 git repo를 만들고 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 폴더의 공간이 절약되지 않지만 이름이 바뀌더라도 해당 파일에 대한 모든 변경 기록이 보존됩니다. 그리고 이것은 "많은" 기록 손실이 없다면 그만한 가치가 없을 수도 있습니다. 하지만 적어도 오래된 커밋을 잃지는 않을 것입니다!


rogerdpack

나는 정확히이 문제가 있었지만 git filter-branch를 기반으로 한 모든 표준 솔루션은 매우 느렸습니다. 당신이 작은 저장소를 가지고 있다면 이것은 문제가 되지 않을 수도 있습니다. 그것은 나를 위한 것이었습니다. libgit2를 기반으로 하는 또 다른 git 필터링 프로그램을 작성했습니다. 이 프로그램은 첫 번째 단계로 기본 저장소의 각 필터링에 대한 분기를 만든 다음 다음 단계로 저장소를 정리하기 위해 이를 푸시합니다. 내 저장소(500Mb 100000 커밋)에서 표준 git filter-branch 메서드는 며칠이 걸렸습니다. 내 프로그램은 동일한 필터링을 수행하는 데 몇 분이 걸립니다.

git_filter라는 멋진 이름을 가지고 있으며 여기에 있습니다.

https://github.com/slobaby/git_filter

깃허브에서.

누군가에게 유용하기를 바랍니다.


slobobaby

태그와 브랜치를 유지하면서 이 필터 명령을 사용하여 하위 디렉토리를 제거합니다.

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

cmcginty

그 가치를 위해 Windows 시스템에서 GitHub를 사용하는 방법은 다음과 같습니다. C:\dir1 에 있는 복제된 저장소가 있다고 가정해 보겠습니다. 디렉토리 구조는 다음과 같습니다: C:\dir1\dir2\dir3 . dir3 디렉토리는 새로운 별도의 저장소가 되고 싶은 디렉토리입니다.

깃허브:

  1. 새 저장소 만들기: MyTeam/mynewrepo

배쉬 프롬프트:

  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


James Lawruk

위에서 언급했듯이 커밋의 약 95%를 제거하는 데 꽤 잘 작동하는 것처럼 보이는 dir/subdir/targetdir 건드리지 않는 모든 커밋 삭제)을 사용해야 했습니다(원하는 대로). 그러나 두 가지 작은 문제가 남아 있습니다.

먼저 filter-branch 는 코드를 도입하거나 수정하는 커밋을 제거하는 작업을 수행했지만 분명히 병합 커밋 은 Gitiverse의 스테이션 아래에 있습니다.

이것은 내가 아마도 견딜 수 있는 미용상의 문제입니다 (그는 말합니다...눈을 피하고 천천히 물러납니다) .

두 번째로 남아 있는 몇 가지 커밋이 거의 모두 복제되었습니다! 프로젝트의 전체 역사에 걸쳐 중복되는 두 번째 타임라인을 얻은 것 같습니다. 흥미로운 점(아래 그림에서 볼 수 있음)은 세 개의 로컬 분기가 모두 동일한 타임라인에 있지 않다는 것입니다(즉, 이것이 존재하고 단순히 가비지 수집이 아닌 이유).

내가 상상할 수있는 유일한 것은 삭제 된 커밋 중 하나가 filter-branch 실제로 삭제 한 단일 병합 커밋이었고 현재 병합되지 않은 각 가닥이 커밋의 자체 복사본을 가져갈 때 병렬 타임 라인을 생성했다는 것입니다. ( 어깨를 으쓱하며 내 TARDiS는 어디 있지?) 이 문제를 해결할 수 있다고 확신하지만 어떻게 된 건지 정말 알고 싶습니다.

미친 mergefest-O-RAMA의 경우 내 커밋 기록에 너무도 확고하게 자리잡았기 때문에 그냥 내버려 둘 것입니다. 비 미용적인 문제와 Tower.app에서 꽤 예쁘기 때문입니다.


Jay Allen

더 쉬운 방법

  1. git splits 설치하십시오. jkeating의 솔루션을 기반으로 git 확장으로 만들었습니다.
  2. 디렉토리를 로컬 분기로 분할 #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

  3. 어딘가에 빈 저장소를 만드십시오. git@github.com:simpliwp/xyz.git 경로가 있는 GitHub에 xyz 라는 빈 저장소를 생성했다고 가정하겠습니다.

  4. 새 저장소로 푸시합니다. #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

  5. 새로 생성된 원격 저장소를 새 로컬 디렉터리에 복제
    #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


AndrewD

실제로 파일을 정리하려면 가비지 수집 전에 "git reflog expire --expire=now --all"과 같은 것이 필요할 수 있습니다. git filter-branch는 기록에서 참조를 제거하지만 데이터를 보유하는 reflog 항목은 제거하지 않습니다. 물론 이것을 먼저 테스트하십시오.

이 작업을 수행하는 동안 내 디스크 사용량이 크게 떨어졌지만 초기 조건은 약간 달랐습니다. 아마도 --subdirectory-filter는 이러한 필요성을 무효화하지만 의심스럽습니다.




https://github.com/vangorra/git_split에서 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.

vangorra

이것을 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'

grosser

git 하위 트리가 모두 훌륭하고 훌륭하다고 확신하지만 이동하려는 git 관리 코드의 하위 디렉터리는 모두 이클립스에 있었습니다. 따라서 egit을 사용하는 경우 매우 쉽습니다. 이동하려는 프로젝트를 가져와 팀->연결 해제한 다음 팀->새 위치에 공유합니다. 기본적으로 이전 저장소 위치를 사용하려고 시도하지만 기존 선택 항목을 선택 취소하고 새 위치를 선택하여 이동할 수 있습니다. 모두 만세.


stu

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을 따르십시오.


Barath Ravichander

나는 아주 간단한 해결책을 찾았습니다. 아이디어는 저장소를 복사한 다음 불필요한 부분을 제거하는 것입니다. 작동 방식은 다음과 같습니다.

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를 제거하고 3단계에서 XYZ -> ABC로 이름을 바꿉니다.


Vlad Troyan

이 멋진 기사 원본 참조를 쉽게 찾을 수 있습니다. 액세스할 수 없는 경우에 대비하여 여기에 문서화합니다.

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

마지막으로 루트 디렉토리로 돌아가서 주 리포지토리에서 폴더를 제거한 다음 변경 사항을 커밋하고 푸시합니다. 이제 기본 리포지토리에 폴더가 있지만 여러 프로젝트에서 재사용할 수 있는 완전히 별도의 리포지토리에 연결되어 있습니다.


infiniteLearner

출처 : http:www.stackoverflow.com/questions/359424/detach-move-subdirectory-into-separate-git-repository

반응형