git filter-branch
man ページの例またはこの回答のわずかに変更されたバージョンを使用して、これを行うことができます。これは git v1.8.2 の man ページ バージョンです。
To move the whole tree into a subdirectory, or remove it from there:
git filter-branch --index-filter \
'git ls-files -s | sed "s-\t\"*-&newsubdir/-" |
GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
git update-index --index-info &&
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD
まず、各サブモジュールをリモートとして親リポジトリに追加し、次に各サブモジュールのmaster
ブランチをローカル追跡ブランチ (例: submoduleA-master
、submoduleB-master
など) としてチェックアウトします。ブランチは履歴を共有しないため、Git は警告をスローしますが、それ以外の場合は続行できます。サブモジュール ブランチの履歴を適切なサブディレクトリに書き直し、それを親の にマージしmaster
ます。最終的に、これらのサブディレクトリに対する一連のマージ コミットと、親リポジトリにまとまりのある単一の履歴が作成されます。
実際よりもはるかに複雑に聞こえます。万一の場合に備えて、必ずバックアップを作成してください。すべてをスクリプト化して、正しく理解できるまで試してみてください。各サブモジュールの大まかな実行順序は次のとおりです。
git remote add submodule submodule_remote
git checkout -b submodule-master submodule/master
git filter-branch ... # With the index-filter described above.
# Depending on length of history, this could
# take quite a while to process/
git checkout master # Get back on parent's master.
今、あなたは選択を迫られています。サブモジュールのすべての痕跡を削除するために親を書き直しますか? 後者の場合は、git バージョンに適したソリューションを使用して親リポジトリからサブモジュールを削除してから、 . 履歴からすべてのサブモジュールのコミットも消去したい場合は、親も同様に書き換えることができます。git merge submodule-master
git filter-branch
私はかつて、35 の異なるリポジトリに対してこれを行いました。ヒントは次のとおりです。AWS での数時間のクラスター コンピューティングに 10 ドルを費やしてください。git filter-branch
非常にRAMバウンドです。ラップトップでは 20 時間以内に実行できなかったことが、AWS クラスター コンピューティング インスタンスでは昼食中に完了する可能性があります。このような操作を行うには、美しくシンプルで安価な方法です。
最後に 1 つ。BSD を使用している場合、man ページsed
の置換が失敗する可能性がかなりあります。\t
Jeff King のperl
バージョンは、この問題を回避します。
git filter-branch --index-filter '
git ls-files -s |
perl -pe "s{\t\"?}{$&newsubdir/}" |
GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info &&
mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE
' HEAD