Git 計算物件 Hash 時:
"blob {內容長度}\0{內容}"(\0 為 NUL 字元)例:空檔案 → "blob 0\0" → e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
using System;
using System.Security.Cryptography;
using System.Text;
public class GitHasher
{
public string Content { get; set; }
public string Hash { get; private set; }
public void GenerateHash()
{
// 關鍵:UTF-8 編碼 + blob 格式 + NUL 字元
var computedContent = string.Format("blob {0}\0{1}", Content.Length, Content);
var bytes = Encoding.UTF8.GetBytes(computedContent);
using (var sha1 = SHA1.Create()) // .NET Core 建議用 SHA1.Create() 而非 SHA1Managed
{
var hashBytes = sha1.ComputeHash(bytes);
// 轉 40 字元小寫十六進制
var sb = new StringBuilder(hashBytes.Length * 2);
foreach (var b in hashBytes)
sb.Append(b.ToString("x2"));
Hash = sb.ToString();
}
}
}
[Fact]
public void EmptyContent_ShouldMatchGit()
{
var hasher = new GitHasher { Content = "" };
hasher.GenerateHash();
Assert.Equal("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", hasher.Hash);
}
[Fact]
public void NonEmptyContent_ShouldMatchGit()
{
var hasher = new GitHasher { Content = "hello world" };
hasher.GenerateHash();
// 可用命令驗證:echo -en "blob 11\0hello world" | sha1sum
Assert.Equal("3b18e512dba79e4c8300dd08aeb37f8e728b8dad", hasher.Hash);
}
\0 或 \u0000 表示Content.Length),非位元組數SHA1Managed,.NET Core / 5+ 建議用 SHA1.Create()(自動選擇平台最佳實作,且支援 FIPS)ToString("x2") 保證小寫掌握此算法,即可在 C# 中產出與 Git 完全一致的物件 ID,實現與 Git 生態的無縫互通。