source

많은 하위 디렉터리를 별도의 새로운 Git 저장소로 분리

manycodes 2023. 9. 28. 08:37
반응형

많은 하위 디렉터리를 별도의 새로운 Git 저장소로 분리

이 질문은 하위 디렉터리를 별도의 Git 저장소로 분리하는 것을 기반으로 합니다.

하나의 서브디렉토리를 분리하는 것이 아니라 몇 개를 분리하고 싶습니다.예를 들어, 현재 디렉터리 트리는 다음과 같습니다.

/apps
  /AAA
  /BBB
  /CCC
/libs
  /XXX
  /YYY
  /ZZZ

그 대신에 이것을 원합니다.

/apps
  /AAA
/libs
  /XXX

--subdirectory-filter 논쟁git filter-branch처음 실행할 때 주어진 디렉토리를 제외한 모든 것을 제거하기 때문에 작동하지 않습니다.하는 줄 요.--index-filter원하지 않는 모든 파일에 대한 인수는 지루하지만, 두 번 이상 실행을 시도하면 다음과 같은 메시지가 나타납니다.

Cannot create a new backup.
A previous backup already exists in refs/original/
Force overwriting the backup with -f

무슨 생각 있어요? TIA.

subshell을 처리하고 ext glob(skynan이 제안한 대로)을 사용하는 대신 다음과 같은 훨씬 간단한 접근 방식을 시도해 보십시오.

git filter-branch --index-filter 'git rm --cached -qr --ignore-unmatch -- . && git reset -q $GIT_COMMIT -- apps/AAA libs/XXX' --prune-empty -- --all

무효로 언급된 바와 같이.포인터의 코멘트, 이것은 다음을 제외한 모든 것을 제거할 것입니다.apps/AAA그리고.libs/XXX현재 저장소에서.

빈 병합 커밋 제거

이것은 많은 빈 병합을 남깁니다.이것들은 그의 답변에서 알파벳으로 설명된 다른 패스로 제거할 수 있습니다.

git filter-branch --prune-empty --parent-filter \
'sed "s/-p //g" | xargs -r git show-branch --independent | sed "s/\</-p /g"'

⚠️ 경고:위는 GNU 버전을 사용해야 합니다.sed그리고.xargs그렇지 않으면 다음과 같은 모든 커밋을 제거할 것입니다.xargs패.brew install gnu-sed findutils그 다음에 사용합니다.gsed그리고.gxargs:

git filter-branch --prune-empty --parent-filter \
'gsed "s/-p //g" | gxargs git show-branch --independent | gsed "s/\</-p /g"' 

쉬운 해결책: git-filter-repo

비슷한 문제가 있었는데 여기 나열된 여러 가지 방법을 검토한 결과 git-filter-repo를 발견했습니다.여기 공식 git 문서에서 git-filter-branch의 대안으로 추천합니다.

기존 저장소의 디렉토리 부분 집합에서 새 리포지토리를 만들려면 다음 명령을 사용합니다.

git filter-repo --path <file_to_keep>

여러 파일/폴더를 체인 방식으로 필터링:

git filter-repo --path keepthisfile --path keepthisfolder/

따라서 git-filter-repo를 사용하여 원래 질문에 답하려면 다음 명령만 있으면 됩니다.

git filter-repo --path apps/AAA/ --path libs/XXX/

간단한 git 명령을 사용한 수동 단계

이 계획은 개별 디렉토리를 자체 저장소로 분할한 다음 이를 병합하는 것입니다.다음 수동 단계에서는 geek-to-use 스크립트를 사용하지 않고 이해하기 쉬운 명령을 사용하여 추가 N개의 하위 폴더를 다른 단일 저장소로 병합하는 데 도움이 될 수 있습니다.

나누다

원래 레포를 다음과 같이 가정합니다. original_repo

1 - 앱 분할:

git clone original_repo apps-repo
cd apps-repo
git filter-branch --prune-empty --subdirectory-filter apps master

2 - 갈라진 입술

git clone original_repo libs-repo
cd libs-repo
git filter-branch --prune-empty --subdirectory-filter libs master

폴더가 2개 이상 있으면 계속합니다.이제 두 개의 새로운 임시 깃 저장소를 갖게 됩니다.

앱과 립을 병합하여 정복하기

3 - 새 레포를 준비합니다.

mkdir my-desired-repo
cd my-desired-repo
git init

그리고 적어도 하나의 약속을 해야 할 것입니다.다음 세 줄을 건너뛰어야 할 경우 첫 번째 레포가 레포 루트 바로 아래에 나타납니다.

touch a_file_and_make_a_commit # see user's feedback
git add a_file_and_make_a_commit
git commit -am "at least one commit is needed for it to work"

merge나중 섹션의 명령이 예상대로 중지됩니다.

합니다와 같은 .a_file_and_make_a_commit, 당신은 a를 추가할 것을 선택할 수 있습니다..gitignore, 아니면README.md

4 - 앱 레포를 먼저 병합합니다.

git remote add apps-repo ../apps-repo
git fetch apps-repo
git merge -s ours --no-commit apps-repo/master # see below note.
git read-tree --prefix=apps -u apps-repo/master
git commit -m "import apps"

이제 새 저장소 안에 apps 디렉토리가 표시됩니다.git log모든 관련 기록 커밋 메시지를 표시해야 합니다.

와 같이의 경우 를 : Chris git 의(>2.9) 의.--allow-unrelated-histories와 함께git merge

5 - 립스 레포를 다음과 같은 방법으로 병합합니다.

git remote add libs-repo ../libs-repo
git fetch libs-repo
git merge -s ours --no-commit libs-repo/master # see above note.
git read-tree --prefix=libs -u libs-repo/master
git commit -m "import libs"

병합할 리포지토리가 2개 이상 있으면 계속합니다.

참조:다른 리포지토리의 하위 디렉터리를 git와 병합합니다.

를 하려고 합니까?filter-branch한 번 이상?할 수 다항)).extglob사용할 수 있도록 셸에서 활성화):

git filter-branch --index-filter "git rm -r -f --cached --ignore-unmatch $(ls -xd apps/!(AAA) libs/!(XXX))" --prune-empty -- --all

이렇게 않는 하위 되고 합니다(, )로 을 미치지 않는 한 및 --prune-empty- -

이 후 않는 는 됩니다에서 되지 않은 됩니다.git status.

$(ls ...)합니다.extglob됩니다.됩니다sheval()extglob사용할 수 없음).git에서 옵션을 활성화하려면 어떻게 해야 합니까?를 참조하십시오.그것에 대한 더 자세한 사항을 위하여.

여기서 제 질문에 답을 드리자면...우여곡절 끝에

는 를 할수.git subtree및 . 이 지침은 다음을 기반으로 합니다.

  • git 하위 트리로 프로젝트 간 코드 공유 – http://psionides.jogger.pl/2010/02/04/sharing-code-between-projects-with-git-subtree/
  • 직무에 적합한 도구: git- stitch-repo – http://ifup.org/2009/02/07/the-right-tool-for-the-job-git-stitch-repo/

먼저 별도의 저장소에 보관할 디렉토리를 꺼냈습니다.

cd origRepo
git subtree split -P apps/AAA -b aaa
git subtree split -P libs/XXX -b xxx

cd ..
mkdir aaaRepo
cd aaaRepo
git init
git fetch ../origRepo aaa
git checkout -b master FETCH_HEAD

cd ..
mkdir xxxRepo
cd xxxRepo
git init
git fetch ../origRepo xxx
git checkout -b master FETCH_HEAD

그런 다음 빈 저장소를 새로 만들고 마지막 두 개를 가져오거나 연결했습니다.

cd ..
mkdir newRepo
cd newRepo
git init
git-stitch-repo ../aaaRepo:apps/AAA ../xxxRepo:libs/XXX | git fast-import

이렇게 하면 두 개의 가지가 생기고,master-A그리고.master-B, 연결된 저장소 중 하나의 내용을 각각 보유하고 있습니다.이들을 결합하고 정리하는 방법:

git checkout master-A
git pull . master-B
git checkout master
git branch -d master-A 
git branch -d master-B

지금은 어떻게/언제 이런 일이 일어나는지 잘 모르겠지만, 첫번째 사건 이후로checkout그리고.pull, 코드는 마법처럼 마스터 브랜치에 합쳐집니다(여기서 무슨 일이 일어나고 있는지에 대한 어떤 통찰력이라도 감사히 받겠습니다!).

모든 것이 예상대로 작동한 것 같은데요, 다만 제가 자세히 들여다보면요.newRepo이 commit history,다에 영향을 미쳤을 때 되는 것이 .apps/AAA그리고.libs/XXX할 수 있는 중복을 제거할 수 있는 방법이 있다면 완벽할 것 같습니다.

저는 이 문제를 정확히 해결하기 위해 깃 필터를 작성했습니다.git_filter라는 환상적인 이름을 가지고 있으며 여기 github에 위치해 있습니다.

https://github.com/slobobaby/git_filter

그것은 훌륭한 libgit2를 기반으로 합니다.

커밋이 많은 대용량 저장소를 분할해야 했는데(~100000개) git filter-branch 기반 솔루션을 실행하는 데 며칠이 걸렸습니다. git_filter는 동일한 작업을 수행하는 데 1분이 걸립니다.

git split' git 확장자 사용

git splits bash 스크립트는 포장지 주변에 있는 bash script입니다.git branch-filterJkeating의 솔루션을 바탕으로 Git 확장으로 만든 것입니다.

이것은 정확히 이 상황을 위해 만들어졌습니다.git splits -f백업을 강제로 제거하는 옵션입니다..git splits새 분기에서 작동하므로 현재 분기를 다시 쓸 수 없으므로 백업은 관련이 없습니다.자세한 내용은 readme을 참조하고 repo의 복사본/클론에 사용하십시오(만일의 경우를 대비하여!).

  1. 설치.
  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 apps/AAA libs/ZZZ

  3. 어딘가에 빈 레포를 만듭니다.포(repo)입니다라는 빈를 만들었다고xyz진 GitHub에서:git@github.com:simpliwp/xyz.git

  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

git clone git@example.com:thing.git
cd thing
git fetch
for originBranch in `git branch -r | grep -v master`; do
    branch=${originBranch:7:${#originBranch}}
    git checkout $branch
done
git checkout master

git filter-branch --index-filter 'git rm --cached -qr --ignore-unmatch -- . && git reset -q $GIT_COMMIT -- dir1 dir2 .gitignore' --prune-empty -- --all

git remote set-url origin git@example.com:newthing.git
git push --all

을 덮어씁니다. .-fo로 때filter-branch그 경고를 무시할 수 있습니다. 있다고 합니다. ( 원하지 입니다. :) 그렇지 않으면 해결책이 있다고 생각합니다(, 원하지 않는 디렉토리를 한 번에 제거하는 것).filter-branch).

다음 경로에 해당하는 커밋을 내보내는 것이 더 쉽다고 생각합니다.

git log --pretty=email --patch-with-stat --reverse --full-index --binary -- /apps/{AAA,BBB,CCC} /libs/{XXX,YYY,ZZZ} > subdir.patch

다음과 같은 커밋을 새 레포로 가져옵니다.

git am < subdir.patch

할 수 를 해 볼 수 .-m --first-parent:

git log --pretty=email --patch-with-stat --reverse --full-index --binary -m --first-parent -- <your paths>

메시지가 제시하는 것처럼 refs/original의 .git 디렉토리 아래에 있는 백업을 삭제합니다.디렉터리가 숨겨져 있습니다.

언급URL : https://stackoverflow.com/questions/2982055/detach-many-subdirectories-into-a-new-separate-git-repository

반응형