私は自分のソースコード(Webアプリケーション)が依存している大きなバイナリファイルの扱い方についての意見を探しています。我々は現在いくつかの代替案を検討しています。
これについてのあなたの経験/考えは何ですか?
また、複数のGitリポジトリとそれらを1つのプロジェクトで管理した経験がある人はいますか。
ファイルはそれらのファイルでPDFを生成するプログラムのための画像です。これらのファイルは(数年の間に)それほど頻繁には変更されませんが、プログラムに非常に関連性があります。プログラムはファイルなしでは動作しません。
プログラムがファイルなしでは動作しない場合は、それらを別々のリポジトリに分割することは悪い考えです。大規模なテストスイートを用意していますが、それらは別々のリポジトリに分割されていますが、それらは本当に "補助的な"ファイルです。
ただし、ファイルを別のリポジトリで管理してから、 git-submodule
を使用して適切な方法でプロジェクトに取り込むことができます。それで、あなたはまだあなたのすべてのソースの完全な歴史を持っているでしょう、しかし、私がそれを理解するように、あなたはあなたの画像サブモジュールの1つの関連した改訂を持っているだけでした。 git-submodule
機能は、正しいバージョンのコードを正しいバージョンのイメージと一致させるのに役立ちます。
これが良い サブモジュールの紹介 Git Bookからです。
私は最近 git-annex を発見しました。大きなファイルを効率的に管理するために設計されました。写真や音楽などのコレクションに使用します。 git-annexの開発は非常に活発です。ファイルの内容はGitリポジトリから削除することができ、ツリー階層のみがGitによって追跡されます(シンボリックリンクを通じて)。ただし、ファイルの内容を取得するには、引っ張ったり押したりした後に次の手順が必要です。
$ git annex add mybigfile
$ git commit -m'add mybigfile'
$ git Push myremote
$ git annex copy --to myremote mybigfile ## This command copies the actual content to myremote
$ git annex drop mybigfile ## Remove content from local repo
...
$ git annex get mybigfile ## Retrieve the content
## or to specify the remote from which to get:
$ git annex copy --from myremote mybigfile
利用可能なコマンドはたくさんあり、Webサイトには素晴らしいドキュメントがあります。パッケージは Debian で入手可能です。
2015年4月以降の別の解決策は、 Gitラージファイルストレージ(LFS) (GitHubによる)です。
git-lfs を使用します(git-lfs.github.comを参照)。 lfs-test-server :
あなたはメタデータをgitリポジトリに、そして大きなファイルを他の場所にのみ保存することができます。
git bup は、大きなバイナリをGitリポジトリにスマートに保存するためのGitの拡張機能です。
あなたはそれをサブモジュールとして持ちたいのですが、リポジトリが扱いにくくなることを心配する必要はありません。サンプルの使用例の1つは、GitにVMイメージを格納することです。
私は実際にはより良い圧縮率を見たことがありません、しかし私のリポジトリはそれらの中に本当に大きなバイナリを持っていません。
あなたのマイレージは異なる場合があります。
git-fat も使えます。私はそれが普通のPythonと rsync
だけに依存するのが好きです。また、通常のGitワークフローもサポートしています。次のような自明のコマンドがあります。
git fat init
git fat Push
git fat pull
さらに、あなたはあなたのリポジトリに.gitfatファイルをチェックインし、あなたがgit fat
で管理したいファイル拡張子を指定するためにあなたの.gitattributesを修正する必要があります。
通常のgit add
を使用してバイナリを追加します。これにより、gitattributesルールに基づいてgit fat
が呼び出されます。
最後に、バイナリが実際に格納されている場所をリポジトリやユーザー間で共有できるという利点があり、rsync
が行うことすべてをサポートします。
更新:Git-SVNブリッジを使用している場合はgit-fatを使用しないでください。 Subversionリポジトリからバイナリファイルが削除されてしまいます。ただし、純粋なGitリポジトリを使用している場合は、それは美しく機能します。
私はサブモジュール(Pat Notzとして)または2つの異なるリポジトリを使用します。バイナリファイルを頻繁に変更する場合は、巨大なリポジトリが履歴を消去することによる影響を最小限に抑えるようにします。
数ヶ月前、私は非常によく似た問題を抱えていました。
メインのGitリポジトリで外付けハードディスクドライブを使い、それを各コンピュータにクローンしました。その後、私は習慣的な方法でそれらを分類し始めました(プッシュ、プル、マージ...削除と名前の変更を何度も)。
最後に、私はたった6 GBのMP3ファイルと.gitディレクトリにある83 GBしか持っていませんでした。私はgit-write-tree
とgit-commit-tree
を使って、コミット先祖なしで新しいコミットを作成し、そのコミットを指す新しいブランチを始めました。そのブランチの "git log"はコミットを1つだけ示しました。
それから、古いブランチを削除し、新しいブランチだけを残して、ref-logsを削除して、 "git Prune"を実行します。
あなたは同じように時々巨大なリポジトリを "削除"することができます。あなたの "gitクローン"はより速くなるでしょう。
私の意見では、これらの大きなファイルを頻繁に変更する可能性がある場合、またはgit clone
またはgit checkout
を多数作成する予定の場合は、別のGitリポジトリ(またはこれらのファイルにアクセスする別の方法)の使用を真剣に検討する必要があります。
しかし、私たちのように作業し、バイナリファイルが頻繁に変更されない場合は、最初のクローン/チェックアウトは長くなりますが、その後は必要な速度で実行する必要があります。持っていました)。
私が提案したい解決策は、孤立したブランチとタグメカニズムのわずかな悪用に基づいています。今後は* Orphan Tags Binary Storage(OTABS)と呼びます。
TL; DR 12-01-2017githubのLFSやその他のサードパーティを使用できる場合は、ぜひとも使うべきです。あなたができない場合は、次に読んでください。注意してください、この解決策はハックであり、そのように扱われるべきです。
OTABSの望ましい性質
git pull
を含むgit fetch
とgit fetch --all
は、まだ帯域幅効率が良いです。つまり、デフォルトですべての大きなバイナリがリモートから取り出されるわけではありません。OTABSの望ましくない性質
git clone
を潜在的に非効率的にします(しかしあなたの用法によっては必ずしもそうではありません)。このソリューションを展開する場合は、git clone -b master --single-branch <url>
の代わりにgit clone
を使用するよう同僚にアドバイスする必要があるかもしれません。これは、git cloneがデフォルトで文字通りentirerepositoryを複製するためです。参照されていないコミットのように、通常は帯域幅を浪費したくないものも含みます。 SO 4811434 から引用。git fetch <remote> --tags
の帯域幅は非効率的になりますが、必ずしもストレージが非効率的になるわけではありません。あなたはいつでも同僚にそれを使わないように忠告することができます。git gc
トリックを使用する必要があります。バイナリファイルを追加する
変更をすべてコミットしたことを確認する前に、作業ツリーが最新のものであり、索引に未確定の変更が含まれていないことを確認してください。何らかの災害が発生した場合に備えて、すべてのローカルブランチをリモート(githubなど)にプッシュすることをお勧めします。
git checkout --Orphan binaryStuff
がうまくいくでしょう。これにより、他のブランチから完全に切り離されたブランチが作成され、このブランチで最初に作成したコミットには親がなくなり、ルートコミットになります。git rm --cached * .gitignore
を使用してインデックスを消去してください。rm -fr * .gitignore
を使って作業ツリー全体を削除してください。 .git
ワイルドカードは一致しないため、内部の*
ディレクトリは変更されません。git fetch
を呼び出して接続を詰まらせるときにダウンロードするようになります。ブランチの代わりにタグを押すことでこれを避けることができます。 git fetch <remote> --tags
と入力する習慣がある場合でも、これは同僚の帯域幅とファイルシステムの記憶域に影響を与える可能性がありますが、回避策をお読みください。進んでgit tag 1.0.0bin
git Push <remote> 1.0.0bin
をプッシュしてください。git branch -D binaryStuff
を削除することもできます。コミットを1.0.0bin
で指し示す孤児タグで十分に生きているため、ガベージコレクションのマークは付けられません。バイナリファイルをチェックアウトする
git checkout 1.0.0bin -- VeryBigBinary.exe
を使えます。1.0.0bin
をダウンロードしていない場合、これは失敗します。その場合は、事前にgit fetch <remote> 1.0.0bin
を実行する必要があります。VeryBigBinary.exe
に.gitignore
を追加することができます。そうすればあなたのチームの誰もが偶然にバイナリでプロジェクトの主な歴史を汚染することはありません。バイナリファイルを完全に削除する
ローカルリポジトリ、リモートリポジトリ、および同僚のリポジトリからVeryBigBinary.exeを完全に削除することにした場合、次の操作を実行できます。
git Push <remote> :refs/tags/1.0.0bin
のOrphanタグを削除しますgit tag -l | xargs git tag -d && git fetch --tags
。 SO 1841341 から若干変更を加えたものです。git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 -c gc.rerereresolved=0 -c gc.rerereunresolved=0 -c gc.pruneExpire=now gc "$@"
。他の未参照のコミットもすべて削除されます。 SO 1904860から取得git clone -b master --single-branch <url>
ではなく常にgit clone
を推奨するのであれば、帯域幅とストレージの観点から、チームが影響を受けるかどうかは関係ありません。2.0.0bin
を作成できます。同僚がgit fetch <remote> --tags
と入力するのが心配な場合は、実際にもう一度1.0.0bin
と名前を付けることができます。これにより、次回それらがすべてのタグを取得したときに、古い1.0.0bin
が参照されず、後続のガベージコレクションのためにマークされます(手順3を使用)。あなたがリモート上のタグを上書きしようとするとき、あなたはこのように-f
を使わなければなりません:git Push -f <remote> <tagname>
あとがき
OTABSはあなたのマスターや他のソースコード/開発ブランチには触れません。コミットハッシュ、すべての履歴、およびこれらのブランチの小さいサイズは影響を受けません。バイナリファイルを使ってソースコード履歴を既に肥大化させている場合は、それを別の作業としてクリーンアップする必要があります。 このスクリプト は役に立ちます。
Git-bashを使ってWindowsで動作することを確認しました。
バイナリファイルの格納をより効率的にするために、 一連の標準的なトリック を適用することをお勧めします。 git gc
を(追加の引数なしで)頻繁に実行すると、gitはバイナリデルタを使用してファイルの基礎となるストレージを最適化します。しかし、ファイルがコミットからコミットへと変わらないと思われる場合は、バイナリデルタを完全に無効にすることができます。さらに、.zip、.jpg、または.cryptのようにすでに圧縮または暗号化されたファイルを圧縮することは意味がないので、gitでは基礎となるストレージの圧縮を無効にすることができます。残念ながら、これはあなたのソースコードにも影響を与えるオールオアナッシングの設定です。
あなたはより速い使用を可能にするためにOTABSの一部を台本にしたいと思うかもしれません。特に、バイナリファイルの完全削除からupdate
gitフックへのスクリプトステップ2-3は、git fetch( "時代遅れのものすべてをフェッチして削除する"という説得力があるが恐らく危険なセマンティクスを与えるかもしれません。 ")。
あなたはバイナリファイルを完全に削除するのステップ4を飛ばしたくなるかもしれません。ローカルリポジトリは、時間の経過とともにスリムに保たれます。
Javaの世界では、このソリューションとmaven --offline
を組み合わせて、完全にあなたのバージョン管理に格納された再現可能なオフラインビルドを作成することができます(gradleよりもmavenの方が簡単です)。 Golangの世界では、go get
の代わりにこのソリューションに基づいてGOPATHを管理することが可能です。 Pythonの世界では、これをvirtualenvと組み合わせることで、ビルドごとにPyPiサーバに頼らずに自己完結型の開発環境を一から作成することができます。
ビルド成果物のようにバイナリーファイルが頻繁に変更される場合は、最新バージョンの成果物の5つをOrphanタグmonday_bin
、tuesday_bin
、...、friday_bin
、およびOrphanタグに格納するソリューションをスクリプト化することをお勧めします。リリースごとに1.7.8bin
、2.0.0bin
など。weekday_bin
をローテーションしたり、古いバイナリを毎日削除したりできます。こうすることで、2つの長所を活用することができます。ソースコードの全体履歴を保持し、バイナリ依存関係のrelated履歴のみを保持します。与えられたタグのバイナリファイルをなしで取得するのもとても簡単です:全ての履歴を含むソースコード全体を取得する:git init && git remote add <name> <url> && git fetch <name> <tag>
はあなたのためにそれをするべきです。
SVNはGitよりもバイナリデルタをより効率的に扱うようです。
ドキュメントのバージョン管理システム(JPEGファイル、PDFファイル、および.odtファイル)を決定する必要がありました。私はちょうどJPEGファイルを追加し、それを90度4回回転させてテストしました(バイナリデルタの有効性をチェックするため)。 Gitのリポジトリは400%成長しました。 SVNのリポジトリは11%しか成長していません。
そのため、SVNはバイナリファイルの方がはるかに効率的です。
だから私の選択はソースコードのGitとドキュメントのようなバイナリファイルのSVNです。
私は、ソースコード(Webアプリケーション)が依存する大きなバイナリファイルを処理する方法についての意見を探しています。これに関するあなたの経験/考えは何ですか?
私は個人的にGitとの同期エラーに遭遇しました。Webアプリケーションのバイナリデータにノッチを付けた後、クラウドホストの一部でGBマークを超えるになりました。 BFT Repo Cleaner を検討しましたが、ハックのように感じました。それ以来、ファイルの管理、バージョン管理、バックアップのために、Amazon S3などの専用ツールを活用して、Gitの範囲外でファイルを保持し始めました。
複数のGitリポジトリを使用し、1つのプロジェクトでそれらを管理した経験がある人はいますか?
はい。 Hugoテーマ は、主にこの方法で管理されます。それは少し不器用ですが、仕事を終わらせます。
私の提案は、仕事に最適なツールを選択です。企業向けで、GitHubでコードラインを管理している場合は、お金を支払い、Git-LFSを使用します。そうでない場合は、分散型の暗号化された ブロックチェーンを使用したファイルストレージ など、より創造的なオプションを検討できます。
Git 2.19以降のgit clone --filter
+浅いクローン
GitとGitHubがそれを十分に使いやすくするならば、この新しいオプションは最終的にバイナリファイルの問題に対する最終的な解決策になるかもしれません(それらはおそらく間違いなく サブモジュール のためにまだ達成できません) 。
それは実際にあなたがサーバーのために欲しいファイルとディレクトリだけを取得することを可能にし、そしてリモートプロトコル拡張と一緒に導入されました。
これにより、最初に浅いクローンを作成してから、ビルドの種類ごとにビルドシステムでどのBLOBをフェッチするかを自動化できます。
フェッチする最大BLOBサイズを制限することを可能にする--filter=blob:limit<size>
さえすでにあります。
この機能がどのように見えるかについての最小限の詳細な例を提供しました。 Gitリポジトリのみのサブディレクトリを複製するにはどうすればよいですか?