Error on step4, writing tree object

I’m stuck on Stage #(WRITE A TREE OBJECT, ex. #FE4).

I’ve tried … (mention what you’ve tried so far).
setting debug to true,
tried different logic

Here are my logs:

 Running tests for Stage #FE4 (Write a tree object)
remote: [tester::#FE4] $ ./your_program.sh init
remote: [your_program] Logs from your program will appear here!
remote: [your_program] Initialized git directory
remote: [tester::#FE4] Creating some files & directories
remote: [tester::#FE4] $ ./your_program.sh write-tree
remote: [your_program] Logs from your program will appear here!
remote: [your_program] cc7d00e3acfaf6f13efc1a104da753b2f4967664
remote: [tester::#FE4] Reading file at .git/objects/cc/7d00e3acfaf6f13efc1a104da753b2f4967664
remote: [tester::#FE4] Found git object file written at .git/objects/cc/7d00e3acfaf6f13efc1a104da753b2f4967664.
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 39 35 00 31 30 30 36 34 34 20 64 6f 6f 00 cc | tree 95.100644 doo..
remote: [tester::#FE4] 05 24 11 35 51 c0 55 66 34 55 66 fb db 83 4b 94 b3 93 31 34 | .$.5Q.Uf4Uf...K...14
remote: [tester::#FE4] 30 30 30 30 20 64 6f 6f 62 79 00 9d dd 0b 8b 28 92 72 24 05 | 0000 dooby.....(.r$.
remote: [tester::#FE4] 23 42 ab a9 59 62 39 ea db 0e 95 34 30 30 30 30 20 79 69 6b | #B..Yb9....40000 yik
remote: [tester::#FE4] 65 73 00 f3 cf 74 cf 6a b1 cf ac 66 20 18 61 17 45 78 f9 90 | es...t.j...f .a.Ex..
remote: [tester::#FE4]
remote: [tester::#FE4] Actual (bytes 0-100), hexadecimal:                          | ASCII:
remote: [tester::#FE4] 74 72 65 65 20 31 32 36 00 34 30 30 30 30 20 2e 67 69 74 00 | tree 126.40000 .git.
remote: [tester::#FE4] 52 e7 24 10 73 0c cf 5d 9a 0b f4 71 df f8 b6 d6 dc 91 ae ce | R.$.s..]...q........
remote: [tester::#FE4] 31 30 30 36 34 34 20 64 6f 6f 00 cc 05 24 11 35 51 c0 55 66 | 100644 doo...$.5Q.Uf
remote: [tester::#FE4] 34 55 66 fb db 83 4b 94 b3 93 31 34 30 30 30 30 20 64 6f 6f | 4Uf...K...140000 doo
remote: [tester::#FE4] 62 79 00 9d dd 0b 8b 28 92 72 24 05 23 42 ab a9 59 62 39 ea | by.....(.r$.#B..Yb9.
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 path = require("path");
const zlib = require("zlib");
const crypto = require("crypto");

// You can use print statements as follows for debugging, they'll be visible when running tests.
console.error("Logs from your program will appear here!");

// Uncomment this block to pass the first stage
const command = process.argv[2];

switch (command) {
    case "init":
        createGitDirectory();
        break;
    case "cat-file":
        const hash = process.argv[4];
        readBlobObject(hash)
        break;
    case "hash-object":
        const object = process.argv[4]
        hashObject(object);
        break;
    case "ls-tree":
        lsTree();
        break;
    case "write-tree":
        const directory = process.cwd();
        const hash40 = writeTree(directory);
        console.log(hash40);
        break;
    default:
        throw new Error(`Unknown command ${command}`);
}

function createGitDirectory() {
  fs.mkdirSync(path.join(process.cwd(), ".git"), { recursive: true });
  fs.mkdirSync(path.join(process.cwd(), ".git", "objects"), { recursive: true });
  fs.mkdirSync(path.join(process.cwd(), ".git", "refs"), { recursive: true });

  fs.writeFileSync(path.join(process.cwd(), ".git", "HEAD"), "ref: refs/heads/main\n");
  console.log("Initialized git directory");
}

function readBlobObject(hash){
    const content = fs.readFileSync(path.join(process.cwd(), ".git", "objects", hash.slice(0,2), hash.slice(2)));
    const dataUnzipped = zlib.inflateSync(content);
    const res = dataUnzipped.toString().split('\0')[1];
    process.stdout.write(res);
}

function hashObject(object){
    const writeCommand = process.argv[3];
	if (writeCommand !== "-w") return;
    const content = fs.readFileSync(object);
    const header = `blob ${content.length}\0`;
    const data = header + content;
    const hash = crypto.createHash("sha1").update(data).digest("hex");
    const objectsDirPath = path.join(process.cwd(), ".git", "objects");
	const hashDirPath = path.join(objectsDirPath, hash.slice(0, 2));
	const filePath = path.join(hashDirPath, hash.slice(2));
	fs.mkdirSync(hashDirPath, { recursive: true });
	fs.writeFileSync(filePath, zlib.deflateSync(data));
	process.stdout.write(hash);
}

function lsTree(){
    let hash = '';
    if(process.argv[3] === "--name-only"){
        hash = process.argv[4];
        const filePath = path.join(process.cwd(), ".git", "objects", hash.slice(0,2), hash.slice(2));
        const compressedData = fs.readFileSync(filePath);
        const decompressedData = zlib.inflateSync(compressedData);
        const entries = decompressedData.toString("utf-8").split('\0');
        const data = entries.slice(1);
        const directoryNames = data.filter((line) => line.includes(" "))
        .map((line) => line.split(" ")[1])
        .filter((names) => names.indexOf("/") === -1);
        const response = directoryNames.join('\n');
        console.log(response);
    }else {
        hash = process.argv[3];
        const filePath = path.join(process.cwd(), ".git", "objects", hash.slice(0,2), hash.slice(2));
        const compressedData = fs.readFileSync(filePath);
        const decompressedData = zlib.inflateSync(compressedData);
        const entries = decompressedData.toString("utf-8").split('\0');
        const data = entries.slice(1);
        const directoryNames = data.filter((line) => line.includes(" "));
        console.log(directoryNames);
    }
}

function writeTree(directory){
    const entries = fs.readdirSync(directory);
    const treeEntries = [];
    
    entries.forEach(entry => {
        const fullPath = path.join(directory, entry);
        const stats = fs.statSync(fullPath);
        
        if(stats.isFile()){
            const blobHash = createBlob(fullPath);
            treeEntries.push({type: 'blob', name: entry, hash: blobHash});
        }else if(stats.isDirectory()){
            const subTreeHash = writeTree(fullPath);
            treeEntries.push({type: 'tree', name: entry, hash: subTreeHash});
        }
    })
    const treeHash = createTreeObject(treeEntries);
    return treeHash;
    
}

function createTreeObject(treeEntries){
    const treeData = treeEntries.map(entry => {
        const type = entry.type === "blob"? "100644" : "40000";
        const name = entry.name;
        const hashBinary = Buffer.from(entry.hash, "hex"); // Binary SHA1
        const entryHeader = `${type} ${name}\0`; // File mode, name, and null terminator
        return Buffer.concat([Buffer.from(entryHeader), hashBinary]); 
        // return `${type} ${name}\0${hashBinary}`;
    });

    const data = Buffer.concat(treeData.map(line => Buffer.from(line)));
    const header = `tree ${data.length}\0`;
    const treeBuffer = Buffer.concat([Buffer.from(header), data]);

    const hash = crypto.createHash("sha1").update(treeBuffer).digest("hex");
    writeObject(hash, treeBuffer);
    return hash;
}

// Function to write an object to .git/objects
function writeObject(hash, data) {
    const objectsDir = path.join(process.cwd(), ".git", "objects");
    const objectDir = path.join(objectsDir, hash.slice(0, 2));
    const objectFile = path.join(objectDir, hash.slice(2));

    fs.mkdirSync(objectDir, { recursive: true });
    fs.writeFileSync(objectFile, zlib.deflateSync(data));
}


// Function to create a blob object and write to .git/objects
function createBlob(filePath) {
    const content = fs.readFileSync(filePath);
    const header = `blob ${content.length}\0`;
    const data = Buffer.concat([Buffer.from(header), content]);

    const hash = crypto.createHash("sha1").update(data).digest("hex");
    writeObject(hash, data);
    return hash;
}`
`

Hi @SREERAJ089, could you upload your code to GitHub and share the link? It will be much easier to debug if I can run it directly.

The link to my GitHub is provided below:

SREERAJ089/Git

Thanks for sharing your code! I’ll take a look and get back to you by the end of the week.

Any updates?

Hi @SREERAJ089, the issue is that you code is not filtering out the .git directory,

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