web-dev-qa-db-ja.com

大きなGitリポジトリを多くの小さなリポジトリに分割します

SVNリポジトリをGitに正常に変換した後、非常に大きなGitリポジトリができました。これを複数の小さなリポジトリに分割し、履歴を維持します。

だから、誰かがこのようなリポジトリを分割するのを手伝うことができます:

MyHugeRepo/
   .git/
   DIR_A/
   DIR_B/
   DIR_1/
   DIR_2/

このように見える2つのリポジトリに:

MyABRepo/
   .git
   DIR_A/
   DIR_B/

My12Repo/
   .git
   DIR_1/
   DIR_2/

この前の質問の指示に従ってみましたが、複数のディレクトリを個別のレポジトリに配置しようとすると、実際には適合しません( Detach(move)subdirectory to different Git repository )。

84
MikeM

これによりMyABRepoがセットアップされます。もちろん、My12Repoも同様に実行できます。

git clone MyHugeRepo/ MyABRepo.tmp/
cd MyABRepo.tmp
git filter-branch --Prune-empty --index-filter 'git rm --cached --ignore-unmatch DIR_1/* DIR_2/*' HEAD 

.git/refs/original/refs/heads/masterへの参照は残ります。次の方法で削除できます:

cd ..
git clone MyABRepo.tmp MyABRepo

すべてうまくいった場合は、MyABRepo.tmpを削除できます。


何らかの理由で.git-rewriteに関するエラーが発生した場合、これを試すことができます:

git clone MyHugeRepo/ MyABRepo.tmp/
cd MyABRepo.tmp
git filter-branch -d /tmp/git-rewrite.tmp --Prune-empty --index-filter 'git rm --cached --ignore-unmatch DIR_1/* DIR_2/*' HEAD 
cd ..
git clone MyABRepo.tmp MyABRepo

これにより、.git-rewriteの代わりに/tmp/git-rewrite.tmpが一時ディレクトリとして作成および使用されます。当然、書き込み許可があり、ディレクトリがまだ存在しない限り、/tmp/git-rewrite.tmpの代わりに任意のパスに置き換えることができます。

78
unutbu

git filter-branch --index-filtergit rm --cachedを使用して、元のリポジトリのクローン/コピーから不要なディレクトリを削除できます。

例えば:

trim_repo() { : trim_repo src dst dir-to-trim-out...
  : uses printf %q: needs bash, zsh, or maybe ksh
  git clone "$1" "$2" &&
  (
    cd "$2" &&
    shift 2 &&

    : mirror original branches &&
    git checkout HEAD~0 2>/dev/null &&
    d=$(printf ' %q' "$@") &&
    git for-each-ref --Shell --format='
      o=%(refname:short) b=${o#Origin/} &&
      if test -n "$b" && test "$b" != HEAD; then 
        git branch --force --no-track "$b" "$o"
      fi
    ' refs/remotes/Origin/ | sh -e &&
    git checkout - &&
    git remote rm Origin &&

    : do the filtering &&
    git filter-branch \
      --index-filter 'git rm --ignore-unmatch --cached -r -- '"$d" \
      --tag-name-filter cat \
      --Prune-empty \
      -- --all
  )
}
trim_repo MyHugeRepo MyABRepo DIR_1 DIR_2
trim_repo MyHugeRepo My12Repo DIR_A DIR_B

各リポジトリの不要なブランチまたはタグを手動で削除する必要があります(たとえば、feature-x-for-ABブランチがある場合は、「12」リポジトリから削除することをお勧めします)。

10
Chris Johnsen

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.
5
vangorra

Rubyそれを行うスクリプトです。 https://Gist.github.com/43410

4
EnabrenTane

回答ありがとうございます。リポジトリを2回コピーして、それぞれから不要なファイルを削除しました。削除されたファイルは他の場所ですでにバージョン管理されているため、後日、フィルターブランチを使用して、削除されたファイルのすべてのコミットを取り除きます。

cp -R MyHugeRepo MyABRepo
cp -R MyHugeRepo My12Repo

cd MyABRepo/
rm -Rf DIR_1/ DIR_2/
git add -A
git commit -a

これは私が必要としていたものでうまくいきました。

編集:もちろん、My12RepoでもAおよびBディレクトリに対して同じことが行われました。これにより、不要なディレクトリを削除するまで、同一の履歴を持つ2つのリポジトリが作成されました。

1
MikeM