A tree object records the contents of one directory as a list of entries, each naming a file or subdirectory. Today you encode a single entry, the building block of every directory listing, with its mode, name, and the raw bytes of a hash.
Encode one tree entry as a mode, a name, a NUL, and the 20 raw bytes of an id.
A tree is Git’s directory: a flat list of entries, one per item directly inside that directory. Each entry has three parts: a mode (a numeric file type, like Unix permission bits), the name of the file or subdirectory, and the id of the object it points at. A file entry points at a blob; a subdirectory entry points at another tree.
The encoding has one sharp edge worth pinning now: the id is stored as 20 raw
bytes, the binary form of the hash, not the 40 hex characters we print. So the
hello.txt entry is the text 100644 hello.txt, a NUL separator, then the 20-byte
form of ce013625.... The modes are written as plain digits with no leading zero
(so a directory is 40000, not 040000). Get these bytes exactly right and the
tree ids will match real Git; get the binary-vs-hex detail wrong and every tree
hash will be off.
// "<mode> <name>\0" then the id as 20 raw bytes, NOT 40 hex charsfunc EncodeEntry(mode, name, id string) []byte {raw, _ := hex.DecodeString(id) // 40 hex -> 20 bytesout := []byte(mode + " " + name + "\x00")return append(out, raw...)}