bugfix> git > 投稿

私の機能ブランチには、約50のコミットがあります。最初のコミットでは、後続のコミットで大幅に変更されるファイルを作成しました。私は今、そのファイルを別のディレクトリに保存する方が良いことを理解しているので、最初のコミットに戻って最初から適切な場所に作成して、履歴をきれいに保ちたいと思います。最初のコミットを編集してファイルを移動することでインタラクティブなリベースでこれを行うことができますが、そのファイルに触れる以降のコミットはすべて手動で解決する必要がある競合を生成します。ファイルが移動されたことをすべてのコミットに伝える方法はありますか?そのため、適切な場所で変更を自動的に適用しますか?

回答 1 件
  • TL;DR

    git filter-branch を使用する 。 --index-filter を使用できます  スピードのためですが、これは使いにくいです。わずか50件のコミットで、 --tree-filter を使用します  はるかに遅いですが、はるかに使いやすいです:

    git filter-branch --tree-filter <fill this in> --tag-name-filter cat -- --all
    
    

    通常、これはコピー 元のリポジトリの(クローン)フィルターブランチを簡単に変更でき、回復します それから、コピーを削除して最初からやり直すことです。

    動作したら、すべての refs/original/ を削除します   git filter-branch で説明されている名前  ドキュメンテーション。リポジトリーは最終的にデブロートされます(フィルターブランチのサイズは一時的におよそ2倍になります)。

    長いです

    Gitでの履歴は、コミットです。履歴を変更するには、古いコミット(古い履歴を提供する)を新しい異なるコミット(新しい履歴を提供する)にコピーする必要があります。だからあなたの目標は、すべての50のようなコミットを同じものに置き換えることですを除く ファイルが他のパスに再配置されること。

    あなたが言ったように、あなたはできる インタラクティブなリベースでこれを行いますが、それは苦痛です:リベースは、コピーする各コミットを変更セットに変換し(そのコミットをその親と比較して、変更内容を確認することにより)、既存のコミットに同じ変更を適用することで動作します。

    かなり重いコマンド git filter-branch があります 、その目的は、ある種のコミット修飾子を適用しながらコミットをコピーすることです。本質的に非常に遅いため、多くのオプションがあります。しかし基本的には、次のもので構成されます。

    操作対象のすべてのコミットを(ハッシュIDで)リストします。あなたの場合、それは単に「すべてのコミット」です。また、古いハッシュID→新しいハッシュIDの空のマップを作成します。

    次に、ルートの最も古い(最も古い/最も古い)コミットから開始します。

    コミットを一時的な作業領域に抽出します。

    さまざまなフィルターのそれぞれを適用します。

    結果から新しいコミットを作成します。ハッシュマップを使用して親IDをマッピングし、新しいコミットが以前にコピーされた新しいコミットを指すようにします。これにより、コマンドに新しいコミットのハッシュIDが与えられます。

    古いコミットハッシュ→新しいコミットハッシュからマップにエントリを追加します。

    最後に、コミットされるすべてのコミットについて上記を実行した後、すべてのループをループします参照 変更するように指示します(主にブランチ名ですが、 --tag-name-filter を使用する場合はタグ名も ):

    refs/whatever から元の参照の名前を変更します   refs/original/refs/whatever へ 。

    新しい refs/whatever を作成する  マップで見つかった新しいハッシュを使用します。

    このプロセスの最後に、元のすべてのコミットがあります( refs/original  それらを参照するため)とすべての新しいコミット(ブランチ名を使用)。

    ブランチ名が1つしかなく(タグがない)場合、指定する必要がある唯一の名前はこの1つのブランチ名で、おそらく master 、しかし --all  Gitにすべての参照を参照するよう指示し、 --tag-name-filter cat  タグを更新するときにタグ名に加えるべき変更は、変更を加えないことであることをGitに伝えます。

    ザ・ --tree-filter   git filter-branch に指示します  ステップ1(コミットの抽出)では、 git filter-branch の一時ディレクトリに対して完全かつ完全な抽出を実行する必要がある  独自に構築します。 (他のフィルターオプションは、非常に高速な一時インデックスへの抽出のみのトリックで逃げようとします。) tree-filter に指定するコマンド  この一時ディレクトリで実行されるため、ファイルの名前を変更するだけでよい場合は、次のコマンドを実行します。

    mv old-relative-path new-relative-path
    
    

    十分です(Unix/Linuxのようなシステムを想定しています)。

あなたの答え