Как сделать правильную Git-совместимую упаковку / сжатие hex Sha в Go - PullRequest
2 голосов
/ 23 мая 2019

Я изучаю книгу Building Git , написанную Джеймсом Когланом, где Джеймс знакомит вас с реализацией базовой версии Git на Ruby.Я решил все усложнить для себя, выполнив свою реализацию в Go.

Я дошел до того, что мне нужно хранить сжатые хеши содержимого файла в дереве для записи на диск, но явозникли проблемы с выполнением такого вида шестнадцатеричного сжатия / упаковки, которое ищет Git.

Вот код Ruby, который я отработал для

ENTRY_FORMAT = "A7Z*H40"
MODE = "100644"
FILE_NAME = "tree.rb"
SHA = "baae99010b237a699ff0aba02fd5310c18903b1b"
[MODE, FILE_NAME , SHA].pack(ENTRY_FORMAT)

метода пакета Ruby:

Метод Array # pack принимает массив различных типовзначений и возвращает строку, которая представляет эти значения.То, как каждое значение будет представлено в строке, определяется форматной строкой, которую мы передаем пакету.

Кодировка MODE и FILE_NAME Я думаю, что у меня все хорошо.Это последняя часть, которая кодирует ша, с которым я борюсь.

• H40: это кодирует строку из сорока шестнадцатеричных цифр, entry.oid, упаковывая каждую пару цифр в один байт

Это "упаковка каждой пары цифр в один байт, которую я не могу понять. Это моя текущая попытка:

mode := 100644
fileName := "tree.go"
sha:= "baae99010b237a699ff0aba02fd5310c18903b1b"
// slice of strings for constructing the packed sha
var eid []string

// iterate through each character in id
for i := 0; i < len(sha); i += 2 {
    // gathering them in pairs of two
    one, two := sha[i], sha[i+1]
    // compress two digits into one byte
    // using bitwise or?? addition?? bit shifting?? not sure.
    eid = append(eid, string(one|two))
}
// concat the new packed id with the mode and file name.
stringRep := fmt.Sprintf("%-7d", mode) + fileName + "\x00" + strings.Join(eid, "")

Перейти на игровую площадкудля приведенного выше кода

По какой-то причине, которую я не могу выяснить, строковое представление записи дерева, которую создает функция, несовместимо с тем, как Git хранит деревья на диске.сдвигая биты перед or их использованием, и я попытался просто сложить байты вместе, но, похоже, ничего не работает. Мне в основном нужно повторить поведение метода Ruby Array#pack таким образом, который Git примет.

Любое руководство или совет очень приветствуется. Я был бы рад объяснить больше или опубликовать больше примеров кода, если это необходимо. Большое спасибо за ваше время!

PS моРеализация контекста вокруг упаковки git выполняется из Building Git

Git хранит идентификатор каждой записи в упакованном формате, используя двадцать байтов для каждого.Каждая шестнадцатеричная цифра представляет число от нуля до пятнадцати, где десять представлено a, одиннадцать - b и так далее до f в течение пятнадцати.В сороказначном идентификаторе объекта каждая цифра обозначает четыре бита 160-битного числа.Вместо того, чтобы разбивать эти биты на сорок кусочков по четыре бита каждый, мы можем разделить их на двадцать блоков по восемь бит, а восемь бит - это один байт.Таким образом, все, что здесь происходит, заключается в том, что 160-битный идентификатор объекта хранится в двоичном виде в виде двадцати байтов, а не в виде сорока символов, обозначающих шестнадцатеричные цифры.

1 Ответ

1 голос
/ 23 мая 2019

Функции для преобразования между двоичными и шестнадцатеричными строками можно найти в пакете hex .

Например: функция для преобразования входной шестнадцатеричной строки в массив байтов (где каждый байт содержит две из начальных цифр шестнадцатеричной строки): hex.DecodeString - или hex.Decode, если вы вводите []byte вместо string.


Если вы хотите повторно реализовать эту функцию:

  • каждый символ входной строки должен быть преобразован в его числовое значение,
  • каждая пара значений должна рассматриваться как цифра в базе 16: var newByte byte = 16*one + two
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...