Git 履歴から大きなバイナリを削除して、複製されたリポジトリのサイズを管理する

Azure DevOps Services |Azure DevOps Server |Azure DevOps Server 2022

Git は一般的な分散ソース コード リポジトリ (リポジトリ) です。これにより、ユーザーは切断された状態で完全なリポジトリを操作できます。 Git の利点は十分に文書化されていますが、プライマリ リポジトリで "クロックをロールバック" する必要がある場合はどうなりますか? これを行うには直感的ではなく、昇格されたアクセス許可が必要です。 この要件は、リポジトリのすべての単一ユーザーに影響を与えるものに対して必要です。

中央リポジトリを安全にロールバックするにはどうすればよいですか?

問題のシナリオ

ビデオなどの大きなファイルを Git サーバーにコミットするとします。 従来のソース コード システムでは、すべてを 1 か所に格納し、必要なものをプルダウンすると便利です。 Git では、リポジトリ全体が各ユーザーのローカル コンピューターに複製されます。 大きなファイルでは、プロジェクトのすべてのユーザーが大きなファイルもダウンロードする必要があります。

後続の大きなファイルがサーバーにコミットされるたびに、問題は大きくなるだけです。 リポジトリが大きくなりすぎて、ユーザーにとって効率的になりません。 ローカル リポジトリから大きなファイルを削除してコミットした場合でも、そのファイルはリポジトリの履歴に残ります。 その結果、ファイルは履歴の一部としてすべてのユーザーのローカル コンピューターにダウンロードされます。

[チーム エクスプローラーの変更] ダイアログを示すスクリーンショット。含まれている変更に大きなビデオが含まれています。

ローカル リポジトリに大きなファイルを追加します。

大きなビデオ ファイルのコピーを含むサーバーリポジトリとローカル リポジトリを示すスクリーンショット。

ローカル リポジトリからコミットした後、サーバーには大きなファイルもあります。

リポジトリを凍結する

大きなリポジトリの問題を解決するには、ソースから開始する必要があります。 このシナリオでは、ソースはサーバー リポジトリです。 リポジトリへのプッシュを停止するようにチームに依頼します。 このプロセス中にさらにプッシュが発生した場合は、データが失われないように、それらを管理する必要があります。

Von Bedeutung

次の手順では、ブランチ履歴からビデオを削除しますが、Azure Repos からリポジトリを複製すると、ファイルはリポジトリ履歴に残ります。 ブランチ履歴からファイルを削除すると、ファイルが更新されず、リポジトリに別のバージョンの大きなファイルが作成されます。

Git での大きなファイルの管理の詳細について説明します。 Azure Repos Git リポジトリを使用する場合のこの動作の説明と回避策については、「 Visual Studio Team Services からの複製で古い参照されていないオブジェクトが返される理由」を参照してください。

リベースと強制プッシュ

チームの他の誰もリポジトリに変更を加えなかった場合 (通常はプッシュによって発生します)、簡単なルートを取得できます。 基本的に、ローカルリポジトリを望む状態に設定します(つまり、大きなファイルを除外して)。 その後、サーバーに変更を強制します。

この作業を開始する前に、ローカル リポジトリの複製または修正が必要になる場合があります。 このプロセスにより、作業や変更が失われる可能性があるため、慎重に進めてください。

既定では、ローカル プロジェクト ファイルを変更してサーバーに変更をプッシュできますが、削除やリベースなどのサーバー レベルの操作は実行できません。 続行するには、リポジトリに対する強制プッシュ (優先) または管理者アクセス許可が必要です。 プロジェクト管理者に連絡してこれらのアクセス許可を要求するか、既にアクセス許可を持っているユーザーに支援を依頼してください。 詳細については、「Git リポジトリのアクセス許可を設定する」を参照してください。

コマンド プロンプト (git push --force アクセス許可) を示すスクリーンショット。

次に、リポジトリをリベースする必要があります。

  1. git logを使用して、最新のコミットのセキュア ハッシュ アルゴリズム (SHA) ハッシュ値を検索します。 この情報は、最新の安定したコミットを知るためにすぐに必要です。 その情報を取得するには、Git コマンド プロンプトを開き、次のように入力します。

    git log

    または、Visual Studio チーム エクスプローラーでブランチ履歴を表示して SHA ハッシュを取得することもできます。

    メイン ブランチの [履歴の表示] オプションを示すスクリーンショット。

  2. Git コマンド プロンプトを開きます。

    [同期] ダイアログの [コマンド プロンプトを開く] アクションを示すスクリーンショット。

  3. 関心のある SHA ハッシュ番号を見つけます。

    ビデオ コミットのコマンド プロンプトを示すスクリーンショット。

    25b4を開始する SHA が必要です。

    Git ではポインターを使用して、リポジトリ内のヘッドブランチまたは Current Branch が配置されている場所を決定します。 関心のあるリポジトリの状態は、過去の特定の時点に存在しています。

  4. 時間をさかのぼって以前の状態を新しい現在の状態にするには、 git rebase コマンドを使用します。

    git rebase -i <SHA hash of desired new current branch>

    リベースを使用してビデオ ファイルを削除する方法を示すスクリーンショット。

    -iスイッチは、エディターで履歴を表示するため、安全性が高い機能を提供します。 (この記事では、Windows のコマンド ラインでクラシック vi エディターを起動する Git の実装を使用します。Unix ベースのシステムを使用していた場合は覚えているかもしれません。

  5. この例では、次のように入力します。

    git rebase -i 25b4

  6. エディターが表示されたら、新しいヘッドとして保持するブランチを除くすべての pick 行を削除します。 すべてが正しく表示されたら、vi に「 :w\<enter\> 」と入力して保存するか、「 !q\<enter\> 」と入力して保存せずに終了します。

    コマンド プロンプト -git rebase -i 25b4 pick コマンドを示すスクリーンショット。

    不要になった行を変更します。

    コマンド プロンプト -git rebase -i 25b4 drop コマンドを示すスクリーンショット。

  7. pickを次のようにdropに変更します。 保存する :w (vi) を入力し、「 :q! 」と入力してリベースを開始します。

    ここで、もう一度「 git log 」と入力します。 問題のあるブランチはログに含まれないようにする必要があります。 その場合は、プロジェクト管理者のアクセス許可が必要な最後の手順に進むことができます。

    git log

    リベース後のローカル リポジトリとサーバー リポジトリを示すスクリーンショット。

    これで、大きなビデオのコミットがローカル リポジトリから削除されました。

  8. 次のコマンドを入力します。

    git push --force

    コマンド プロンプト -git push --force を示すスクリーンショット。

    コマンド プロンプト (git push --force result) を示すスクリーンショット。

    このコマンドは、サーバー上のリポジトリを上書きするようにリポジトリを強制します。

    サーバー上のデータが簡単に失われる可能性があるため、このコマンドは注意して使用してください。

    大きなビデオファイルを含まず、残すべきコンテンツを示す強制プッシュのスクリーンショット。

このアクションを機能させるには、サーバーに対して認証を行う必要があります。

Azure Repos を使用している場合は、特殊文字を使用しない代替資格情報の設定が必要になる場合があります。 たとえば、電子メール アドレスのアット マーク (@) です。 このタスクを実行するには、「 Azure Repos を使用した認証」の手順に従います。

これで、ブランチはサーバーから完全に削除されました。 プロジェクト チーム メンバーによる後続の複製と同期では、削除しようとした大きなファイルはダウンロードされません。 ユーザーは、サーバーからプルダウンして、新しいサーバー リポジトリの状態と同期していることを確認する必要があります。

ユーザーが新しいコミットを持っている場合

他のユーザーがコミットをサーバー リポジトリにプッシュした場合は、別の考慮事項があります。 大きなファイルを含むブランチを削除するが、チームが行った変更を失いたくない。 この状況に対処するには、リベースの一環としてエディターを開くときに、コミットを注意深く確認します。 保持するコミットが pick 行に一覧表示されていることを確認します。 大きなファイルが追加された場所など、削除するファイルを削除します。

リベース後、チームの他のユーザーも、すべてのユーザーがサーバー リポジトリの一貫したコピーを持つよう、リベースする必要があります。 この作業はすべての人にとって面倒で、避けたいです。 プッシュを削除する必要がある場合は、チームと調整する必要があります。 リベースの詳細については、「 Git 分岐 - リベース」を参照してください。

重要なのは、必要なコミットと不要なコミットを確実に把握することです。 統合開発環境 (Visual Studio など) の git log または履歴を調べることができます。 保持する SHA ハッシュと削除するハッシュを細心の注意を払います。

大きなファイルが古く、後続の分岐とマージがあったシナリオでは、 git filter-branch スイッチを使用してファイルを削除できる場合があります。 詳細については、 リポジトリからの機密データの削除を参照してください。

ベスト プラクティスに関する考慮事項

チーム メンバーを余分な作業から救うために、大きなファイルがメイン リポジトリから除外されていることを確認します。 チームが留意すべき一般的なベスト プラクティスを次に示します。

やること

  • 変更を頻繁にコミットします。 後でスカッシュまたはリベースを使用していつでも修正できます。
  • ブランチを使用して変更を分離します。 ブランチは安価で非公開であり、簡単にマージできます。 サーバーにプッシュすることで、ブランチの変更をバックアップすることもできます。
  • トピック ブランチを発行するときは、名前付け規則を使用します。 ブランチ users/<alias>/<branchname>に名前を付けます。 この名前は、ブランチをグループ化するのに役立ち、他のユーザーが所有者を簡単に識別できるようにします。
  • 変更をプッシュすることを忘れないでください。 Commit != Checkin(Commit + Push) == Checkinを使用します。
  • リポジトリに追加されないように、大きなバイナリに .gitignore を使用することを検討してください。 詳細については、 ファイルの無視を参照してください。
  • NuGet または Team Foundation Server のバージョン管理を使用して、大きなバイナリを格納することを検討してください。

回避すべき事項

  • プッシュ後にリベースしないでください。 Git でプッシュされたコミットをリベースすると、リポジトリ内の他のすべてのユーザーがローカルの変更を強制的にリベースするため、不適切な場合があります。 このタスクを実行する必要がある場合、チーム メンバーは満足できない可能性があります。 自分の個人用ブランチでプッシュされたコミットをリベースすることは、他のユーザーがそれらのコミットをプルしていない限り、問題ありません。
  • バイナリをリポジトリにコミットしないでください。 Git では、Team Foundation バージョン コントロールと同様にバイナリ ファイルは圧縮されません。 すべてのリポジトリには履歴全体があるため、バイナリ ファイルをコミットすることは永続的な肥大化を意味します。

概要

場合によっては、大きなファイルなどの望ましくない要素がリポジトリに追加され、リポジトリをクリーンで軽量に保つために削除する必要があります。 このタスクは、ローカル リポジトリを順番に取得することで実行できます。 git rebase コマンドを使用し、git push --force コマンドを使用して、サーバー リポジトリをローカル リポジトリで上書きします。