Низкоуровневая работа с git репозиторием

У меня появилась интересная задача — сконверсить некие версионные данные в формат git репозитория. Для решения этой задачи я чуть-чуть разобрался как храняться данные в git репозитории и как их можно формировать руками.

Задача

Я сформировал для себя следующую задачу, которую я хочу научиться решать. Я хочу сделать git репозтоторий с несколькими комитами:


line 1
line 2
line 3

line 1
line 22 АБВ
line 3

Решение

Я нашел в интернете замечательную серию статей про внутренности git. В этих статья совершенно прекрасно объяснено как git хранит данные и как с ними работать. Огромный респект и уважуха автору.

В этих статьях сильно больше информации чем мне нужно для того чтобы решить мою задачу. Вот тезисы из этих статей, которые мне важны для решения задачи:


$ mkdir ~/tmp/gitguts
$ cd ~/tmp/gitguts

$ git init
Initialized empty Git repository in .git/

$ echo 'Hello, World!' > tutorial.txt

$ git hash-object -w tutorial.txt
8ab686eafeb1f44702738c8b0f24f2567c36da6d

$ find .git/objects -type f
.git/objects/8a/b686eafeb1f44702738c8b0f24f2567c36da6d

$ mkdir ~/tmp/gitgut3
$ cd ~/tmp/gitgut3

$ git init
Initialized empty Git repository in .git/

$ echo "File1" > file1
$ echo "File2" > file2

$ git hash-object -w file1
03f128cf48cb203d938805e9f3e13b808d1773e9
$ git hash-object -w file2
b973e639605e63466ea5ba09b04a545f16946ca8

$ echo -e "100640 blob 03f128cf48cb203d938805e9f3e13b808d1773e9\tfile1
100640 blob b973e639605e63466ea5ba09b04a545f16946ca8\tfile2" | git mktree
b2efb2a7e48025c4d185080412a6ba1121ee6c59

$ ls .git/objects/b2/efb2a7e48025c4d185080412a6ba1121ee6c59
.git/objects/b2/efb2a7e48025c4d185080412a6ba1121ee6c59

$ mkdir ~/tmp/gitguts4
$ cd ~/tmp/gitguts4
$ git init
Initialized empty Git repository in .git/

$ echo "file1" > file1
$ echo "file2" > file2
$ git hash-object -w file1
e2129701f1a4d54dc44f03c93bca0a2aec7c5449
$ git hash-object -w file2
6c493ff740f9380390d5c9ddef4af18697ac9375

$ echo -e "10644 blob e2129701f1a4d54dc44f03c93bca0a2aec7c5449\tfile1
10644 blob 6c493ff740f9380390d5c9ddef4af18697ac9375\tfile2" | git mktree
eaa27839f1ccaa6e087202ec96c479ee2c93b71e

$ export GIT_AUTHOR_NAME="Git Guts"
$ export GIT_AUTHOR_EMAIL="gitguts@localhost"
$ export GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"
$ export GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"

$ echo "Initial commit" | faketime 20000101 git commit-tree  eaa27839f1ccaa6e087202ec96c479ee2c93b71e
6d8e5c7bab119e7b746e76259b37513cb5cc84e9

$ git cat-file commit 6d8e5c7bab119e7b746e76259b37513cb5cc84e9
tree eaa27839f1ccaa6e087202ec96c479ee2c93b71e
author Git Guts  946684800 +0000
committer Git Guts  946684800 +0000

Initial commit

$ echo '6d8e5c7bab119e7b746e76259b37513cb5cc84e9' > .git/refs/heads/master
$ git branch -a
* master

Все. Этих данных достаточно для того чтобы решить мою задачу. Теперь мне нужно написать скрипт, который будет создавать репозиторий с комитами из условия задачи.

Perl

Пошел искать как бы успросить всю эту работу из Perl. Нашел библиотеку [Git::Raw][gr]. Про нее есть отзыв:

I really recommend this module if you have to handle git repository directly! :-)

Побробовал этот модуль, но он не подошел — возникли сложности со сборкой его и всех его зависимостей в deb пакеты. Нашел другой модуль Git::Repository, оказалось что он уже запакетирован в deb и есть в репозитории ubutnu. Поставил — и это оказался очень хороший модуль.

И с помощью Git::Repository я написал perl скрипт, которы выполняет ровно ту задачу, которую я собирался решить.

Получилось достоточно забавно — я руками создаю все фалый в базе данных git, создаю комиты и создаю ветку master, но настоящие файлы в рабочей копии я не создаю, поэтому после выполнения скрипта git status говорит что рабочая копия отличается от комита, но для моей задачи это не важно, поэтому я не стал это исправлять.

bessarabov@rofl:/tmp/nSUTrsQ7gU$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       deleted:    aaa.md
#       deleted:    bbb.md
#       deleted:    ccc.md
#

Иван Бессарабов
ivan@bessarabov.ru

26 августа 2014

Edit this post on GitHub