C#计算GIT提交哈希

时间:2014-01-25 03:59:01

标签: c# git sha

我正在尝试手动获取GIT提交的SHA1提交哈希值,但某些内容无法正常工作。

首先,我们有标准的提交消息,如下所示:

tree f594b3f6d9ae291c83902f3992aa36872aa70d68

parent 0000004bf6d464667df5150b4526083886947d92

author User <foo@bar.com> 1390620460.46263 +0000
committer User <foo@bar.com> 1390620460.46263 +0000

Commit Message

我们称之为'commitMessage'

规范说要获取提交哈希说我们必须使用sha1:

  • 字符串“commit”
  • 加上空格“”
  • 加上commitMessage
  • 中的字节数
  • 加上空字节
  • 加上commitMessage

so(伪代码obv)

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

这是我在C#中的实现 (我知道这很笨重)

    var commitBody = "tree " + treeHash + "\n\n" +
                     "parent " + parentHash + "\n\n" +
                     "author User <foo@bar.com> " + date + "\n" +
                     "committer User <foo@bar.com> " + 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

4 个答案:

答案 0 :(得分:1)

每个对象的哈希实际上都是“长度+'+ +内容”的哈希值 - 这可以防止SHA1哈希冲突(因为现在你必须在SHA1 两者上发生冲突,是不太可能)

答案 1 :(得分: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);

答案 2 :(得分:0)

treeparent行之后应该没有空行,即提交正文应该是:

tree f594b3f6d9ae291c83902f3992aa36872aa70d68
parent 0000004bf6d464667df5150b4526083886947d92
author User <foo@bar.com> 1390620460.46263 +0000
committer User <foo@bar.com> 1390620460.46263 +0000

Commit Message

参见原始的C实现; commit.c中的commit_tree_extended()。

答案 3 :(得分:0)

不是C#,但是这里有如何从bash提示符计算git commit hash:

keyup

检查哈希是否正确:

<input type="text" id="searchbar" placeholder="search file"> <span id="loading" style="display:none;">loading</span>
<div id="result"></div>
<script src="../../vendor/jquery/jquery-3.2.1.min.js"></script>
<script>
    $(function(){
        $('#searchbar').keyup(function(){//event after user release keyboard
            var val = $(this).val();
            if(val.length >= 2){//min 2 words to start find
                $.ajax({
                    url: 'search.php',
                    type: 'POST',
                    dataType: 'json', //we use json
                    data: {keyword: val},
                    beforeSend: function(){
                        $('#loading').show();
                    },
                    success: function(d){
                        if(d.ok==1){
                            $('#result').html(d.list);
                        }else{
                            alert(d.msg);
                        }
                        $('#loading').hide();
                    },
                    error: function(d){
                        alert('error');
                        $('#loading').hide();
                    }
                });
            }
        })
    });
</script>