I’m stuck on Stage #FE4.
I’ve tried to refactor how I create the object in the createTree() method. however, no matter what I try it keeps telling me that the git objects don’t match. I do see that the Tree may be the issue. I just can’t figure out why they could be different.
On a sidenote when I run this locally and the run the ls-tree on the object it created it the output is the correct tree structure.
Here are my logs:
remote: [tester::#FE4] Running tests for Stage #FE4 (Write a tree object)
remote: [tester::#FE4] $ ./your_program.sh init
remote: [your_program] Initialized git directory
remote: [tester::#FE4] Creating some files & directories
remote: [tester::#FE4] $ ./your_program.sh write-tree
remote: [your_program] dcb4a85d839bbac0681f9d78de7806a5ba0f3b58
remote: [tester::#FE4] Reading file at .git/objects/dc/b4a85d839bbac0681f9d78de7806a5ba0f3b58
remote: [tester::#FE4] Found git object file written at .git/objects/dc/b4a85d839bbac0681f9d78de7806a5ba0f3b58.
remote: [tester::#FE4] Git object file doesn't match official Git implementation. Diff after zlib decompression:
remote: [tester::#FE4]
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 61 70 70 6c | tree 101.100644 appl
remote: [tester::#FE4] 65 00 f6 5b 24 36 3c f5 76 ef ae 87 58 a5 df f7 aa 9a cb df | e..[$6<.v...X.......
remote: [tester::#FE4] 51 f8 34 30 30 30 30 20 6d 61 6e 67 6f 00 c7 8a 95 55 9e 53 | Q.40000 mango....U.S
remote: [tester::#FE4] 2c 11 b9 71 f4 1d 7f d7 27 6a e5 3c 8f 54 34 30 30 30 30 20 | ,..q....'j.<.T40000
remote: [tester::#FE4] 72 61 73 70 62 65 72 72 79 00 94 6f bc ff ab 03 58 a8 11 57 | raspberry..o....X..W
remote: [tester::#FE4]
remote: [tester::#FE4] Actual (bytes 0-100), hexadecimal: | ASCII:
remote: [tester::#FE4] 74 72 65 65 20 33 00 30 34 30 30 30 30 20 6d 61 6e 67 6f 00 | tree 3.040000 mango.
remote: [tester::#FE4] 4e 58 07 ef bf bd 64 ef bf bd ef bf bd 13 2a 42 ef bf bd ef | NX....d.......*B....
remote: [tester::#FE4] bf bd 21 ef bf bd c8 92 ef bf bd ef bf bd 58 2c 30 34 30 30 | ..!...........X,0400
remote: [tester::#FE4] 30 30 20 72 61 73 70 62 65 72 72 79 00 49 ef bf bd 4b 70 5f | 00 raspberry.I...Kp_
remote: [tester::#FE4] 03 ef bf bd 2e ef bf bd ef bf bd 56 ef bf bd ef bf bd 76 ef | ...........V......v.
remote: [tester::#FE4]
remote: [tester::#FE4] Git object file doesn't match official Git implementation
remote: [tester::#FE4] Test failed
And here’s a snippet of my code:
const fs = require('fs');
const zlib = require('zlib');
const crypto = require('crypto');
const path = require('path');
// Helper to compute SHA-1 hash
function computeSha1(data) {
return crypto.createHash('sha1').update(data).digest('hex');
}
// Helper to write object to the .git/objects directory
function writeObject(sha, content) {
const dir = path.join('.git', 'objects', sha.slice(0, 2));
const file = sha.slice(2);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
fs.writeFileSync(path.join(dir, file), content);
}
// Create a blob object for a file and return its SHA-1 hash
function createBlob(filePath) {
const content = fs.readFileSync(filePath, 'utf-8');
const blobData = Buffer.from(`blob ${content.length}\0${content}`);
// const blobData = Buffer.concat([blobHeader, content]);
const sha = computeSha1(blobData);
const compressedBlob = zlib.deflateSync(blobData);
writeObject(sha, compressedBlob);
return sha;
}
// Recursively create tree objects for directories
function createTree(dirPath) {
const entries = fs.readdirSync(dirPath).filter(e => e !== '.git');
// console.log(entries)
let treeEntries = [];
entries.forEach(entry => {
const fullPath = path.join(dirPath, entry);
const stat = fs.statSync(fullPath);
// console.log(`${fullPath} - ${stat.isFile()}`)
let mode, sha;
if (stat.isFile()) {
mode = '100644'; // Regular file mode
sha = createBlob(fullPath);
} else if (stat.isDirectory()) {
mode = '040000'; // Directory mode
sha = createTree(fullPath); // Recursive call for subdirectories
}
const buff = Buffer.from(sha, 'hex')
const entryData = `${mode} ${entry}\0${buff}`;
treeEntries.push(Buffer.from(entryData));
});
// Sort tree entries alphabetically by name
treeEntries.sort((a, b) => a.toString().localeCompare(b.toString()));
// Create tree object
const treeHeader = `tree ${treeEntries.length}\0`;
const treeData = Buffer.from(`${treeHeader}${[...treeEntries]}`);
// console.log(treeData)
const treeSha = computeSha1(treeData);
const compressedTree = zlib.deflateSync(treeData);
writeObject(treeSha, compressedTree);
return treeSha;
}
// Main function for the write-tree command
function writeTree() {
const treeSha = createTree(process.cwd());
console.log(treeSha); // Print the tree SHA-1 hash
}
module.exports = writeTree;