Здесь мы взглянем на то как манипулировать git на более низком уровне, в случае если вы пожелаете написать инструмент генерирующий новые блобы, деревья, или коммиты искуственным способом. Если вы захотите написать скрипт который использует более низкоуровневые функции git, чтобы проделать что то новое, здесь некоторые инструменты нужные вам.
Создание блобов в вашем Git репозитории и получение SHA значения несложно. Команда git hash-object это все что вам нужно. Чтобы создать объект блоб из существующего файла, просто выполните ее с параметром '-w' (который говорит ей записать блоб, а не просто вычислить SHA).
$ git hash-object -w myfile.txt
6ff87c4664981e4397625791c8ea3bbb5f2279a3
$ git hash-object -w myfile2.txt
3bb0e8592a41ae3185ee32266c860714980dbed7
В выводе команды вы увидите SHA значение блоба который был создан..
Теперь давайте положим вы хотите создать дерево из ваших новых объектов. Команда git mktree делает это просто генерируя новый объект дерево из git ls-tree форматированного вывода. Например, если вы записали следующее в файл под именем '/tmp/tree.txt' :
100644 blob 6ff87c4664981e4397625791c8ea3bbb5f2279a3 file1
100644 blob 3bb0e8592a41ae3185ee32266c860714980dbed7 file2
и затем пропустили это через команду git mktree, Git запишет новое дерево в базу данных объектов и выдаст вам новое sha значение этого дерева.
$ cat /tmp/tree.txt | git mk-tree
f66a66ab6a7bfe86d52a66516ace212efa00fe1f
Затем, мы можем взять это и сделать это поддиректорией еще одного другого дерева, и так далее. Если мы хотим создать новое дерево с этим как поддеревом, мы просто созданим новый файл (/tmp/newtree.txt) с нашим новым SHA как дерево в нем:
100644 blob 6ff87c4664981e4397625791c8ea3bbb5f2279a3 file1-copy
040000 tree f66a66ab6a7bfe86d52a66516ace212efa00fe1f our_files
и затем выполним git mk-tree снова:
$ cat /tmp/newtree.txt | git mk-tree
5bac6559179bd543a024d6d187692343e2d8ae83
И мы теперь имеем искуственную структуру директорий в Git, которая выглядит следующим образом:
.
|-- file1-copy
`-- our_files
|-- file1
`-- file2
1 directory, 3 files
причем это структура никогда в действительности не существовала на диске. Плюс, у нас есть SHA (5bac6559
) которое указывает на нее.
Мы также можем проделать манипуляции с объединением деревьев в новую структуру используя файл индекс. Как простейший пример, давайте возьмем дерево которое мы только что создали и сделаем новое дерево которое имеет две копии нашего 5bac6559
дерева в нем используя временный файл индекс. (Вы можете проделать это сбросив переменную окружения GIT_INDEX_FILE или в командной строке)
Первое, мы читаем дерево в наш индекс файл под новым префиксом используя команду git read-tree, и затем запишем содержимое индекса как дерево используя команду git write-tree:
$ export GIT_INDEX_FILE=/tmp/index
$ git read-tree --prefix=copy1/ 5bac6559
$ git read-tree --prefix=copy2/ 5bac6559
$ git write-tree
bb2fa6de7625322322382215d9ea78cfe76508c1
$>git ls-tree bb2fa
040000 tree 5bac6559179bd543a024d6d187692343e2d8ae83 copy1
040000 tree 5bac6559179bd543a024d6d187692343e2d8ae83 copy2
Теперь мы видим что мы создали новое дерево просто манипулируя индексом. Вы также можете делать интересные операции слияния и тому подобное во временном индексе. Просмотрите документацию git read-tree чтобы получить больше подробностей.
Теперь когда у нас есть SHA дерева, мы можем создать объект коммит которое на него указывает. Мы можем проделать это используя команду git commit-tree. Больщинство данных которые потом войдут в коммит должны быть установленны как переменные окружения, так что вам потребуется установить их:
GIT_AUTHOR_NAME
GIT_AUTHOR_EMAIL
GIT_AUTHOR_DATE
GIT_COMMITTER_NAME
GIT_COMMITTER_EMAIL
GIT_COMMITTER_DATE
Затем вам потребуется записать ваше сообщение-описание коммита в файл или каким либо образом передать эту информацию в команду через STDIN. Затем, вы можете создать ваш коммит основываясь на sha дерева которое есть нас.
$ git commit-tree bb2fa < /tmp/message
a5f85ba5875917319471dfd98dfc636c1dc65650
Если вы хотите определить один или более родителей коммита, просто добавьте sha значения в командную строку вместе с параметром '-p' перед каждым из них. SHA нового объекта коммита будет выведено как результат работы команды..
Теперь у нас есть SHA значение нового объекта коммит, и мы можем обновить ветку чтобы она указывала него если мы так хотим. Давайте скажем что мы хотим обновить нашу ветку 'master' так чтобы она указывала на новый коммит который мы только что создали - мы используем команду git update-ref для этого:
$ git update-ref refs/heads/master a5f85ba5875917319471dfd98dfc636c1dc65650