Gitストレージの原則と関連する実装について話す

以下のコンテンツはhttps://www.toutiao.com/i6938300453767676455/から複製されています。

点滅する遺伝子2021-03-1115:53:07

Gitストレージの原則と関連する実装について話す

 

[編集者注] Gitは現在最も人気のあるバージョン管理システムです。ローカル開発から本番環境への展開まで、毎日バージョン管理にGitを使用しています。毎日のコマンドに加えて、Gitの理解を深めたい場合は、次に、Gitの基本的なストレージ原則を研究することは、Gitとその使用法を理解するのに非常に役立ちます。Git開発者でなくても、Gitの基本的な原則を理解することをお勧めします。Gitのまったく新しい力が得られます。理解して、毎日のGit使用プロセスでより便利になります。

この記事は、Gitをある程度理解している読者を対象としています。Gitの特定の役割と使用法については紹介しません。また、Subversionなどの他のバージョン管理システムとの違いについても紹介しません。主にGitを紹介します。彼のストレージ実装の関連する原則は、バージョン管理にGitを使用するときに、Gitユーザーが内部実装をより明確に理解できるように設計されています。

Gitの本質は何ですか

Gitは基本的にコンテンツアドレス指定のKey-Valueデータベースです。Gitリポジトリに任意のタイプのコンテンツを挿入でき、Gitは一意のキー値を返します。このキーを使用して、その時点で挿入した値を取得できます。基になるコマンドgithash-objectコマンドを使用して試すことができます。

➜  Zoker git:(master) ✗ cat testfile

Hello Git

➜  Zoker git:(master) ✗ git hash-object testfile -w

9f4d96d5b00d98959ea9960f069585ce42b1349a

ディレクトリにtestfileという名前のファイルがあることがわかります。コンテンツはHelloGitです。githash-objectコマンドを使用して、このファイルのコンテンツをGitリポジトリに書き込みます。-wオプションは、Gitにこのコンテンツを書き込むように指示します。 Gitに。git/ objectsオブジェクトデータベースディレクトリで、GitがSHA値を返した場合、このSHA値は、後で取得するファイルのキー値です。

➜  Zoker git:(master) ✗ git cat-file -p 9f4d96d5b00d98959ea9960f069585ce42b1349a

Hello Git

git cat-fileコマンドを使用して、Gitリポジトリに保存されたばかりのコンテンツを取得しました。Redisコマンドが設定されるほど直感的ではありませんが、実際にはKVデータベースです。

挿入しようとしたデータは基本的なblobタイプのオブジェクトです。Gitにはtreeやcommitなどの他のオブジェクトタイプもあります。これらの異なるオブジェクトタイプには特定の関連付け関係があり、論理的に異なるオブジェクトを関連付けます。起きたときにのみ制御できます。さまざまなバージョンをチェックしてください。これらのさまざまなオブジェクトタイプについては後で詳しく説明します。まず、Gitのディレクトリ構造を理解し、データがGitにどのように格納されるかを見てみましょう。

Gitディレクトリ構造

前のセクションの紹介を通じて、Gitは本質的にKVデータベースであり、コンテンツは.git / objectsオブジェクトディレクトリに書き込まれることもわかりました。このディレクトリはどこにありますか?Gitはこのデータをどのように保存しますか?このセクションでは、Gitストレージディレクトリ構造に焦点を当て、Gitがさまざまなタイプのデータを保存する方法を理解します。

詳細な紹介については、
https //github.com/git/git/blo ... t.txtを参照してください。

git initを使用して、現在のディレクトリに空のGitウェアハウスを初期化できます。Gitは自動的に.gitディレクトリを生成します。この.gitディレクトリは、後続のすべてのGitメタデータのストレージセンターです。ディレクトリ構造を見てみましょう。

➜  Zoker git init

Initialized empty Git repository in /Users/zoker/tmp/Zoker/.git/

➜  Zoker git:(master) ✗ tree .git

.git

├── HEAD              // 是一个符号引用,指明当前工作目录的版本引用信息,我们平时执行 checkout 命令时就会改变 HEAD 的内容

├── config             // 配置当前存储库的一些信息,如:Proxy、用户信息、引用等,此处的配置项相对于全局配置权重更高

├── description      // 仓库描述信息

├── hooks             // 钩子目录,执行 Git 相关命令后的回调脚本,默认会有一些模板

│   ├── update.sample

│   ├── pre-receive.sample

│   └── ...

├── info                // 存储一些额外的仓库信息如 refs、exclude、attributes 等

│   └── exclude

├── objects           // 元数据存储中心

│   ├── info

│   └── pack

└── refs               // 存放引用信息,也就是分支、标签

├── heads

└── tags

デフォルトの初期化で生成されたGitウェアハウスには、これらのファイルのみが含まれます。さらに、packed-refsモジュールログなど、他の種類のファイルやディレクトリもあります。これらのファイルには特定の用途があり、特定の操作または構成の後にのみ表示されます。 、ここではコアストレージの実装にのみ焦点を当て、これらの追加のファイルまたはディレクトリの役割と使用シナリオは、ドキュメントを単独で参照できます。ここでは、コアファイルの一部のみを紹介します。

フックディレクトリ

hooksディレクトリには主にGitフックが格納されています。Gitフックは多くのイベントが発生した後または発生する前にトリガーできるため、非常に柔軟な使用方法が提供されます。デフォルトでは、すべてに.sampleサフィックスが付いています。削除する必要があります。このサフィックスと実行可能権限を付与して有効にします。一般的に使用されるフックとその一般的な使用法を次に示します。

クライアントフック:

  • pre-commit:送信された情報が標準化されているかどうか、テストが完了しているかどうか、コード形式が要件を満たしているかどうかの確認など、送信前にトリガーされます
  • コミット後:逆に、これは送信全体が完了した後にトリガーされ、通知の送信に使用できます

サーバーフック:

  • pre-receive:サーバーがプッシュ要求を受信したときに最初に呼び出され、これらのプッシュされた参照が要件を満たしているかどうかを検出できるスクリプト
  • 更新:事前受信と同様ですが、事前受信は1回だけ実行され、更新はプッシュされたブランチごとに1回実行されます。
  • 受信後:プッシュプロセス全体が完了した後にトリガーされ、通知の送信、ビルドシステムのトリガーなどに使用できます。

オブジェクトディレクトリ

前のセクションで述べたように、Gitは受信したすべてのコンテンツ生成オブジェクトファイルをこのディレクトリに保存します
。githash -objectを介してオブジェクトを生成し、Gitウェアハウスに書き込みました。このオブジェクトのキー値は9f4d96d5b00d98959ea9960f069585ce42b1349aです。オブジェクトディレクトリの構造で:

➜  Zoker git:(master) ✗ git hash-object testfile -w

9f4d96d5b00d98959ea9960f069585ce42b1349a

➜  Zoker git:(master) ✗ tree .git/objects

.git/objects

├── 9f

│   └── 4d96d5b00d98959ea9960f069585ce42b1349a

├── info

└── pack

オブジェクトディレクトリに新しいコンテンツがあることがわかります。追加の9fフォルダとファイルがあります。このファイルはGitリポジトリに挿入されたオブジェクトファイルです。Gitはキー値の最初の2文字をフォルダとして取り、保存します。オブジェクトファイルのファイル名は次の文字です。ここに格納されているオブジェクト(つまり、objects / [0-9a-f] [0-9a-f])は、一般にルーズオブジェクトまたはアンパックオブジェクトと呼ばれます。ルーズです。オブジェクト。

オブジェクトストレージフォルダに加えて、パッケージファイルに対応するobjects / packフォルダの存在に注意する必要があります。スペースを節約して効率を向上させるために、緩いオブジェクトファイルが多すぎる場合や手動で実行する場合git gcコマンド、またはプッシュとプルの転送プロセス中に、Gitはこれらのルーズオブジェクトファイルをパックファイルにパックして効率を向上させます。パックされたファイルは次のとおりです。

➜  objects git:(master) git gc

...

Compressing objects: 100% (75/75), done.

...

➜  objects git:(master) tree

.

├─ pack

├── pack-fe24a22b0313342a6732cff4759bedb25c2ea55d.idx

└── pack-fe24a22b0313342a6732cff4759bedb25c2ea55d.pack

└── ...

オブジェクトディレクトリにルーズオブジェクトがないことがわかります。代わりに、パックディレクトリに2つのファイルがあります。1つはパッケージファイルで、もう1つはパッケージコンテンツのインデックスを作成するidxファイルです。オブジェクトは、対応するパックパッケージのこの中にあります。

現時点で手動で作成したblobオブジェクトのウェアハウスでGCを実行した場合、現時点ではGitウェアハウス全体がこのオブジェクトを参照していないため、効果はありません。このオブジェクトは無料です。参照が保存されているディレクトリを紹介しましょう。

refsディレクトリ

refsディレクトリには参照が格納されます。参照はバージョン番号のエイリアスと見なすことができます。実際には特定のコミットのSHA値が格納されます。上記のテストに使用したウェアハウスにはコミットがないため、空は1つだけです。ディレクトリ構造。

└── refs

├── heads

└── tags

彼のデフォルトのブランチマスターを表示するためのコミットを含むリポジトリをランダムに見つけます。

➜  .git git:(master) cat refs/heads/master

87e917616712189ecac8c4890fe7d2dc2d554ac6

マスター参照にはコミットSHA値のみが格納されていることがわかります。もちろん、SHA値の長い文字列を覚えておく必要がないという利点があります。このバージョンを取得するには、マスターエイリアスを使用するだけで済みます。同じタグディレクトリにタグが保存されます。ブランチとは異なり、タグの記録された参照値は通常変更されませんが、ブランチはバージョンによって変更される可能性があります。さらに、特定の名前空間への参照を格納するrefs / remotes refs / fetchなどのディレクトリも表示される場合があります。

別の状況があります。それは前述のGCメカニズムです。ウェアハウスがGCを実行すると、オブジェクトディレクトリ内の緩いオブジェクトがパッケージ化されるだけでなく、参照の下の参照もパッケージ化されますが、それらはベアウェアハウスに保存されます。 .git / packed-refsのルートディレクトリ

➜  .git git:(master) cat packed-refs

# pack-refs with: peeled fully-peeled sorted

87e917616712189ecac8c4890fe7d2dc2d554ac6 refs/heads/master

ブランチマスターにアクセスする必要がある場合、Gitは最初にrefs / headsを検索します。見つからない場合は、.git / packed-refsに移動して検索します。すべての参照を1つのファイルにパックすると、間違いなく多くのことが改善されます。効率.. この時点でマスターブランチへのコミットを更新すると、Gitはこの時点で.git / packed-refsファイルを直接変更せず、refs / heads /の下にマスター参照を直接再作成することに注意してください。最新のコミットのSHA値。先ほど紹介したGitメカニズムによると、Gitは最初にrefs / heads /を調べ、見つからない場合は.git / packed-refsに移動します。

では、参照に格納されているCommitのSHA値は何を参照していますか?cat-fileコマンドを使用して、表示するblobオブジェクトのコンテンツを表示できます。

➜  .git git:(master) git cat-file -p 87e917616712189ecac8c4890fe7d2dc2d554ac6

tree aab1a9217aa6896ef46d3e1a90bc64e8178e1662 // 指向的 tree 对象

parent 7d000309cb780fa27898b4d103afcfa95a8c04db // 父提交

author Zoker <[email protected]> 1607958804 +0800 // 作者信息

committer Zoker <[email protected]> 1607958804 +0800 // 提交者信息



test ssh // 提交信息

これはコミットタイプのオブジェクトであり、主な属性は、それが指すツリーオブジェクト、その親コミット(最初のコミットの場合、次に0000000 ...)、作成者、およびコミット情報です。

では、コミットオブジェクトとは何ですか?それが指すツリーオブジェクトは何ですか?以前に手動で作成したblobオブジェクトとの違いは何ですか?次に、Gitストレージオブジェクトについて説明しましょう。

Gitストレージオブジェクト

Gitの世界には、ファイル(blob)、ツリー(tree)、commit(commit)、tag(tag)の4つのタイプのストレージオブジェクトがあります。ここでは、最初の3つのタイプについて主に説明します。これらの3つは最も基本的なGitだからです。メタデータであり、タグオブジェクトは、追加の属性情報、つまり注釈付きタグを含む単なるタグなので、ここではあまり紹介しません。

軽量で注釈付きのタグの概要:
https //git-scm.com/book/zh/v2 ...%25BE

Blobオブジェクト

Gitの本質を紹介するとき、Gitがコンテンツアドレス指定に基づくKVデータベースであることを示すために、ファイルのコンテンツをGitリポジトリに挿入しました。

➜  Zoker git:(master) ✗ cat testfile

Hello Git

➜  Zoker git:(master) ✗ git hash-object testfile -w

9f4d96d5b00d98959ea9960f069585ce42b1349a

キーが
9f4d96d5b00d98959ea9960f069585ce42b1349aであるGitオブジェクトは、実際にはBlobオブジェクトであり、テストファイルファイルの値を格納します。cat-fileコマンドを使用して以下を表示できます。

➜  Zoker git:(master) ✗ git cat-file -p 9f4d96d5b00d98959ea9960f069585ce42b1349a

Hello Git

ファイルを変更するたびに、Gitは差異を記録するのではなく、ファイルの完全なスナップショットを保存します。したがって、テストファイルファイルのコンテンツを変更して、Gitリポジトリに再度保存すると、Gitは最新のものに基づいてファイルを生成します。 contentそのキー、コンテンツが変更されない場合、そのキー値は固定されていることに注意してください。結局のところ、前述したように、Gitはコンテンツアドレス指定に基づくKVデータベースです。

さらに、ここのBlobオブジェクトはテキストコンテンツを格納します。バイナリコンテンツにすることもできますが、Gitを使用してバイナリファイルのバージョンを管理することはお勧めしません。日常の運用プロセスでGiteeプラットフォームが遭遇する最も一般的な問題は、ユーザーウェアハウスが大きすぎることです。この状況は通常、ユーザーが大きなバイナリファイルを送信することによって発生します。これは、各ファイルの変更がスナップショットとして記録されるため、このバイナリがfile変更が頻繁に行われる場合、それが占めるスペースは2倍になります。また、テキストコンテンツブロブの場合、GitはGCプロセス中に2つの送信間のファイルの違いのみを保存するため、スペースを節約できますが、バイナリコンテンツブロブの場合、テキストコンテンツブロブのように処理することはできません。したがって、頻繁に変更されるものを保存しないようにしてください。 Gitリポジトリ内のバイナリコンテンツ。LFSを使用して保存できます。すでに多数のバイナリファイルがある場合は、フィルターブランチを使用して体重を減らすことができます。新しい同僚は、ウェアハウスのクローンを初めて作成するときに間違いなく感謝します。

LFSの使用
:https://gitee.com/help/articles/4235、大きな倉庫のスリム化:https://gitee.com/help/articles/4232、フィルターブランチ:https:// github .com / git / git / blo ... h.txt

ここに着いたら何かがおかしいと思いますか?そうです、このBlobオブジェクトはこのファイルのコンテンツのみを格納し、ファイル名は記録しません。では、このコンテンツがどのファイルに属しているかをどのようにして知ることができますか?その答えは、Gitのもう1つの重要なオブジェクトであるTreeオブジェクトです。

ツリーオブジェクト

Gitでは、Treeオブジェクトの主な機能は複数のBlobまたは子Treeオブジェクトをまとめることであり、すべてのコンテンツはTreeおよびBlobタイプのオブジェクトによって保存されます。ツリーオブジェクトには1つ以上のツリーエントリ(ツリーオブジェクトレコード)が含まれ、各ツリーオブジェクトレコードには、BlobまたはサブツリーSHA値へのポインタと、対応するファイル名およびその他の情報が含まれます。これらは実際に理解できます。ファイルシステム内のiノードとブロックの関係にインデックスを付けるために、Treeオブジェクトが表示されている場合は、次のようになります。

Gitストレージの原則と関連する実装について話す

 

このTreeオブジェクトに対応するディレクトリ構造は次のとおりです。

.

├── LICENSE

├── readme.md

└── src

├── libssl.so

└── logo.png

このようにして、Linuxでディレクトリを整理する方法、Treeをディレクトリ構造、Blobを特定のファイルコンテンツと見なすなど、構造化された方法でウェアハウスのコンテンツを保存できます。

では、Treeオブジェクトを作成する方法は?Gitでは、対応するTreeオブジェクトがステージング領域の状態に応じて作成されます。ここでのステ​​ージング領域は、実際にはGitを使用する日常のプロセスで理解されるステージング領域(Staged)です。通常、gitaddコマンドを使用してaddいくつかのファイルが、送信されるステージング領域に追加されます。送信されていない空のウェアハウスでは、このステージング領域のステータスは、次のようにgitaddを介して追加したファイルです。

➜  Zoker git:(master) ✗ git status

On branch master



No commits yet



Changes to be committed:

(use "git rm --cached <file>..." to unstage)

new file:   LICENSE

new file:   readme.md



Untracked files:

(use "git add <file>..." to include in what will be committed)

src/

ここでのステ​​ージング領域の現在の状態は、ルートディレクトリに2つのファイルがあることです。ステージング領域の状態は.git / indexファイルに保存されます。fileコマンドを使用して、それが何であるかを確認しましょう。

➜  Zoker git:(master) ✗ file .git/index

.git/index: Git index, version 2, 2 entries

インデックスファイルには2つのエントリがあります。つまり、ルートディレクトリには2つのファイルLICENSEとreadme.mdがあります。送信されたウェアハウスの場合、一時ストレージ領域にコンテンツがない場合、このインデックスはディレクトリツリーの状態の現在のバージョンを表します。ファイルが変更または削除され、一時ストレージ領域が追加されると、インデックスは次のようになります。変更、関連ファイルのポインターは、ファイルの新しいBlobオブジェクトのSHA値を指します。

したがって、Treeオブジェクトを作成する場合は、ステージング領域に何かを配置する必要があります。gitaddを使用するだけでなく、基になるコマンドupdate-indexを使用してステージング領域を作成することもできます。次に、上記で作成したテストファイルファイルに基づいてツリーオブジェクトを作成します。1つ目は、ファイルテストファイルを一時ストレージ領域に追加することです。

➜  Zoker git:(master) ✗ git update-index --add testfile // 与 git add testfile 一样

➜  Zoker git:(master) ✗ git status

On branch master



No commits yet



Changes to be committed:

(use "git rm --cached <file>..." to unstage)

new file:   testfile

このプロセスでは、Gitは主にテストファイルのコンテンツをBlobの形式でGitウェアハウスに挿入し、返されたBlobのSHA値をインデックスに記録して、ファイルのコンテンツが現在どのコンテンツであるかを一時ストレージ領域に通知します。

➜  Zoker git:(master) ✗ tree .git/objects

.git/objects

├── 9f

│   └── 4d96d5b00d98959ea9960f069585ce42b1349a

├── info

└── pack



3 directories, 1 file

➜  Zoker git:(master) ✗ git cat-file -p 9f4d96d5b00d98959ea9960f069585ce42b1349a

Hello Git

Gitがupdate-indexコマンドを実行すると、指定されたファイルのコンテンツがBlobオブジェクトとして保存され、インデックスファイルの状態で記録されます。以前にgithash-objectコマンドを使用してこのファイルのコンテンツを挿入したことがあるので、コンテンツが変更されていないため、生成されたBlobオブジェクトのSHA値も、すでに挿入している場合は同じであることがわかります。次のコマンドは同等です。

git update-index --add --cacheinfo 9f4d96d5b00d98959ea9960f069585ce42b1349a testfile

このコマンドは、実際には、以前に生成されたBlobオブジェクトを一時記憶域に置き、そのファイル名をtestfileとして指定します。ステージング領域にはすでにファイルtestfileがあるため、git write-treeコマンドを使用して、現在のステージング領域のステータスに基づいてTreeオブジェクトを作成できます。

➜  Zoker git:(master) ✗ git write-tree

aa406ee8804971cf8edfd8c89ff431b0462e250c

➜  Zoker git:(master) ✗ tree .git/objects

.git/objects

├── 9f

│   └── 4d96d5b00d98959ea9960f069585ce42b1349a

├── aa

│   └── 406ee8804971cf8edfd8c89ff431b0462e250c

├── info

└── pack

コマンドの実行後、Gitは現在のステージング領域の状態に基づいてSHA値が
aa406ee8804971cf8edfd8c89ff431b0462e250cのTreeオブジェクトを生成し、このTreeオブジェクトをBlobオブジェクトのように.git / objectsディレクトリに保存します。

➜  Zoker git:(master) ✗ git cat-file -p aa406ee8804971cf8edfd8c89ff431b0462e250c

100644 blob 9f4d96d5b00d98959ea9960f069585ce42b1349a    testfile

cat-fileコマンドを使用してこのTreeオブジェクトを表示すると、このオブジェクトの下にtestfileという名前のファイルが1つしかないことがわかります。

Gitストレージの原則と関連する実装について話す

 

2番目のTreeオブジェクトの作成を続行します。2番目のTreeオブジェクトの下に変更されたtestfileファイル、新しいtestfile2ファイル、および2番目のTreeオブジェクトの複製ディレクトリとして最初のTreeオブジェクトが必要です。まず、変更したテストファイルと新しく追加したtestfile2ファイルを一時ストレージ領域に追加します。

➜  Zoker git:(master) ✗ git update-index testfile

➜  Zoker git:(master) ✗ git update-index --add testfile2

➜  Zoker git:(master) ✗ git status

On branch master



No commits yet



Changes to be committed:

(use "git rm --cached <file>..." to unstage)

new file:   testfile

new file:   testfile2

次に、最初のTreeオブジェクトを重複ディレクトリにハングアップする必要があります。read-treeコマンドを使用して次のことを実行できます。

➜  Zoker git:(master) ✗ git read-tree --prefix=duplicate aa406ee8804971cf8edfd8c89ff431b0462e250c 

➜  Zoker git:(master) ✗ git status

On branch master



No commits yet



Changes to be committed:

(use "git rm --cached <file>..." to unstage)

new file:   duplicate/testfile

new file:   testfile

new file:   testfile2

次に、write-treeを実行し、cat-fileを介して2番目のTreeオブジェクトを表示します。

➜  Zoker git:(master) ✗ git write-tree

64d62cef754e6cc995ed8d34f0d0e233e1dfd5d1

➜  Zoker git:(master) ✗ git cat-file -p 64d62cef754e6cc995ed8d34f0d0e233e1dfd5d1

040000 tree aa406ee8804971cf8edfd8c89ff431b0462e250c    duplicate

100644 blob 106287c47fd25ad9a0874670a0d5c6eacf1bfe4e    testfile

100644 blob 098ffe6f84559f4899edf119c25d276dc70607cf    testfile2

正常に完了すると、testfileのファイル内容を変更するだけでなく、新しいファイルtestfile2を追加し、最初のTreeオブジェクトを2番目のTreeオブジェクトの複製ディレクトリとして扱いました。現時点では、Treeオブジェクトは次のようになっています。

Gitストレージの原則と関連する実装について話す

 

これまで、Treeオブジェクトを手動で作成する方法を知っていますが、後でこれら2つの異なるツリーのスナップショットが必要になった場合はどうなりますか?これらの3つのTreeオブジェクトのSHA値を思い出せませんか?そうです、覚えておくのは大変な労力です。重要なのは、誰がいつ、何のためにこのスナップショットを作成したのかわからないことです。Commitオブジェクト(commitオブジェクト)は、この問題の解決に役立ちます。

オブジェクトをコミットする

Commitオブジェクトは、主にスナップショットのいくつかの追加情報を記録し、スナップショット間の線形関係を維持することです。git commit-treeコマンドを使用してコミットを作成できます。このコマンドは、文字通り、TreeオブジェクトをCommitオブジェクトとして送信するために使用されるコマンドであることを意味します。

➜  Zoker git:(master) ✗ git commit-tree -h

usage: git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...] [(-F <file>)...] <tree>



-p <parent>           id of a parent commit object

-m <message>          commit message

-F <file>             read commit log message from file

-S, --gpg-sign[=<key-id>]

                      GPG sign commit

2つの重要なパラメータは-pと-mです。-pはこの提出物の親提出物を指定します。それが最初の最初の提出物である場合、ここでは無視できます。-mはこの提出物の情報を指定し、主に提出の理由。最初のTreeオブジェクトを最初のコミットとして使用しましょう。

➜  Zoker git:(master) ✗ git commit-tree -m "init commit" aa406ee8804971cf8edfd8c89ff431b0462e250c

17ae181bd6c3e703df7851c0f7ea01d9e33a675b

この提出物を表示するには、cat-fileを使用してください。

tree aa406ee8804971cf8edfd8c89ff431b0462e250c

author Zoker <[email protected]> 1613225370 +0800

committer Zoker <[email protected]> 1613225370 +0800



init commit

Commitによって保存されるコンテンツはTreeオブジェクトであり、コミッター、コミット時間、およびコミット情報を記録します。このコミットに基づいて2番目のTreeオブジェクトを参照します。

➜  Zoker git:(master) ✗ git commit-tree -p 17ae181bd -m "add dir" 64d62cef754e6cc995ed8d34f0d0e233e1dfd5d1

de96a74725dd72c10693c4896cb74e8967859e58

➜  Zoker git:(master) ✗ git cat-file -p de96a74725dd72c10693c4896cb74e8967859e58

tree 64d62cef754e6cc995ed8d34f0d0e233e1dfd5d1

parent 17ae181bd6c3e703df7851c0f7ea01d9e33a675b

author Zoker <[email protected]> 1613225850 +0800

committer Zoker <[email protected]> 1613225850 +0800



add dir

git logを使用してこれら2つのコミットを表示できます。ここで、-statパラメーターを追加してファイル変更レコードを表示します。

commit de96a74725dd72c10693c4896cb74e8967859e58

Author: Zoker <[email protected]>

Date:   Sun Feb 13 22:17:30 2021 +0800



add dir



duplicate/testfile | 1 +

testfile           | 2 +-

testfile2          | 1 +

3 files changed, 3 insertions(+), 1 deletion(-)



commit 17ae181bd6c3e703df7851c0f7ea01d9e33a675b

Author: Zoker <[email protected]>

Date:   Sun Feb 13 22:09:30 2021 +0800



init commit



testfile | 1 +

1 file changed, 1 insertion(+)

このとき、オブジェクト全体の構造は次のとおりです。

Gitストレージの原則と関連する実装について話す

 

演習:低レベルのコマンドを使用してコミットを作成します

上記のハッシュオブジェクト書き込みツリー読み取りツリーコミットツリーなどの低レベルコマンドのみを使用してコミットを作成し、どのプロセスがgit add gitcommitと同等であるかを検討します。

オブジェクトストレージ方式

前回の紹介で、Gitはさまざまなオブジェクトタイプのデータを要約し、アドレス指定として使用するコンテンツに基づいてSHA値を計算することを知っていますが、どのように計算されますか?Blobオブジェクトを例にとると、Gitは主に次の手順を実行します。

  • オブジェクトのタイプを識別し、ヘッダー情報を作成し、タイプ+コンテンツバイト+ヌルバイトをヘッダー情報として使用します(blob 151 \ u0000など)。
  • ヘッダー情報とコンテンツをつなぎ合わせて、SHA-1チェックサムを計算します
  • zlibを介してコンテンツを圧縮する
  • そのコンテンツをSHA値で対応するオブジェクトディレクトリに配置します

これらはプロセス全体で実行されます。TreeオブジェクトとCommitオブジェクトは似ていますが、ヘッドタイプが異なります。ここでは詳しく説明しません。「ProGit 2」では、Rubyを使用して同じことを実現する方法を紹介します。 Gitの内部原則の章にあります。ロジック、興味のある人は自分でそれを読むことができます。

Git-内部原則:
https //git-scm.com/book/zh/v2 ...%25A1

Gitリファレンス

上記のgitlog --stat 17ae181bを介して最初のバージョンの関連情報を表示し、このSHA値の文字列を介してこのスナップショットのコンテンツを取得できますが、文字列が意味がない現時点では、Gitリファレンスが役に立ちます。Gitディレクトリ構造の章では、refsディレクトリを紹介しました。Commitオブジェクトのキー値がリファレンスに格納されていることがわかります。これは、オブジェクトのSHA値です。このようにして、現在のバージョンに意味のある名前を付け、通常、デフォルトのブランチ参照としてmasterを使用します。

➜  Zoker git:(master) ✗ echo "17ae181bd6c3e703df7851c0f7ea01d9e33a675b" >> .git/refs/heads/master

➜  Zoker git:(master) ✗ tree .git/refs

.git/refs

├── heads

│   └── master

└── tags

この時点で、最初のCommitのSHA値がマスターに格納されており、masterを使用して17ae181bの無意味な文字列を置き換えることができます。

➜  Zoker git:(master) ✗ git cat-file -p master

tree aa406ee8804971cf8edfd8c89ff431b0462e250c

author Zoker <[email protected]> 1613916447 +0800

committer Zoker <[email protected]> 1613916447 +0800



init commit

ただし、これは最新バージョンではありません。最新バージョンは2番目の
送信de96a74725dd72c10693c4896cb74e8967859e58です。同様に、refs / heads / masterのコンテンツをこの送信のSHA値に変更できますが、ここでは低レベルのコマンドcarryを使用します。でる。

➜  Zoker git:(master) ✗ git update-ref refs/heads/master de96a74725dd72c10693c4896cb74e8967859e58

➜  Zoker git:(master) ✗ cat .git/refs/heads/master

de96a74725dd72c10693c4896cb74e8967859e58

現時点では、ブランチマスターは最新バージョンを指しています。

Gitストレージの原則と関連する実装について話す

 

総括する

上記では、主にGitの基本的なストレージの原則といくつかの実装、およびパックのパッケージ化、送信ネゴシエーションメカニズム、ストレージ形式などについて説明します。スペースの制限のため、これらについては説明しません。後で説明します。いくつかのシナリオ。

著者:ゾッカー

https://zoker.io/blog/talk-about-git-internals

おすすめ

転載: blog.csdn.net/pyf09/article/details/115095221