ビットごとの分析
フォーマットをよりよく理解し、いくつかのフィールドをより詳細に調査するために、少しテストを行うことにしました。
以下の結果はGitバージョン1.8.5.2
とで同じです2.3
。
わからない/見つからないポイントをマークしましたTODO
。これらのポイントを自由に補完してください。
他の人が述べたように、インデックスは.git/index
標準のツリーオブジェクトとしてではなくの下に保存され、その形式はバイナリであり、https://github.com/git/git/blob/master/Documentation/technical/index-formatにドキュメント化されています。 txt
インデックスはコミットを作成するためのキャッシュであるため、インデックスを定義する主要な構造体はcache.hにあります。
セットアップ
次のコマンドでテストリポジトリを開始すると、
git init
echo a > b
git add b
tree --charset=ascii
.git
ディレクトリのルックスが好き:
.git/objects/
|-- 78
| `-- 981922613b2afb6025042ff6bd878ac1994e85
|-- info
`-- pack
そして、唯一のオブジェクトのコンテンツを取得する場合:
git cat-file -p 78981922613b2afb6025042ff6bd878ac1994e85
我々が得ますa
。これは次のことを示しています。
- blobオブジェクトが作成されて
index
からのファイル内容へのポイントgit add b
- メタデータは、ツリーオブジェクトではなくインデックスファイルに保存されます。これは、オブジェクトが1つしかないためです。ブロブ(通常のGitオブジェクトでは、ブロブメタデータはツリーに保存されます)
hd分析
次に、インデックス自体を見てみましょう。
hd .git/index
与える:
00000000 44 49 52 43 00 00 00 02 00 00 00 01 54 09 76 e6 |DIRC.... ....T.v.|
00000010 1d 81 6f c6 54 09 76 e6 1d 81 6f c6 00 00 08 05 |..o.T.v. ..o.....|
00000020 00 e4 2e 76 00 00 81 a4 00 00 03 e8 00 00 03 e8 |...v.... ........|
00000030 00 00 00 02 78 98 19 22 61 3b 2a fb 60 25 04 2f |....x.." a;*.`%./|
00000040 f6 bd 87 8a c1 99 4e 85 00 01 62 00 ee 33 c0 3a |......N. ..b..3.:|
00000050 be 41 4b 1f d7 1d 33 a9 da d4 93 9a 09 ab 49 94 |.AK...3. ......I.|
00000060
次に結論します:
| 0 | 4 | 8 | C |
|-------------|--------------|-------------|----------------|
0 | DIRC | Version | File count | ctime ...| 0
| ... | mtime | device |
2 | inode | mode | UID | GID | 2
| File size | Entry SHA-1 ...|
4 | ... | Flags | Index SHA-1 ...| 4
| ... |
最初に来るのは、次の場所で定義されたヘッダーです。struct cache_header:
44 49 52 43
:DIRC
。TODO:なぜこれが必要なのですか?
00 00 00 02
:形式バージョン:2.インデックス形式は時間とともに進化しました。現在、4までのバージョンが存在します。GitHub上の異なるコンピューター間でコラボレーションする場合、ベアリポジトリにはインデックスが格納されないため、インデックスの形式は問題になりません。インデックスはクローン時に生成されます。
00 00 00 01
:インデックス上のファイルの数:ちょうど1、 b
。
次に、struct cache_entryで定義されたインデックスエントリのリストを開始します。ここでは1つだけです。を含む:
一連のファイルメタデータ:8バイトctime
、8バイトmtime
、4バイト:デバイス、iノード、モード、UID、GID。
方法に注意してください:
ctime
そして、mtime
(同じです54 09 76 e6 1d 81 6f c6
私たちは、ファイルを変更していないので、予想通り)
最初のバイトは、16進数のEPOCHからの秒数です。
date --date="@$(printf "%x" "540976e6")"
与える:
Fri Sep 5 10:40:06 CEST 2014
これは私がこの例を作ったときです。
次の4バイトはナノ秒です。
UIDとGIDは00 00 03 e8
、16進数で1000です。これは、シングルユーザーセットアップの一般的な値です。
このメタデータのほとんどはツリーオブジェクトに存在しないため、Gitは内容全体を比較することなく、ファイルがすばやく変更されたかどうかを確認できます。
行の先頭に30
:00 00 00 02
:ファイルサイズ:2バイト(a
と\n
からecho
)
78 98 19 22 ... c1 99 4e 85
:エントリの以前のコンテンツを超える20バイトのSHA-1。有効フラグを想定する私の実験によると、それに続くフラグはこのSHA-1では考慮されないことに注意してください。
2バイトのフラグ: 00 01
1ビット:有効なフラグと見なします。私の調査では、この名前の付いていないフラグがgit update-index --assume-unchanged
その状態を保存する場所であることが示されています:https : //stackoverflow.com/a/28657085/895245
1ビット拡張フラグ。拡張フラグが存在するかどうかを決定します。0
拡張フラグを持たないバージョン2でなければなりません。
マージ中に使用される2ビットのステージフラグ。ステージは次の場所に記載されていman git-merge
ます。
0
:マージ競合ではない通常のファイル
1
: ベース
2
: 私たちのもの
3
:彼らのもの
マージの競合中、1〜3のすべてのステージがインデックスに格納され、などの操作が可能になりますgit checkout --ours
。
の場合git add
、ステージ0がパスのインデックスに追加され、Gitは競合が解決済みとしてマークされていることを認識します。TODO:これを確認してください。
たどるパスの12ビット長0 01
::パスがあったため、1バイトのみb
2バイトの拡張フラグ。「拡張フラグ」が基本フラグに設定されている場合にのみ意味があります。TODO。
62
(ASCII b
):可変長パス。前のフラグで決定された長さ、ここでは1バイトのみb
。
次に00
、パスがnullで終了し、インデックスが8バイトの倍数で終了するように、1〜8バイトのゼロパディングがあります。これは、インデックスバージョン4以前にのみ発生します。
拡張機能は使用されませんでした。ファイルにチェックサム用の十分なスペースが残っていないため、Gitはこれを認識しています。
最後にee 33 c0 3a .. 09 ab 49 94
、インデックスの内容に対して20バイトのチェックサムがあります。