次の方法で共有


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

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

Git は、ユーザーが接続されていない状態でもリポジトリ全体を操作できる分散ソース コード リポジトリとして、近年非常に人気が高まっています。 Git の利点は十分に文書化されていますが、プライマリ リポジトリで "クロックのロールバック" が必要になった場合はどうなるのでしょうか? それを行うことはそれほど直感的ではなく、リポジトリのすべてのユーザーに影響を与えるものであることが予想されるため、高い権限が必要です。

では、どうすれば中央リポジトリを安全にロールバックできるのでしょうか?

問題のシナリオ

ビデオなどの大きなファイルを Git サーバーにコミットするとします。 従来のソース コード システムでは、すべてを 1 か所に保存しておき、必要なものをプルダウンするのが便利です。 ただし、Git では、リポジトリ全体が各ユーザーのローカル コンピューターに複製されます。 大きなファイルの場合、プロジェクトのすべてのユーザーが大きなファイルをダウンロードする必要があります。 後続の大きなファイルがサーバーにコミットされるたびに問題は増大し、リポジトリが大きすぎてユーザーにとって効率的でなくなるまで続きます。 さらに悪いことに、ローカルリポジトリから差し障りのある物を削除して再コミットしたとしても、そのファイルは以前としてリポジトリの履歴に残っており、履歴の一部としてすべてのユーザーのローカル コンピューターにダウンロードされることになります。

含まれる変更に大きなビデオが表示されているチーム エクスプローラーの [変更] ダイアログ

"ローカル リポジトリへの大きなファイルの追加"

サーバーおよびローカルのリポジトリ (両方とも大きなビデオ ファイルのコピーを含む)

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

リポジトリを凍結する

重要

次の手順では、ブランチ履歴からビデオを削除しますが、Azure Repos からリポジトリを複製したときにファイルがリポジトリ履歴に残ります。 ブランチ履歴からファイルを削除すると、ファイルが更新されるのを防ぐことができます。これにより、リポジトリに大きなファイルの別のバージョンが作成されます。 Git で大きなファイルを管理する方法の詳細を確認してください。Azure Repos Git リポジトリ使用時のこの動作の詳細な説明と回避策については、こちらのブログ記事を参照してください。

これを修正するには、ソース (この場合は、サーバー リポジトリ) から開始する必要があります。 リポジトリへのプッシュを停止するようにチームに依頼しますが、このプロセス中に追加のプッシュが発生した場合、データを失わないよう、それらも考慮する必要があります。

リベースと強制プッシュ

チームの誰もリポジトリに変更を加えていない場合 (通常はプッシュを通じて)、簡単な方法を取ることができます。この方法では、基本的にローカル リポジトリを望む形 (つまり、大きなファイルがない状態) にし、その後、変更をサーバーに強制します。

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

既定では、ローカル プロジェクト ファイルとリポジトリを変更し、変更をサーバーにプッシュすることしかできないため、削除やリベースなどの他の変更をサーバー レベルで行うことはできません。 したがって、管理者からプロジェクトの強制プッシュ (推奨) または管理者のアクセス許可を取得するか、それらを持っていて協力してくれる人を見つける必要があります。 Git のアクセス許可の詳細については、こちらを参照してください。

コマンド プロンプト - git push --force permissions。

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

  1. ただし、最初に git log を使用して、最新のコミットの SHA ハッシュ値を見つけます。この情報がすぐに必要になります。 これは、最新の良好なコミットを知る必要があるためです。 その情報を取得するには、Git コマンド プロンプトを開き、次のように入力します。

git log

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

メイン ブランチの [履歴の表示]

  1. 次に、Git コマンド プロンプトを開きます。

[同期] ダイアログ - [コマンド プロンプトを開く] アクション

  1. 目的の SHA ハッシュ番号を見つけます。

コマンド プロンプト - ビデオのコミットを選択する

  1. "25b4" で始まる SHA が必要になります

Git ではポインターを使用して、リポジトリ内のヘッドまたは現在のブランチがどこにあるかを判断します。 このため、関心のあるリポジトリの状態は過去のある時点のものになります。 "過去にさかのぼって"、以前の望ましい状態を新しく現在の状態にするためには、git rebase コマンドを使用する必要があります

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

リベースしてビデオ ファイルを削除する

-i スイッチを使用すると、エディターで履歴が表示されるため、安全性が少し高まります (Windows のコマンド ラインで git を実装すると、クラシックな vi エディターが表示されます。これは、Unix ベースのシステムで作業したことがあれば覚えているかもしれません)。

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

git rebase -i 25b4

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

コマンド プロンプト - git rebase -i 25b4 pick コマンド

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

コマンド プロンプト - git rebase -i 25b4 drop コマンド

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

再度「git log」と入力します。問題のあるブランチはログに含めてはいけません。 これで、プロジェクト管理者のアクセス許可が必要な最後の手順の準備が整います。

git log

リベース後のローカルおよびサーバーのリポジトリ

"大きなビデオのコミットがローカル リポジトリから削除されていることに注意してください"

  1. 型: git push --force

コマンド プロンプト - git push --force

コマンド プロンプト - git push --force の結果

このコマンドを実行すると、サーバー上のリポジトリが自分のリポジトリに強制的に上書きされます。

サーバー上のデータを簡単に失う可能性がありますので、注意して使用してください。

ビデオ ファイルなしの保持するコンテンツを表示する強制プッシュ

"これを機能させるには、サーバーに対して認証を行う必要があることに注意してください"

Azure Repos を使用している場合、特殊文字 (メール アドレスの "@" など) を使用しない代替資格情報を設定する必要がある場合があります。 このためには、こちらの手順に従ってください。

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

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

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

リベース後、チームの他のユーザーもリベースして、すべてのユーザーがサーバー リポジトリの一貫したコピーを持つようにする必要があることに注意してください。 これは誰にとっても苦痛であり、通常は避けるべきです。 したがって、ここで説明したようにプッシュを削除する必要がある場合は、チームと調整することが重要です。 リベースの詳細については、こちらの公式のリベース ドキュメントを参照してください。

重要なのは、必要なコミットと必要でないコミットを確実に把握することです。 Git ログまたは IDE (Visual Studio など) の履歴を調べて、残すべき SHA ハッシュと捨てるべき SHA ハッシュを注意深くメモします。

大きなファイルがしばらく存在し、後続のブランチやマージがあるシナリオでは、git filter-branch スイッチを使用してファイルを削除できる場合があります。 これを試す場合は、こちらの手順に従ってください。

推奨設定の注意事項

そもそも大きなファイルがメイン リポジトリに置かれないようにすることで、多くの作業が節約されます。 そのことを念頭に置いて、チームが留意すべき一般的なベスト プラクティスをいくつか次に示します。

推奨

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

非推奨

  • プッシュ後にリベースしないでください。 Git でプッシュされたコミットをリベースすると、リポジトリ内の他のすべてのユーザーはローカルの変更のリベースが強制されるため、問題が発生する可能性があります。また、これを行わなければならないのは不満に感じるでしょう。 プッシュされたコミットを自分の個人ブランチにリベースすることは、たとえプッシュされたとしても、他の人がそれらのコミットをプルしていない限り、大きな問題ではありません。
  • リポジトリにバイナリをコミットしないでください。 Git では、TFVC のようにバイナリ ファイルは圧縮されません。また、すべてのリポジトリがすべての履歴を持っているため、バイナリ ファイルをコミットすると永続的に肥大化することになります。

まとめ

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

著者: JEdward Fry および Jesse Houwing | 著者および ALM | DevOps Ranger とつながるにはこちらから

(c) 2015 Microsoft Corporation. All rights reserved. このドキュメントは "現状のまま" 提供されます。このドキュメントに記載されている情報および見解 (URL および他のインターネット Web サイトの参照を含む) は、予告なしに変更されることがあります。 お客様は、その使用に関するリスクを負うものとします。

このドキュメントは、Microsoft 製品の知的財産権に関する法的な権利をお客様に許諾するものではありません。 内部での参照を目的とする場合、このドキュメントをコピーして使用できます。