GITはファイルデルタを保存しないという事実にもかかわらず、以前のファイルバージョンにロールバックできます(無制限の時間ですか?)


14

Gitはファイルの差分を保存しないことを読みました。これに該当する場合、以前のバージョンへのファイルロールバックはどのようにサポートされますか?ファイル全体を格納する場合、ディスク上のリポジトリスペースは管理不能なほど大きくなる必要があります。Gitはファイルのロールバックとファイルバージョン1への差分をサポートしていますか?ファイルに関連するバージョン管理の概念もサポートしていますか?これは、VCS / DVCSと私のニーズを理解するために不可欠です。チェックインする内容を以前のバージョンと比較できるようにする必要があります。

回答:


44

Gitはそれ自体で情報破棄しません *。すべてのファイルの以前のバージョンはすべて、復元、差分、検査などに常に使用できます。

ツリー全体と個々のファイル

調整しようとしているのは、個々のファイルの古いバージョンにアクセスするという考え方と、Gitの履歴モデルがツリー全体に焦点を合わせているという事実です。ツリー全体のバージョン管理では、foo.c10個のfoo.c変更前のバージョンと10個のツリー全体の変更前のバージョンを(たとえば)確認するために、もう少し作業が必要です。

# 10 foo.c-changes ago
git show $(git rev-list -n 10 --reverse HEAD -- foo.c | head -1):foo.c

# 10 whole-tree-changes ago
git show HEAD~10:foo.c

ツリー指向の利点は、主にコミットをツリー全体のさまざまな部分に行われた相互依存の変更の単位として表示できることです。一般的に、余分なタイピング(エイリアス、スクリプトなど)とCPU時間を大幅に上回ります。過去のコミットを掘り下げました。

ストレージ効率

新しいオブジェクト(以前は見えなかった内容のファイルなど)がシステムに入ると、「ルーズオブジェクト」としてプレーン(zlib)圧縮で保存されます。十分な緩いオブジェクトが蓄積されたとき(に基づいてgc.auto構成オプションにまたはユーザーがgit gcまたは下位レベルのパッキングコマンドのいずれかを実行すると、れると、Gitは多数のルーズオブジェクトを1つの「パックファイル」に収集します。

パックファイル内のオブジェクトは、プレーンな圧縮データ(ルーズオブジェクトと同じ、他のオブジェクトにバンドルされたものと同じ)として、または他のオブジェクトに対する圧縮デルタとして保存できます。デルタは、構成可能な深さ(pack.depth)に連結でき、任意の適切なオブジェクトに対して作成できます(pack.windowGitが最適なデルタベースを検索する範囲を制御します。これを行うと、歴史的に無関係なファイルのバージョンをベースとして使用できます。良好なデルタ圧縮)。深さおよびウィンドウサイズの構成がデルタ圧縮エンジンに与える寛容さは、多くの場合、CVSスタイルの単純な1バージョン対次/前バージョンの「差分」圧縮よりも優れたデルタ圧縮をもたらします。

(通常のzlib圧縮と組み合わせた)この積極的なデルタ圧縮は、Gitリポジトリ(完全な履歴と非圧縮作業ツリー)が単一のSVNチェックアウト(非圧縮作業ツリーと初期コピー)よりも多くのスペースを取ることができない場合がよくあります。

Git Community BookのGit StoresオブジェクトPackfileセクションをご覧ください。また、gitのパックは、オブジェクトのmanページ

*「履歴を書き換える」とgit resetなどのコマンドを使用してGitにコミットを破棄するように指示できますが、これらの場合でも、Gitは必要な場合に備えて、新しく破棄されたコミットをしばらく「ハング」します。git reflogおよびgit pruneを参照してください。


3
提供した情報の量と詳細についてのみ+1。
タマラWijsman

3
また、Gitはデルタではなくファイルのスナップショットを使用するため、実際には歴史を遡るのが簡単です。20コミット前のファイルを見る必要があると想像してください。デルタでは、20個の変更セットを取り消す必要があります。スナップショットを使用すると、正しいスナップショットを取得できます。履歴が長いほど、メリットは大きくなります。あなたは現在のバージョンとその1つの間の差分を確認したい場合は、それはむしろなど、元に戻す、やり直し、行われているものを判断するより、ただ一つの差分です
ネイサンロング

クリス、あなたはGitの内部構造をかなりよく理解しているようです。これでスイングする可能性はありますか?stackoverflow.com/questions/5176225/...
ネイサンロング

@ChrisJohnsenこれを理解するのを手伝ってください。あなたが言ったことに基づいて、GitはSubversionと同じ(またはより良い)ストレージ効率を得ることができますか?何回も変更をほとんど行わずにファイルをコミットすると、1GBのデータを100MBで保存できることを知っています。Gitでも同じことができますか?
アリレザノリ

@AlirezaNoori:データの性質とキャプチャされた変更(ファイルのサイズ、ファイルの圧縮率、変更のサイズと場所など)にすべて依存します。そのようなことは確かに可能でなければなりません(詳細に依存します)。一般に、Gitのパックファイルは、SVNサーバーが使用する厳密に逆時系列のデルタと比較して、そのデルタ圧縮のベースの幅広い選択から引き出すことができます(使用されていますか?SVN開発に従っていません)。特定の質問がある場合は、関連するすべての詳細を含む新しい質問をすることを検討してください。
クリスジョンセン

1

同じページで読むことができます:

...

そのため、Gitはソースコードツリーの下のどのレベルでもファイルリビジョン関係を明示的に記録しません。

...

プロジェクト全体よりも、単一ファイルの変更履歴を調べる方が少し費用がかかります。特定のファイルに影響を与える変更の履歴を取得するには、Gitはグローバル履歴をたどり、各変更がそのファイルを変更したかどうかを判断する必要があります。ただし、この方法で履歴を調べることにより、Gitは任意のファイルセットへの変更を示す単一の履歴を同じ効率で生成できます。たとえば、ソースツリーのサブディレクトリと関連するグローバルヘッダーファイルは、非常に一般的なケースです。

...

したがって、ファイルの以前のリビジョンに戻って、2つのファイルを比較できます。


1

gitは実際にはファイルのデルタを保存しますが、ファイルツリー全体のデルタとして保存します。

バージョン間の違いを確認するには、次のいずれかを実行します。

  1. git diff-最後にチェックインしたバージョンと、変更されたが変更されていないファイルとの違いを表示しますgit add実行されてします。
  2. git diff --cached以前のバージョンとgit add、実行されたがコミットされていないすべてのファイルとの違いを表示します
  3. git diff commitid現在の作業ディレクトリとcommitidで指定された以前のコミットの違いを表示します
  4. git diff commita..commitb -2つのコミットaとbの違いを表示します。コミットは、ブランチやタグのようなシンボリック名でもあります。

この答えは本当に正しくありません。これらのコマンドはすべて、ツリー全体だけでなく任意のファイルセットに適用できます。最後にファイル名を追加するだけです。
naught101
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.