2012-04-21 8 views
2

この質問は多くのポーズに似ていますが、不愉快に違います。以前に結合されたコードを複数のgitリポジトリに分割する

私はgvリポジトリを持っていました。これはかつてはCVSリポジトリでした(CVSリポジトリでした)。これには1999年頃までのデータが含まれています。

この1つのリポジトリをいくつかの異なるリポジトリに分割し、この豊富な履歴をすべて保存する時が来ています。しかし、リポジトリの構造は頻繁に変更されています。すべての現在のプロジェクトは基本プロジェクトからのもので、いくつかのプロジェクトに成長し、2つのプロジェクトに縮小してから再び成長しました。コードは移動しましたが、複製されませんでした。成熟したいくつかのプロジェクトのうちのひとつで、最終的な休息場所を見つけました。

これは、履歴を保存したい場合、リポジトリを非常に分割することになります。 git-filter-branchを使うのは適切なアプローチのようですが、これらのすべてがリポジトリの一部をハックして履歴を切り捨てるようです。

EDIT追加明確にするために、私がリポジトリのルートにいるような小さな例があります。リポジトリが次のようになっているとします:file.txtの内容を編集してみましょう。その後、名前をnewfile.txtに変更します。次に、内容を再度編集します。次に、このファイルをbar/からbaz/に移動します。私のリポジトリには、次のようになります。

foo/ 
    bar/ 
    baz/ 
     newfile.txt 

[OK]を、今の私は、独自のリポジトリに出baz/を分割したいとしましょう。 git filter-branchまたはgit subtree splitを使用すると、bar/の中にあったときに、そしてfile.txtと命名されたときに、コミットメッセージと履歴がすべてnewfile.txtに戻ってしまいます。

私は、過去のリビジョンをチェックアウトするのは狂っているかもしれないことを理解しています。それは../bar/と呼ばれるものを参照しているかもしれないし、存在しないし、壮大に失敗する無効なディレクトリを参照しているかもしれません。特定のリビジョンでファイルの内容を見ることができる限り、私は気にしません。

のEND EDIT

私がやりたいことのための2つの経路があるように思える:

  1. クローンリポジトリN回はそのリポジトリに私がしたいフォルダを保存し、(経由git rm-ing他のフォルダ)、HEADにあるファイルを最終的に参照しないリビジョンを何らかの形でハックします。私はこれがいくつかの否定的な副作用を持っていることを理解しています。古いリビジョンをチェックすることは意味のあるコードベースを提供しません - 私は気にしません。これを行うには、HEADに存在するすべてのファイルの下にあるすべてのパスを取得する方法を見つける必要があります。これは醜いスクリプトで行うことができます。

  2. 各インデックス中にリポジトリの外観の履歴インデックスを作成します。ツリーフィルタを使用して、それぞれのリビジョンで一致しないファイルを切り落とします。次に、表示されないファイル、またはHEAD内のファイルから削除するファイルを削除します。

HEADに表示されないすべてのファイルを検索し、それに関する履歴を削除することはできますか?私は長い間削除されたファイルを復活させることには気をつけません。これは私の問題の要点であるようです。

代替の解決策も認められます。私はgitには比較的新しいので、私はおそらく明らかに何かを欠いているでしょう。

答えて

1

私はいくつかの段階のプロセスでこれを行う必要がありました。私は維持したいファイルが一点に居住していたところ、私が決定することができたことを利用し

git log --pretty=format: --name-only --diff-filter=A | sort -u 

まず、私はすべてのファイルのこれまでのリポジトリに発見されたパスのリストを得ましたまたは別のもの。私の場合、彼らは生涯を通してリポジトリ内の4つの別々のディレクトリに住んでいました。私はこの情報を使用して、(?:^foo|^bar/baz|^qux/(?:moo|woof))のような正規表現を手動で作成しました。これは保存したいディレクトリと一致します。

私はこれらのパス名とそれを含む親のパス名を保存するためにperlスクリプトを作成しました。

use Path::Class;  
if(scalar(@ARGV) < 1) { die "no regex"; } 

my $regex = qr/$ARGV[0]/;  
my @want; my @remove; my $last = undef; my $lastrm = undef; 

while(<STDIN>) { 
    chomp; 
    my $d = $_; 
    if($d =~ $regex) { 
     if(! defined($last) || ! dir($last)->subsumes(dir($d))) { 
      $last = $d; 
      push @want, $d; 
     } 
    } else { 
     if(! defined($last) || ! dir($last)->subsumes(dir($d))) { 
      push @remove, $d; 
     } 
    } 
} 
foreach $rm (@remove) { 
    my $no_rm = 0; 
    if(defined($lastrm) && dir($lastrm)->subsumes($rm)) { 
     $no_rm++; 
    } else { 
     foreach $keep (@want) { 
      if(dir($rm)->subsumes(dir($keep))) { 
       $no_rm++; 
      } 
     } 
    } 
    if($no_rm == 0) { 
     print "$rm\n"; 
     $lastrm = $rm; 
    } 
} 

最後に、git filter-branchを使用して、新しいフィルタを正規表現で使用して、私が望むパスを維持しました。

git filter-branch --prune-empty --index filter ' 
    git ls-tree -d -r -t --name-only --full-tree $GIT_COMMIT 
    | sort | /path/to/filter.pl "(?:regex|of|paths)" 
    | xargs -n 50 git rm -rf --cached --ignore-unmatch' -- --all 

この並べ替えは、perlスクリプトが適切な階層構造でディレクトリを取得できるようにするために必要です。

私がこれを考え出すのに多くの時間を要したので、これが誰かを助けてくれることを願っています。 :)

0

gitサブツリーhttps://github.com/apenwarr/git-subtreeをインストールして使用すると、リポジトリの分割と履歴の保存がうまく処理されます。

+0

hmm。それは私が必要なもののように見えます。私はそれを試してみましょう。 – lucasmo

+0

これは残念なことに、私が必要としていることをしていないようです。私はその事例をさらに例として明確にします。 – lucasmo

関連する問題