Git write-tree command hash mismatch with git output

I’m stuck on Stage #FE4 git write-tree

My write-tree command creates all object files as I expect and they can be read using ls-tree command and it shows the expected result, but the hash differs from the one generated by git write-tree. And if I try to read it using real git I get “error: hash mismatch 72b8d28613c74fcffa26d7fcf662d01880a3e952”.

Here are my logs:

remote: [tester::#FE4] Expected (bytes 0-100), hexadecimal:                        | ASCII:
remote: [tester::#FE4] 74 72 65 65 20 31 30 31 00 31 30 30 36 34 34 20 64 75 6d 70 | tree 101.100644 dump
remote: [tester::#FE4] 74 79 00 f0 51 9d dc d6 b8 40 86 ea 99 cd 92 65 50 87 3f 81 | ty..Q....@.....eP.?.
remote: [tester::#FE4] 12 2f be 34 30 30 30 30 20 68 6f 72 73 65 79 00 b5 ef 33 bb | ./.40000 horsey...3.
remote: [tester::#FE4] f0 a8 2a 9b 85 d1 0a be 61 9a eb 02 6f 65 e9 0d 34 30 30 30 | ..*.....a...oe..4000
remote: [tester::#FE4] 30 20 76 61 6e 69 6c 6c 61 00 d1 fb d0 01 14 d4 11 32 39 f5 | 0 vanilla........29.
remote: [tester::#FE4] 
remote: [tester::#FE4] Actual (bytes 0-100), hexadecimal:                          | ASCII:
remote: [tester::#FE4] 74 72 65 65 20 31 36 31 00 31 30 30 36 34 34 20 64 75 6d 70 | tree 161.100644 dump
remote: [tester::#FE4] 74 79 00 66 30 35 31 39 64 64 63 64 36 62 38 34 30 38 36 65 | ty.f0519ddcd6b84086e
remote: [tester::#FE4] 61 39 39 63 64 39 32 36 35 35 30 38 37 33 66 38 31 31 32 32 | a99cd926550873f81122
remote: [tester::#FE4] 66 62 65 34 30 30 30 30 20 68 6f 72 73 65 79 00 36 34 35 62 | fbe40000 horsey.645b
remote: [tester::#FE4] 32 35 65 35 36 65 32 63 31 30 37 34 33 64 38 35 61 66 37 66 | 25e56e2c10743d85af7f


And here’s a snippet of my code:

System.out.print(writeTree(new File(".")));

private String writeTree(File file) {
        File[] files = file.listFiles();
        Arrays.sort(files);

        StringBuilder treeContent = new StringBuilder();
        for (File f : files) {
            if (f.getName().equals(".git")) {
                continue;
            }
            String hash;
            String mode;
            if (f.isDirectory()) {
                hash = processDir(f);
                mode = "40000";
            } else {
                hash = createObjectFromFile(f.getPath(), true);
                mode = "100644";
            }
            String entry = String.format("%s %s\0%s", mode, f.getName(), hash);
            treeContent.append(entry);
        }

        byte[] content = treeContent.toString().getBytes();
        String hash = hashObjectProcessor.hash(content);
        byte[] header = ("tree " + content.length).getBytes();
        hashObjectProcessor.createObjectFile(hash, header, content);

        return hash;
    }

public String hash(byte[] content) {
           MessageDigest digest = MessageDigest.getInstance("SHA-1");
           digest.update("blob ".getBytes());
           digest.update(String.valueOf(content.length).getBytes());
           digest.update(new byte[]{0});
           byte[] hash = digest.digest(Arrays.copyOf(content, content.length));
           return HexFormat.of().formatHex(hash);
 }

public String createObjectFromFile(String fileName, boolean needWrite) {
        final File file = new File(fileName);
        byte[] content;
        try (FileInputStream fio = new FileInputStream(file)) {
            content = fio.readAllBytes();
        } 
        String hash = hash(content);

        if (needWrite) {
            byte[] header = ("blob " + content.length).getBytes();
            createObjectFile(hash, header, content);
        }
        return hash;
    }

public void createObjectFile(String hash, byte[] header, byte[] content) {
        File root = new File(".git/objects");

        new File(root, hash.substring(0, 2)).mkdirs();
        final File object = new File(root, hash.substring(0, 2) + "/" + hash.substring(2));
        object.createNewFile();

        byte[] output = new byte[header.length + content.length + 1];
        System.arraycopy(header, 0, output, 0, header.length);
        output[header.length] = 0x00;
        System.arraycopy(content, 0, output, header.length + 1, content.length);

        output = ZLibUtils.compress(output);
        try (FileOutputStream fos = new FileOutputStream(object)) {
            fos.write(output);
        }
    }

Hi @antey13, looks like you’re using the SHA-1 hash in its hex form (40 bytes), whereas the expectation is for its raw binary form (20 bytes).

1 Like

You are right, thank you!

1 Like