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


86

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/

この前の質問の指示に従ってみましたが、複数のディレクトリを別のリポジトリに配置しようとすると、実際には適合しません(サブディレクトリを別のGitリポジトリにデタッチ(移動)します)。


11
回答に満足したら、承認済みとしてマークしてください。
ベンファウラー

1
(いくつかのプロジェクトでは難しいかもしれない複数のディレクトリを削除するのではなく)複数の(ネストされた)ディレクトリを新しいリポジトリに分割しようとしている人にとって、この答えは私にとって役に立ちました:stackoverflow.com/a/19957874/164439
thaddeusmt 2015年

回答:


80

これにより、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

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


'git filter-branch'のマンページでは、上記の最後の手順ではなく、書き換えられたリポジトリの新しいクローンを作成することをお勧めします。
ヤクブNarębski

これを試してみましたが、最後に.git-rewriteフォルダーを削除しようとするとエラーが発生しました。
MikeM 2010

-d <path-on-another-physical-disk>が機能し、-tree-filter内のスタンジ「mv」エラーを排除しました。
めまい2013

除外されたパス(DIR_Aたとえば)に関連している場合、最初のコミットを取得する方法を知っていますか?
ビットマスク2013年

1
の完全な影響を認識していませんでしたfilter-branch。知らない人のために、それは履歴を書き換えるので、これを行った後にリポジトリをプッシュすることを計画している場合、コミットハッシュは今は異なり、機能しません。
thaddeusmt 2015年

10

git filter-branch --index-filterwithgit 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」リポジトリから削除する必要があります)。


1
:bashのコメント文字ではありません。#代わりに使用する必要があります。
Daenyth 2010

4
@Daenyth:は、従来の組み込みコマンドです(POSIXでも指定されています)。bashに含まれていますが、コメントではありません。#すべてのシェルが#すべてのコンテキストでコメントイントロデューサーとして使用されるわけではないため(たとえば、INTERACTIVE_COMMENTSオプションが有効になっていないインタラクティブzsh)、特に優先して使用しました。を使用:すると、テキスト全体をインタラクティブシェルに貼り付けたり、スクリプトファイルに保存したりするのに適したものになります。
クリスジョンセン2010

1
鮮やかさ!私が見つけた唯一の解決策は、すべてのブランチを無傷に保つことです
pheelicks 2011

それはで停止し、私のために奇妙な、git remote rm origin常に1を返すように見える、それゆえ私は置き換え&&により;、このラインのため。
kynan 2011年

いいですね、$ @は必要に応じて2つ以上のdirで機能します。終わったら電話しますgit remote add origin $TARGET; git push origin master
ウォルターA

6

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.


1

回答ありがとうございますが、リポジトリを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
これはコミット履歴を保持しません。
Daenyth 2010

どうして?削除されたファイルについても、まだすべての履歴があります。
MikeM 2010

1
レポAがレポBが存在しないふりをしなければならないという要件ではなかったので、これ(Bにのみ影響したコミットの記録を残す)が適切な解決策だと思います。それを壊すよりも少し歴史を複製する方が良いです。
スティーブクレイ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.