2014-01-25 3 views
2

Я пытаюсь передать хэш-код SHA1 для GIT-фиксации вручную, но что-то не работает правильно.C# Compute GIT Commit Hash

Во-первых, мы имеем сообщение стандарт коммит, который выглядит примерно так:

tree f594b3f6d9ae291c83902f3992aa36872aa70d68 

parent 0000004bf6d464667df5150b4526083886947d92 

author User <[email protected]> 1390620460.46263 +0000 
committer User <[email protected]> 1390620460.46263 +0000 

Commit Message 

мы называем это «commitMessage»

Спецификация говорит, что для получения фиксации хэш говорит, что мы должны sha1:

  • строка "фиксации"
  • плюс пробел ""
  • плюс число байтов в commitMessage
  • плюс нулевой байт
  • плюс commitMessage

так (псевдокод OBV)

SHA1("commit" + " " + numBytes(commitMessage) + '\0' + commitMessage);

И вот моя реализация в C# (Я знаю, что это довольно неуклюжий)

var commitBody = "tree " + treeHash + "\n\n" + 
        "parent " + parentHash + "\n\n" + 
        "author User <[email protected]> " + date + "\n" + 
        "committer User <[email protected]> " + date + "\n\n" + 
        "My Commit Message\n"; 

    var blob = "commit " + Encoding.UTF8.GetByteCount(commitBody); 

    // This is the string "commit " (with a space) + byte count 
    var first = Encoding.UTF8.GetBytes(blob); 

    // This is just the null byte 
    var second = new byte[1]; 
    second[0] = (byte)0; 

    // This is the commitMessage 
    var third = Encoding.UTF8.GetBytes(commitBody); 

    // Merge first, second, third into bytez as a byte array 
    var bytez = new byte[first.Length + second.Length + third.Length]; 
    Buffer.BlockCopy(first, 0, bytez, 0, first.Length); 
    Buffer.BlockCopy(second, 0, bytez, first.Length, second.Length); 
    Buffer.BlockCopy(third, 0, bytez, first.Length + second.Length, third.Length); 

    // Debug Print 
    Console.WriteLine(Encoding.UTF8.GetString(bytez)); 

    // Compute the hash and print it 
    var sss = SHA1.Create(); 
    var myssh = GetString(sss.ComputeHash(bytez)); 
    Console.WriteLine(myssh); 

Возвращенный хэш не совпадает с возвратом из GIT. Я на самом деле не ожидаю, что кто-нибудь узнает, как это сделать, поскольку это не то, что обычно делается, но я решил, что спрошу.

Спасибо за любую помощь: D

ответ

1

хэш Каждый объект является на самом деле хэш «Длина +„“+ Content» - это работает, чтобы предотвратить SHA1 хэш столкновений (так как теперь вы должны столкнуться как на SHA1 и длина, которая является менее вероятной)

+0

придираться: Я думаю, что вы имеете в виду объект, не blob, так как это о коммитах – alternative

+0

Исправлено, вы правы! –

1

Если вы используете символы UTF-8 в своих строках, не используйте string.Length для резервирования массива байтов. Это верно, если строка содержит только символы ASCII, но если в вашей строке присутствуют символы UTF-8, то .Length будет меньше, чем фактический размер байта.

Поскольку вы используете .Length для выделения массива, этот массив может быть малым, а не все данные строк могут быть скопированы.

Я бы предположил, что вы используете StringBuilder, чтобы построить свою строку, а затем используйте System.Text.Encoding.UTF8.GetBytes(stringbuilder.ToString()), чтобы получить данные в виде байтов.

StringBuilder sb = new StringBuilder(); 
sb.Append("commit "+ Encoding.UTF8.GetByteCount(commitBody)); 
sb.Append("\0"); 
sb.Append(commitBody); 

var sss = SHA1.Create(); 
var bytez = Encoding.UTF8.GetBytes(sb.ToString()); 
var myssh = GetString(sss.ComputeHash(bytez)); 
Console.WriteLine(myssh); 
0

Там не должно быть никаких пустых строк после того, tree и parent линий, то есть совершает тело должно быть:

tree f594b3f6d9ae291c83902f3992aa36872aa70d68 
parent 0000004bf6d464667df5150b4526083886947d92 
author User <[email protected]> 1390620460.46263 +0000 
committer User <[email protected]> 1390620460.46263 +0000 

Commit Message 

См первоначальную реализацию C; commit_tree_extended() в commit.c.

0

Не C#, но вот как можно вычислить мерзавец совершить хэш из Баш строки:

commit_len=$(git cat-file commit HEAD | wc -c) 
(echo -ne "commit $commit_len\0"; git cat-file commit HEAD) | sha1sum 

Убедитесь, что хэш является правильным:

git show HEAD | grep commit 
Смежные вопросы