Before an object can be hashed or stored, Git wraps its contents in a tiny header that records the object's type and size. Getting these bytes exactly right is what makes our hashes match real Git, so today you build that serialization.
Serialize a piece of content into Git's loose object format, a header followed by the content.
Every object Git stores, whatever its type, is serialized the same way: a short
header of "<type> <size>" then a single NUL byte (a zero byte) then the raw
content. The type is a word like blob, tree, or commit; the size is the
length of the content in bytes as decimal ASCII digits. For our file hello.txt
holding hello\n (5 letters plus a newline, so 6 bytes) the header is
blob 6 then a zero byte.
This wrapper is the whole reason our hashes will match real Git: the hash is taken over these exact bytes, header and all, not over the file content alone. The size and the NUL separator are what let a reader split the header back off later. Keep this a pure function that takes a type and content and returns the serialized bytes; nothing is written to disk yet.
// header is "<type> <size>\0", then the raw contentfunc Serialize(typ string, content []byte) []byte {header := fmt.Sprintf("%s %d\x00", typ, len(content))return append([]byte(header), content...)}