gitソース解析(四)commit-tree
3548 ワード
commit-treeコマンドは、後のgit commitコマンド、フォーマットcommit-tree[-p]に似ています.
1.buffer情報フォーマット:commit%lu0 tree%sparent%sauthor%s%scommitter%s%s%s%s
%lu#「tree%sparent%sauthor%s%scommitter%s%s%s」コンテンツ長
2. write_sha1_file(buffer, size); # sha 1ファイルに情報を書き込む
2.1 write_sha1_buffer(sha1, compressed, size); # 組み立てたbuffer情報を圧縮し、圧縮値にhashを取り、sha 1ファイルに圧縮内容を書き込む
2.1.1 char *filename = sha1_file_name(sha1); # hash値から生成する.dircache/objects/xx/xx..xx(38ビット)ファイル名
2.1.2新規作成およびsha 1ファイルへの圧縮データの書き込み
int main(int argc, char **argv)
{
unsigned char tree_sha1[20];
get_sha1_hex(argv[1], tree_sha1);
for (i = 2; i < argc; i += 2)
a = argv[i]; b = argv[i+1];
if (!b || strcmp(a, "-p") || get_sha1_hex(b, parent_sha1[parents]))
usage("commit-tree [-p ]* < changelog");
parents++;
init_buffer(&buffer, &size);
add_buffer(&buffer, &size, "tree %s
", sha1_to_hex(tree_sha1));
for (i = 0; i < parents; i++)
add_buffer(&buffer, &size, "parent %s
", sha1_to_hex(parent_sha1[i]));
add_buffer(&buffer, &size, "author %s %s
", gecos, email, date);
add_buffer(&buffer, &size, "committer %s %s
", realgecos, realemail, realdate);
while (fgets(comment, sizeof(comment), stdin) != NULL)
add_buffer(&buffer, &size, "%s", comment);
finish_buffer("commit ", &buffer, &size);
// buffer: "commit %lu\0tree %s
parent %s
..parent %s
author %s %s
committer %s %s
%s"
// %lu: size of "tree %s
parent %s
..parent %s
author %s %s
committer %s %s
%s"
// size: size of buffer
write_sha1_file(buffer, size);
stream.next_in = buffer;
stream.avail_in = size;
stream.next_out = compressed;
stream.avail_out = len;
while (deflate(&stream, Z_FINISH) == Z_OK);
size = stream.total_out;
SHA1_Init(&c);
SHA1_Update(&c, compressed, size);
SHA1_Final(sha1, &c);
write_sha1_buffer(sha1, compressed, size);
char *filename = sha1_file_name(sha1);
fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
write(fd, compressed, size);
close(fd);
}
1.buffer情報フォーマット:commit%lu0 tree%sparent%sauthor%s%scommitter%s%s%s%s
%lu#「tree%sparent%sauthor%s%scommitter%s%s%s」コンテンツ長
2. write_sha1_file(buffer, size); # sha 1ファイルに情報を書き込む
int write_sha1_file(char *buf, unsigned len)
{
int size;
char *compressed;
z_stream stream;
unsigned char sha1[20];
SHA_CTX c;
/* Set it up */
memset(&stream, 0, sizeof(stream));
deflateInit(&stream, Z_BEST_COMPRESSION);
size = deflateBound(&stream, len);
compressed = malloc(size);
/* Compress it */
stream.next_in = buf;
stream.avail_in = len;
stream.next_out = compressed;
stream.avail_out = size;
while (deflate(&stream, Z_FINISH) == Z_OK)
/* nothing */;
deflateEnd(&stream);
size = stream.total_out;
/* Sha1.. */
SHA1_Init(&c);
SHA1_Update(&c, compressed, size);
SHA1_Final(sha1, &c);
if (write_sha1_buffer(sha1, compressed, size) < 0)
return -1;
printf("%s
", sha1_to_hex(sha1));
return 0;
}
2.1 write_sha1_buffer(sha1, compressed, size); # 組み立てたbuffer情報を圧縮し、圧縮値にhashを取り、sha 1ファイルに圧縮内容を書き込む
int write_sha1_buffer(unsigned char *sha1, void *buf, unsigned int size)
{
char *filename = sha1_file_name(sha1);
int i, fd;
fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
if (fd < 0)
return (errno == EEXIST) ? 0 : -1;
write(fd, buf, size);
close(fd);
return 0;
}
2.1.1 char *filename = sha1_file_name(sha1); # hash値から生成する.dircache/objects/xx/xx..xx(38ビット)ファイル名
2.1.2新規作成およびsha 1ファイルへの圧縮データの書き込み