Skip to content
Packfile Header: Reading the Bytes
step 1/5

Reading — step 1 of 5

Read

~2 min readObject Storage

Packfile Header: Reading the Bytes

The previous (conceptual) lesson described what packfiles are. Now let's read one — at least the 12-byte header that announces what's inside.

A .pack file begins with:

+---------+---------+---------+---------+
|  'P' 'A' 'C' 'K' |    version (u32 BE)|
+---------+---------+---------+---------+
|         object count (u32 BE)         |
+---------+---------+---------+---------+
                 ... objects ...
                 ... 20-byte SHA footer ...

That's it. Twelve bytes. Magic + version + count. Everything else is the object stream (and the SHA-1 footer over the entire packfile).

Parsing in any language

python
use std::io::Read;
let mut buf = [0u8; 12];
file.read_exact(&mut buf)?;
assert_eq!(&buf[0..4], b"PACK");
let version = u32::from_be_bytes(buf[4..8].try_into()?);
let count   = u32::from_be_bytes(buf[8..12].try_into()?);

Versions

VersionYearWhat's new
12005Original; barely seen in the wild today
22006OFS_DELTA, the dominant format
32018SHA-256 support (experimental)

If you see version 1, you're reading a museum repo. Treat it as unsupported. Most production git uses v2 exclusively; v3 is opt-in via extensions.objectFormat.

Why big-endian?

Network byte order. Packfiles travel over the wire (git fetch / git push), so they use the same endianness as TCP/IP. Even on little-endian disks, the bytes match what comes off the network.

Validation matters

A corrupted pack header is the difference between "git fetch failed" and "git fetch silently produced garbage." The combination of:

  1. Magic bytes
  2. Version whitelist
  3. Length precondition (≥12 bytes for the header alone)
  4. SHA-1 footer over the full file

makes packs robust to truncation, byte-flips, and version skew. The footer is the most important — git always validates it before trusting any object inside the pack.

After the header

Each object in the body starts with a variable-length size + type header, then zlib-compressed (or delta-compressed) data. Parsing the body is substantially more work than the header. That's a great next project — but this lesson stops at byte 12.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…