A directory listing is the concatenation of its entries, sorted by name, wrapped as a tree object and hashed. Today your tree ids start matching real Git, the first Merkle-tree payoff of the project.
Build a tree object from a set of entries and hash it to an id that matches real Git.
A tree body is nothing more than its entries laid end to end, but there is one
non-negotiable rule: entries are sorted by name before hashing. Git compares
names as raw bytes, so uppercase letters (like R, byte 0x52) sort before
lowercase (like h, byte 0x68), and README.md comes before hello.txt. Sort
differently and you get a different byte sequence and therefore a different hash,
even though the entries are the same.
Wrap the sorted, concatenated entries as a tree object (the same WriteObject
that stored blobs) and you have a directory listing whose id is a fingerprint of
its exact contents. This is the Merkle structure at the core of Git: a tree’s
id depends on the ids of everything it contains, which depend on their contents,
all the way down. Change one byte in one file and every tree from it to the root
gets a new id. You can feed the same entries to git mktree and get the identical
3aa9b583... back.
// sort entries by name, concat EncodeEntry(...) for each, hash as "tree"func (r *Repo) WriteTree(entries []Entry) (string, error) {sort.Slice(entries, func(i, j int) bool { return entries[i].Name < entries[j].Name })var body []byte// for each sorted entry: body = append(body, EncodeEntry(e)...)return r.WriteObject("tree", body)}