git 하위 디렉토리를 추출하고 하위 모듈을 만드는 방법은 무엇입니까?


120

몇 달 전에 프로젝트를 시작했고 모든 것을 기본 디렉토리에 저장했습니다. 내 메인 디렉토리 "Project"에는 여러 가지 하위 디렉토리가 있습니다. Project / paper에는 LaTeX로 작성된 문서가 포함되어 있습니다. Project / sourcecode / RailsApp에는 내 rails 앱이 포함되어 있습니다.

"Project"는 GITified이며 "paper"와 "RailsApp"디렉토리 모두에 많은 커밋이 있습니다. 이제 "RailsApp"에 cruisecontrol.rb를 사용하고 싶기 때문에 기록을 잃지 않고 "RailsApp"에서 하위 모듈을 만드는 방법이 있는지 궁금합니다.



답변:


123

요즘에는 수동으로 git filter-branch를 사용하는 것보다 훨씬 쉬운 방법이 있습니다. git subtree

설치

NOTE git-subtreegit1.7.11부터 (contrib을 설치 한 경우)의 일부이므로 이미 설치했을 수 있습니다. 을 실행하여 확인할 수 있습니다 git subtree.


소스에서 git-subtree를 설치하려면 (이전 버전의 git 용) :

git clone https://github.com/apenwarr/git-subtree.git

cd git-subtree
sudo rsync -a ./git-subtree.sh /usr/local/bin/git-subtree

또는 매뉴얼 페이지와 모든

make doc
make install

용법

더 큰 것을 더 작은 청크로 분할 :

# Go into the project root
cd ~/my-project

# Create a branch which only contains commits for the children of 'foo'
git subtree split --prefix=foo --branch=foo-only

# Remove 'foo' from the project
git rm -rf ./foo

# Create a git repo for 'foo' (assuming we already created it on github)
mkdir foo
pushd foo
git init
git remote add origin git@github.com:my-user/new-project.git
git pull ../ foo-only
git push origin -u master
popd

# Add 'foo' as a git submodule to `my-project`
git submodule add git@github.com:my-user/new-project.git foo

자세한 문서 (맨 페이지)는을 참조하십시오 git-subtree.txt.


10
자식 하위 트리 바위!
Simon Woodside 2011

3
그러나 하위 모듈 사용을 피하는 것이 git-subtree의 요점이 아닙니까? 내 말은, 당신은 실제로 git-subtree의 작성자이지만 (닉네임 충돌이없는 한) git-subtree가 변경된 것처럼 보이지만 표시하는 명령이 여전히 유효한 것처럼 보입니다. 이게 맞나요?
Blaisorblade

18
git-subtree는 이제 1.7.11
Jeremy

8
의 전체 기록 에서 잘 git rm -rf ./foo제거 하지만 필터링하지는 않습니다 . 그런 다음에서 시작하는 하위 모듈 만 만듭니다 . 그런 점에서 스크립팅 은 "처음부터 subdir이 하위 모듈 인 것처럼 수행"을 수행 할 수 있기 때문에 우수합니다.fooHEADmy-projectgit submodule add git@github.com:my-user/new-project.git foofooHEADfilter-branch
Gregory

이것에 대한 thx-git subtree docs 약간 당황
스럽고

38

체크 아웃 git filter-branch .

맨 페이지 의 Examples섹션 은 모든 히스토리를 유지하고 다른 파일 / 디렉토리의 히스토리를 버리는 동안 (당신이 찾고있는 바로 그) 서브 디렉토리를 자체 프로젝트로 추출하는 방법을 보여줍니다.

foodir/프로젝트 루트 인 것처럼 보이도록 저장소를 다시 작성하고 다른 모든 기록을 삭제하려면 :

   git filter-branch --subdirectory-filter foodir -- --all

따라서 예를 들어 라이브러리 하위 디렉토리를 자체 저장소로 바꿀 수 있습니다. 옵션과 개정 옵션 을 구분 하고 모든 분기와 태그를 다시 작성 하는
것에 유의하십시오 .--filter-branch--all


1
이것은 나를 위해 잘 작동했습니다. 내가 알아 차린 단점은 결과가 모든 커밋이 포함 된 단일 마스터 브랜치라는 것입니다.
aceofspades 2013 년

@aceofspades : 왜 그게 단점일까요?
naught101

2
나에게 git repo에서 커밋을 추출하는 요점은 역사를 유지하고 싶다는 것입니다.
aceofspades 2013

13

이를 수행하는 한 가지 방법은 그 반대입니다. 유지하려는 파일을 제외한 모든 것을 제거하십시오.

기본적으로 저장소 의 복사본 을 만든 다음을 사용 git filter-branch하여 유지하려는 파일 / 폴더를 제외한 모든 항목을 제거합니다.

예를 들어, 파일 tvnamer.py을 새 저장소 로 추출하려는 프로젝트가 있습니다 .

git filter-branch --tree-filter 'for f in *; do if [ $f != "tvnamer.py" ]; then rm -rf $f; fi; done' HEAD

git filter-branch --tree-filter각 커밋을 수행하고 명령을 실행하고 결과 디렉토리 콘텐츠를 다시 커밋 하는 데 사용 됩니다. 이것은 매우 파괴적이며 (따라서 리포지토리의 복사본에서만이 작업을 수행해야합니다!) 시간이 걸릴 수 있습니다 (300 개의 커밋과 약 20 개의 파일이있는 리포지토리에서 약 1 분).

위의 명령은 각 개정판에서 다음 셸 스크립트를 실행합니다. 물론 수정해야합니다 (대신 하위 디렉터리를 제외하려면 tvnamer.py).

for f in *; do
    if [ $f != "tvnamer.py" ]; then
        rm -rf $f;
    fi;
done

가장 분명한 문제는 남은 파일과 관련이 없더라도 모든 커밋 메시지를 남기는 것입니다. git-remove-empty-commits 스크립트 는 이것을 수정합니다.

git filter-branch --commit-filter 'if [ z$1 = z`git rev-parse $3^{tree}` ]; then skip_commit "$@"; else git commit-tree "$@"; fi'

(기본적으로 백업) 모든 항목과 함께 다시 -f실행 되는 force 인수 를 사용해야합니다.filter-branchrefs/original/

예를 들어 커밋 메시지가 다른 파일을 언급하는 경우에는 물론 이것은 완벽하지 않을 것입니다.하지만 git current가 허용하는 정도에 가깝습니다 (어쨌든 내가 아는 한).

다시 말하지만, 저장소 사본에서만 이것을 실행하십시오! -그러나 요약하면 "thisismyfilename.txt"를 제외한 모든 파일을 제거합니다.

git filter-branch --tree-filter 'for f in *; do if [ $f != "thisismyfilename.txt" ]; then rm -rf $f; fi; done' HEAD
git filter-branch -f --commit-filter 'if [ z$1 = z`git rev-parse $3^{tree}` ]; then skip_commit "$@"; else git commit-tree "$@"; fi'

4
git filter-branch(요즘?) 빈 커밋을 제거하는 내장 옵션, 즉 --prune-empty. 더 나은 가이드 git filter-branch는이 질문에 대한 답변에 있습니다. stackoverflow.com/questions/359424/…
Blaisorblade

4

CoolAJ86apenwarr 답변은 매우 유사하다. 나는 둘 중 하나에서 빠진 부분을 이해하기 위해 두 사람 사이를왔다 갔다했다. 아래는 이들의 조합입니다.

먼저 Git Bash를 분할 할 git repo의 루트로 이동합니다. 여기 내 예에서는~/Documents/OriginalRepo (master)

# move the folder at prefix to a new branch
git subtree split --prefix=SubFolderName/FolderToBeNewRepo --branch=to-be-new-repo

# create a new repository out of the newly made branch
mkdir ~/Documents/NewRepo
pushd ~/Documents/NewRepo
git init
git pull ~/Documents/OriginalRepo to-be-new-repo

# upload the new repository to a place that should be referenced for submodules
git remote add origin git@github.com:myUsername/newRepo.git
git push -u origin master
popd

# replace the folder with a submodule
git rm -rf ./SubFolderName/FolderToBeNewRepo
git submodule add git@github.com:myUsername/newRepo.git SubFolderName/FolderToBeNewRepo
git branch --delete --force to-be-new-repo

아래는 사용자 정의 가능한 이름을 바꾸고 대신 https를 사용하는 위의 사본입니다. 루트 폴더는 이제~/Documents/_Shawn/UnityProjects/SoProject (master)

# move the folder at prefix to a new branch
git subtree split --prefix=Assets/SoArchitecture --branch=so-package

# create a new repository out of the newly made branch
mkdir ~/Documents/_Shawn/UnityProjects/SoArchitecture
pushd ~/Documents/_Shawn/UnityProjects/SoArchitecture
git init
git pull ~/Documents/_Shawn/UnityProjects/SoProject so-package

# upload the new repository to a place that should be referenced for submodules
git remote add origin https://github.com/Feddas/SoArchitecture.git
git push -u origin master
popd

# replace the folder with a submodule
git rm -rf ./Assets/SoArchitecture
git submodule add https://github.com/Feddas/SoArchitecture.git
git branch --delete --force so-package

3

일부 파일 하위 집합을 새 저장소로 전송하고 기록을 유지하려는 경우 기본적으로 완전히 새로운 기록으로 끝납니다. 이것이 작동하는 방식은 기본적으로 다음과 같습니다.

  1. 새 저장소를 만듭니다.
  2. 이전 저장소의 각 개정에 대해 모듈의 변경 사항을 새 저장소에 병합하십시오. 기존 프로젝트 기록의 "사본"이 생성됩니다.

작지만 털이 많은 스크립트를 작성하는 데 신경 쓰지 않는다면 이것을 자동화하는 것은 다소 간단 할 것입니다. 예, 간단하지만 고통 스럽습니다. 사람들은 과거에 Git에서 역사 재 작성을 했으므로 검색을 수행 할 수 있습니다.

또는 저장소를 복제하고 복제본에서 종이를 삭제하고 원본에서 앱을 삭제합니다. 이 작업은 1 분이 걸리며 작동이 보장되며 git 기록을 정화하는 것보다 더 중요한 일로 돌아갈 수 있습니다. 중복 된 기록 사본이 차지하는 하드 드라이브 공간에 대해 걱정하지 마십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.