Stuck at challenge git step 5

I’m stuck on Stage #(FE4)

I’ve tried multiple solutions from the solved examples but I am not able to pass.

Here are my logs:

[tester::#FE4] Running tests for Stage #FE4 (Write a tree object)
remote: [tester::#FE4] $ ./your_git.sh init
remote: [your_program] Initialized git directory
remote: [tester::#FE4] Creating some files & directories
remote: [tester::#FE4] $ ./your_git.sh write-tree
remote: [your_program] 801923b6ac7e55825b73e85ecbeaf26da256505d65496b5b730f2784a1129f210c65eddf53e94c55ca40a0d504bd1b82f45d397fad62dab9563190570bf21250eee4dce73d38daa7b534ae98c9d5056d7f192d74684a2148b7a639b7e1516a244df951a6
remote: [tester::#FE4] Expected a 40-char SHA as output. Got: 801923b6ac7e55825b73e85ecbeaf26da256505d65496b5b730f2784a1129f210c65eddf53e94c55ca40a0d504bd1b82f45d397fad62dab9563190570bf21250eee4dce73d38daa7b534ae98c9d5056d7f192d74684a2148b7a639b7e1516a244df951a6

And here’s a snippet of my code:

const fs = require("fs");
const path = require("path");
const zlib = require("zlib")
const crypto = require("crypto")


 const command = process.argv[2];

 switch (command) {
   case "init":
     createGitDirectory();
     break;
   case "cat-file":
     readBlobObject(process.argv[4]);
     break;
   case "hash-object":
     writeBlobObject(process.argv[4]);
     break;
   case "ls-tree":
     listTreeContent(process.argv[4]);
     break;
   case "write-tree":
      process.stdout.write(writeTreeObject(process.cwd()).toString('hex'));
      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(blobHash) {
    const filePath = sliceHash(blobHash)
    const compressedData = (fs.readFileSync(`.git/objects/${filePath}`)); 
    const decompressedData = decompressData(compressedData);
    const blobContent = extractContent(decompressedData);

    process.stdout.write(blobContent)
 }

 
 function sliceHash(Hash){
    return Hash.slice(0,2) + '/' + Hash.slice(2);
 }

 function decompressData(compressedData){
    return zlib.inflateSync(compressedData);
 }

 function extractContent(decompressedData){
    return decompressedData.toString().split('\0')[1];
 }

 function writeBlobObject(file){
    const fileActualContent = fs.readFileSync(file);
    const fileContent = `blob ${fileActualContent.length}\0${fileActualContent}`;
    const blobHash = createShaHash(fileContent)
    const filePath = sliceHash(blobHash)
    const compressedData = zlib.deflateSync(fileContent);
    createObject(filePath,compressedData);
    process.stdout.write(blobHash)
    const sha = createShaBinary(fileContent);
    return sha;

 }

 function createObject(objectSubPath,compressedData){
    fs.mkdirSync(`.git/objects/${objectSubPath.split('/')[0]}`, { recursive : true})
    fs.writeFileSync(`.git/objects/${objectSubPath}`,compressedData);
 }

 function createShaHash(data){
    const shaHash =  crypto.createHash('sha1');
    shaHash.update(data);
    return shaHash.digest('hex');
 }

 function createShaBinary(data){
    const shaHash =  crypto.createHash('sha1');
    shaHash.update(data);
    return shaHash.digest();
 }

 

 function listTreeContent(shaHash){
    const filePath = sliceHash(shaHash);
    const fileContent = decompressData(fs.readFileSync(`.git/objects/${filePath}`));
    const tree = fileContent.toString().split("\0").slice(1);
    const fileNames = [];
    for(let i = 0; i < tree.length; i++){
        fileNames.push(tree[i].split(' ')[1]);
    }
    process.stdout.write(fileNames.join("\n"));
 }

 function parseTree(dir){
   return fs.readdirSync(dir)
   .filter((file) => file !== ".git")
   .map((file) => {
      const fullPath = path.join(dir,file);
      if(fs.lstatSync(fullPath).isDirectory()){
         return {
            mode: 40000,
            name: file,
            hash: writeTreeObject(fullPath).toString('binary'),
         };
      } 
      return {
            mode: 100644,
            name: file,
            hash: writeBlobObject(fullPath).toString('binary'),
         };
      
   });
 }

  function writeTreeObject(dirPath) { 
    const tree =   parseTree(dirPath); 
    const treeContent =  tree.reduce((acc,{mode, name, hash})=>
      Buffer.concat([
         acc,
         Buffer.from(`${mode} ${name}\0`),
         Buffer.from(hash , 'binary'),
      ])
    ,Buffer.alloc(0));

    const treeObject = Buffer.concat([
      Buffer.from(`tree ${treeContent.length}\0`),
      treeContent
    ]);
    const treeHash = createShaHash(treeObject);
    const compressedData = zlib.deflateSync(treeObject);
    const subDirectory = treeHash.slice(0,2);
    const fileName = treeHash.slice(2);
    const sha = createShaBinary(treeObject);
    if(!fs.existsSync(path.resolve(".git", "objects",subDirectory))){
      fs.mkdirSync(path.resolve(".git", "objects",subDirectory));
    }
    fs.writeFileSync(path.resolve(".git", "objects",subDirectory,fileName), compressedData);
    return sha;
 }

Could you try using shaHash.digest('hex') instead? (and remove the .toString('hex') from the top of the file)

I think the reason you’re seeing more than 40 chars is that shaHash.digest() returns a buffer of bytes by default (which is a “long” string), and converting that the hex is what results in a hexadecimal string that’s extremely long.

1 Like

I have tried multiple solutions like you said I have used the shaHash.digest('hex') first and then tried to convert it to binary using toString('binary') to store hashes in binary format and also tried returning only sha in the createShaBinary method and then converting using .digest('binary') while storing hashes and used .digest('hex') while producing the output and storing objects. Also tried keeping it as hex without converting to binary. Still I am not getting a 40 char sha, please help I am just stuck at this stage.

remote: [tester::#FE4] Running tests for Stage #FE4 (Write a tree object)
remote: [tester::#FE4] $ ./your_git.sh init
remote: [your_program] Initialized git directory
remote: [tester::#FE4] Creating some files & directories
remote: [tester::#FE4] $ ./your_git.sh write-tree
remote: [your_program] ef69c0a874e5df0bde8fd5ad93b37e2b8b0affb70596acea65c19abd0dab4994746aa2b834c2cf6833b2ffaaa1caeb3bf0032a6374a80420dacc232426eb0004463fb35c7e44799f470bce7e2ffdb1e420782b4cd1dadd3a9cd2dde779fa60dc1dcaba67
remote: [tester::#FE4] Expected a 40-char SHA as output. Got: ef69c0a874e5df0bde8fd5ad93b37e2b8b0affb70596acea65c19abd0dab4994746aa2b834c2cf6833b2ffaaa1caeb3bf0032a6374a80420dacc232426eb0004463fb35c7e44799f470bce7e2ffdb1e420782b4cd1dadd3a9cd2dde779fa60dc1dcaba67
remote: [tester::#FE4] Test failed
remote:

Hey really thanks for the help looks like the issue I was printing the blob hash in writeBlobObject function which resulted in the extra characters.

1 Like

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