1. ホーム
  2. git

[解決済み] サブディレクトリを別のGitリポジトリに切り離す(移動する)。

2022-03-15 15:40:43

質問

私は ジット リポジトリは、いくつかのサブディレクトリを含んでいます。今、私はサブディレクトリの1つが他のものと無関係であることを発見し、別のリポジトリに切り離す必要があることを発見しました。

サブディレクトリ内のファイルの履歴を維持したまま、これを行うにはどうしたらよいでしょうか。

クローンを作って、それぞれのクローンの不要な部分を削除すればいいのでしょうが、これでは古いリビジョンなどをチェックアウトするときに完全なツリーができてしまうと思います。これは許容範囲かもしれませんが、私は2つのリポジトリが履歴を共有していないように見せかけることができる方が望ましいと思います。

念のため、以下のような構成にしています。

XYZ/
    .git/
    XY1/
    ABC/
    XY2/

でも、その代わりにこうしてほしい。

XYZ/
    .git/
    XY1/
    XY2/
ABC/
    .git/
    ABC/

解決方法は?

更新情報 : このプロセスは非常に一般的なものなので、git チームは新しいツールでこれをよりシンプルにしました。 git subtree . こちらをご覧ください。 サブディレクトリを別のGitリポジトリにデタッチ(移動)させる


リポジトリをクローンして、その上で git filter-branch を使用して、新しいレポのサブディレクトリ以外のすべてをガベージコレクトするようにマークします。

  1. ローカルリポジトリのクローンを作成する。

    git clone /XYZ /ABC
    
    

    (注意: リポジトリはハードリンクを使用してクローンされますが、ハードリンクされたファイル自体は変更されないので問題ありません - 新しいファイルが作成されます)。

  2. 次に、同様に書き換えたい興味深いブランチを保存し、そこへのプッシュを避け、古いコミットがオリジンから参照されないようにするためにオリジンを削除しましょう。

    cd /ABC
    for i in branch1 br2 br3; do git branch -t $i origin/$i; done
    git remote rm origin
    
    

    またはすべてのリモートブランチに適用されます。

    cd /ABC
    for i in $(git branch -r | sed "s/.*origin\///"); do git branch -t $i origin/$i; done
    git remote rm origin
    
    
  3. ここで、サブプロジェクトと関係のないタグも削除したくなるかもしれません。これは後で行うこともできますが、レポを再度プルーンする必要があるかもしれません。私はそうしなかったので WARNING: Ref 'refs/tags/v0.1' is unchanged さらに、このようなタグを削除すると、より多くのスペースが再生されます。どうやら git filter-branch は他のタグを書き換えることができるはずですが、これは確認できませんでした。すべてのタグを削除したい場合は git tag -l | xargs git tag -d .

  4. そして、filter-branch と reset を使って他のファイルを除外し、刈り込みができるようにします。さらに --tag-name-filter cat --prune-empty を使用して、空のコミットを削除し、タグを書き換えます(この場合、署名を削除する必要があることに注意してください)。

    git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC -- --all
    
    

    または、HEADブランチのみを書き換え、タグや他のブランチを無視することもできます。

    git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC HEAD
    
    
  5. 次に、バックアップのリブログを削除して、スペースを本当に取り戻すことができます(ただし、この操作は破壊的です)。

    git reset --hard
    git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
    git reflog expire --expire=now --all
    git gc --aggressive --prune=now
    
    

    これで、ABC サブディレクトリのローカル git リポジトリが、そのすべての履歴を保存した状態でできあがりました。

注:ほとんどの用途で git filter-branch は、実際に追加されたパラメータを持つべきです。 -- --all . はい、それは本当に - - スペース - - all . これはコマンドの最後のパラメータにする必要があります。Matli が発見したように、これによってプロジェクトのブランチとタグが新しいリポジトリに含まれたままになります。

編集:以下のコメントから様々な提案を取り入れ、例えば、リポジトリが実際にシュリンクされることを確認しました(以前は必ずしもそうではありませんでしたが)。