6. Reading Pack File
At this point, we have all the necessary components to start reading the pack file. Parsing the OFS_DELTA
is not required to complete this stage,
so the only thing that we have to do now is putting all together.
But first, just a few points to remember:
-
Storing Pack-File Objects: All the objects included in the pack file must be written to the
.git/objects
folder. -
Updating the Working Directory: Only the objects directly referenced by the HEAD (such as the current branch) should be written to the working directory.
A basic implementation for handling the object headers might look like this:
Step 1: Reading the Pack File Header
The pack file begins with a header, which provides the total number of objects.
struct PackFileHeader {
uint32_t version; // Pack file version, usually 2 or 3
uint32_t numObjects; // Total objects in the pack file
};
PackFileHeader header = readPackFileHeader(&header);
Step 2: Processing Each Object
Iterate through the objects, parsing their headers and processing based on their type.
std::vector<uint8_t> packFile = getPackFile();
for (uint32_t i {}; i < header.numObjects; i++) {
ObjectHeader objHeader {};
readObjectHeader(&objHeader, packFile);
switch (objHeader.type) {
case COMMIT:
(void)processCommit(packFile);
break;
case TREE:
(void)processTree(packFile);
break;
case BLOB:
(void)processBlob(packFile);
break;
case REF_DELTA:
(void)processRefDelta(packFile);
break;
}
}
Step 3: Writing to the Objects Folder
Each processed object is stored in .git/objects
using its SHA-1 hash:
void writeObjectToDisk(const ObjectHeader& header, const std::string& objectData) {
std::string objectHash = calculateSHA1(objectData);
std::string objectPath = generateObjectPath(objectHash);
createDirectoriesIfNeeded(objectPath);
writeToFile(objectPath, objectData);
}
Step 4: Updating the Working Directory
For objects referenced by the HEAD, extract and write them to the appropriate locations in the working directory.
void updateWorkingDirectory(const ObjectHeader& header, const std::string& objectData) {
if (isReferencedByHead(header)) {
std::string filePath = getWorkingDirectoryPath(header);
writeToFile(filePath, objectData);
}
}
And that should be it!