Git Write a tree GoLang

I’m stuck on Stage Write a tree object

My hashed output is clearly wrong but looking at the examples I’m not sure where I’m going wrong

Here are my logs:

Expected (bytes 0-100), hexadecimal:                        | ASCII:
[tester::#FE4] 74 72 65 65 20 39 38 00 34 30 30 30 30 20 64 6f 6f 62 79 00 | tree 98.40000 dooby.
[tester::#FE4]  d3 f5 e9 63 90 73 4c 7d f6 45 51 57 3d 39 4e 76 74 79 22 19| ...c.sL}.EQW=9Nvty".
[tester::#FE4] 31 30 30 36 34 34 20 68 6f 72 73 65 79 00 ad 53 ca 5b 29 5b | 100644 horsey..S.[)[
[tester::#FE4] 2a b8 16 6f a9 e5 7d 7e 1c 84 d0 da e1 85 34 30 30 30 30 20 | *..o..}~......40000 
[tester::#FE4] 79 69 6b 65 73 00 46 42 ce ab dd 64 3c df 12 ea 0d 63 d4 b4 | yikes.FB...d<....c..

[tester::#FE4] Actual (bytes 0-100), hexadecimal:                          | ASCII:
[tester::#FE4] 74 72 65 65 20 39 38 00 34 30 30 30 30 20 64 6f 6f 62 79 00 | tree 98.40000 dooby.
[tester::#FE4]  e8 26 da a5 e8 80 85 a2 0f 7b 97 db 58 1f af 7d 9c 9c 5d 43| .&.......{..X..}..]C
[tester::#FE4] 31 30 30 36 34 34 20 68 6f 72 73 65 79 00 ad 53 ca 5b 29 5b | 100644 horsey..S.[)[
[tester::#FE4] 2a b8 16 6f a9 e5 7d 7e 1c 84 d0 da e1 85 34 30 30 30 30 20 | *..o..}~......40000 
[tester::#FE4] 79 69 6b 65 73 00 ad a5 98 70 4c 05 c3 54 4a b6 64 a0 7d b7 | yikes....pL..TJ.d.}.

And here’s a snippet of my code:

func writeTreeObject(location string) string {
	entries, _ := os.ReadDir(location)
	tree := ""
	for _, entry := range entries {
		if entry.Name() == ".git" {
			continue
		}
		if !entry.IsDir() {
			// This is a file
			hash := createGitObject(location + "/" + entry.Name())
			s := fmt.Sprintf("100644 %s\x00%s", entry.Name(), hash)
			tree += s
		} else {
			// This is a dir
			encodedHash := writeTreeObject(location + entry.Name())
			hash, _ := hex.DecodeString(encodedHash)
			s := fmt.Sprintf("40000 %s\x00%s", entry.Name(), hash)
			tree += s
		}
	}

	treeHeader := fmt.Sprintf("tree %d\x00", len(tree))
	encodedFilename := hex.EncodeToString(hashContents(tree))
	finalTree := []byte(treeHeader + tree)

	os.MkdirAll(".git/objects/"+encodedFilename[:2], os.ModePerm)
	path := fmt.Sprintf(".git/objects/%v/%v", encodedFilename[:2], encodedFilename[2:])

	var b bytes.Buffer
	w := zlib.NewWriter(&b)
	w.Write(finalTree)
	w.Close()

	os.WriteFile(path, b.Bytes(), 0777)
	return encodedFilename
}
func hashContents(contents string) []byte {
	h := sha1.New()
	h.Write([]byte(contents))

	return h.Sum(nil)
}

func createGitObject(filename string) []byte {
	data, err := os.ReadFile(filename)
	if err != nil {
		fmt.Println(err)
	}

	content := []byte("blob " + strconv.Itoa(len(data)) + "\x00" + string(data))

	// Get hash file name
	hashedFilename := hashContents(string(content))
	encodedFilename := hex.EncodeToString(hashedFilename)

	path := fmt.Sprintf(".git/objects/%v/%v", encodedFilename[:2], encodedFilename[2:])

	var b bytes.Buffer
	w := zlib.NewWriter(&b)
	w.Write(content)
	w.Close()

	os.MkdirAll(".git/objects/"+encodedFilename[:2], os.ModePerm)

	err = os.WriteFile(path, b.Bytes(), 0777)

	if err != nil {
		fmt.Println(err)
	}

	return hashedFilename
}

I’ll take a look shortly.

Hi @NotLucxs, the bug is here:

func writeTreeObject(location string) string {
	...

	firstLine := fmt.Sprintf("tree %d\x00", len(tree))
	encodedFilename := hex.EncodeToString(hashContents(tree))
	finalTree := []byte(firstLine + tree)

The hash should be computed from finalTree instead of tree.

Hi @andy1li
Thank you!
I had a feeling something simple was escaping me, a good spot from you

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.