Gitコマンド入門::Gitオブジェクト(RubyでBLOB作成)第五十三回
みなさんこんにちは! 今回も前回に引き続き、さらに深堀して、BLOBオブジェクトを、Ruby で作成してみますね。とはいっても、そんなに難しいことでもなく、Gitのドキュメントの通りに、実際に自分でも試してみるだけですけどね。(笑)
前回の記事はこちらから!
git本家本元の情報はこちらから!
今日の課題も前回同様、ここを参考にしています!
10.2 Gitの内側 - Gitオブジェクト
Figure 150は、ページの下の方にあります! 今日はここを学習していきますね!
それでは早速いつもの~ git initから!
$ mkdir func0053 && cd $_
// フォルダー作成と移動を同時に実行、
// 第53回なので、func0053
$ git init
// 毎度のイニシャル!
Rubyをインストールして置きましょう!
yum install ruby
$ ruby -v
ruby 2.0.0p648 (2015-12-16) [x86_64-linux]
インストールが分からない方は、こちらのサイトからどうぞ!!
では、久しぶりの作図です!
ヘッダー構造について
- 先頭は、blob とか、tree, commit などの種別の文字列が入ります。
- その次は、コンテンツのデーターサイズですね。
- 最後は、¥0の区切り文字です。ヘッダーとデーターを区別するため。
データー構造について
- こちらは、テキスト、バイナリ、どちらでも当然OK!
- Zlib ライブラリを使って圧縮しています。「ヘッダーも含めて圧縮!」
ハッシュ値について
- ヘッダーのあとにデーターを連結させてから、SHA1でハッシュ値を作成
- 40文字のハッシュ値の最初の2文字がフォルダー名、残りの38文字がファイル名
例:bd9dbf5aae1a3862dd1526723246b20206e5fc37
カレント | フォルダ名 | ファイル名 |
---|---|---|
.git/objects/ | bd | 9dbf5aae1a3862dd1526723246b20206e5fc37 |
では、Rubyでの処理は、こんな感じです!
- コンテンツを作成
- コンテンツのサイズを取得
- ヘッダーを作成
- ヘッダーとコンテンツを結合して、一つにまとめる。
- 4番でまとめたデーターから、SHA1ハッシュ値を作成
- ハッシュ値から、フォルダー名とファイル名を作成
- 4番でまとめたデーターを、Zlibで圧縮する。
- 7番で圧縮したデーターを、6番のファイル名で保存
本家のドキュメントサイトでは、irb コマンドで行っていますので、そちらでお試しください。
$ irb
>> content = "what is up, doc?"
=> "what is up, doc?"
上記のように、irbコマンドで始まるところです。そこを参照してお試しください!
それでは、処理の解説しま~す!
# 1. コンテンツを作成
content = "what is up, doc?" + "\n"
# 2. コンテンツのサイズを取得 #{content.length}
# 3. ヘッダーを作成 blob or tree , commit
header = "blob #{content.length}\0"
# 4. ヘッダーとコンテンツを結合して、一つにまとめる。
store = header + content
# 5. 4番でまとめたデーター[store]から、SHA1ハッシュ値を作成
sha1 = Digest::SHA1.hexdigest(store)
# 6. ハッシュ値から、フォルダー名とファイル名を作成
path = '.git/objects/' + sha1[0,2] + '/' + sha1[2,38]
# 7. 4番でまとめたデーター[store]を、Zlibで圧縮する。
zlib_content = Zlib::Deflate.deflate(store)
# 8. 7番で圧縮したデーターzlib_content を、6番のファイル名[path]で保存
FileUtils.mkdir_p(File.dirname(path))
File.open(path, 'w') {
|f| f.write zlib_content
}
さあ~、いかがでしょうか? いたってシンプルなプログラムですね!
サンプルページでは、コンテンツテキストが、"what is up, doc?" となり、
ハッシュ値は、bd9dbf5aae1a3862dd1526723246b20206e5fc37 ですね。
実際に確認してみましょう!
$ find .git/objects/ -type f
.git/objects/bd/9dbf5aae1a3862dd1526723246b20206e5fc37
// ファイルが作成されました!
$ git cat-file -p bd9dbf5aae1a3862dd1526723246b20206e5fc37
what is up, doc?
// テキスト内容
$ git cat-file -s bd9dbf5aae1a3862dd1526723246b20206e5fc37
16
// ファイルサイズは、16バイト
$ git cat-file -t bd9dbf5aae1a3862dd1526723246b20206e5fc37
blob
// 属性は、blob
私が作成したオリジナルですが、宜しければどうぞ!
ファイルから読み込むようにしてあります。ruby sample.rb <任意のファイル>
実行可能!
#! /bin/ruby
require 'zlib'
require 'digest/sha1'
require 'fileutils'
argvc = ARGV.size()
if argvc == 0 then
print "ruby sample.rb <input-file> \n";
exit
end
$global = ''
f = open(ARGV[0])
while line = f.gets
$global = $global + line
end
f.close
#
# コンテンツテキスト
#
content = $global
# content = "what is up, doc?"
#
# BLOB のヘッダー
#
header = "blob #{content.length}\0"
#
# ヘッダー+コンテンツ
#
store = header + content
print "Data: " + store + "\n"
#
# ハッシュ値の取得
#
sha1 = Digest::SHA1.hexdigest(store)
print "SHA1: " + sha1 + "\n\n"
#
# フォルダー2文字/ファイル名38文字
#
path = '.git/objects/' + sha1[0,2] + '/' + sha1[2,38]
print "PATH: " + path + "\n"
#
# Zlib で圧縮!
#
zlib_content = Zlib::Deflate.deflate(store)
#
# フォルダー作成
#
FileUtils.mkdir_p(File.dirname(path))
#
# ファイル保存
#
File.open(path, 'w') {
|f| f.write zlib_content
}
#
# git cat-file で確認!
#
print "\n"
print "git cat-file -t => "
system('git cat-file -t ' + sha1 )
print "git cat-file -s => "
system('git cat-file -s ' + sha1 )
print "git cat-file -p => "
system('git cat-file -p ' + sha1 )
print "\n"
system('find .git/objects -type f')
print "\n"
exit
sample.rb の実行結果!
$ echo "Ruby BLOB" > README.md
// ファイルの中身は、Ruby BLOB
$ ./sample.rb README.md <!-- 必ず、ファイル名を指定してください!
// ruby sample.rb README.md でも可能!
Data: blob 10Ruby BLOB // <!-- blob + Size + コンテンツテキスト
SHA1: 4571358b3c1294d24cde428fd6babdac9810da18
PATH: .git/objects/45/71358b3c1294d24cde428fd6babdac9810da18
// cat-file で確認した結果!
git cat-file -t => blob
git cat-file -s => 10
git cat-file -p => Ruby BLOB
// find .git/objects/ -type f でファイルの存在確認
.git/objects/45/71358b3c1294d24cde428fd6babdac9810da18
.git/objects/bd/9dbf5aae1a3862dd1526723246b20206e5fc37
今回のまとめ
みなさんも実際に試していただくと、より、gitの中心部に近づいた気がすると思います。私のような古いプログラマーにとっては、データとかソースコードが大好物です。正直なところ、時間の余裕があれば、gitのソースコードの中身を追いかけたいぐらいですけどね。ま、今時は、そんなことをしていたら、いくら時間があっても足りませんね。(^▽^;)
ただ、ファミコン、スーファミの時代は、OSも含めて、全てフルスクラッチ、しかもアセンブラで書いていましたから、どうしてもそういう発想になってしまう。あ、、、セガサターンも提供されたライブラリーが使えなかったから、あの時も、SH2のRISCアセンブラで、フルスクラッチでしたよ!(笑)・・・完全に余談でした。
本気のまとめ・・・
ここでのポイントは、実際にデータに触れることで、Gitへの恐怖感を取り除くことかな? 私もそうですけど、何か問題やトラブルが起こったとき、結構、気が動転しまうタイプです。そんなときに一番役立つのが、知識とか経験ですからね。
それでは、今回はここまで、お疲れ様でした!
Discussion