{
    "mode": "man",
    "parameter": "GITFORMAT-PACK",
    "section": "5",
    "url": "https://www.chedong.com/phpMan.php/man/GITFORMAT-PACK/5/json",
    "generated": "2026-11-08T13:43:15Z",
    "synopsis": "$GITDIR/objects/pack/pack-.{pack,idx}\n$GITDIR/objects/pack/pack-.rev\n$GITDIR/objects/pack/pack-*.mtimes\n$GITDIR/objects/pack/multi-pack-index",
    "sections": {
        "NAME": {
            "content": "gitformat-pack - Git pack format\n",
            "subsections": []
        },
        "SYNOPSIS": {
            "content": "$GITDIR/objects/pack/pack-.{pack,idx}\n$GITDIR/objects/pack/pack-.rev\n$GITDIR/objects/pack/pack-*.mtimes\n$GITDIR/objects/pack/multi-pack-index\n\n",
            "subsections": []
        },
        "DESCRIPTION": {
            "content": "The Git pack format is how Git stores most of its primary repository data. Over the lifetime\nof a repository, loose objects (if any) and smaller packs are consolidated into larger\npack(s). See git-gc(1) and git-pack-objects(1).\n\nThe pack format is also used over-the-wire, see e.g. gitprotocol-v2(5), as well as being a\npart of other container formats in the case of gitformat-bundle(5).\n",
            "subsections": []
        },
        "CHECKSUMS AND OBJECT IDS": {
            "content": "In a repository using the traditional SHA-1, pack checksums, index checksums, and object IDs\n(object names) mentioned below are all computed using SHA-1. Similarly, in SHA-256\nrepositories, these values are computed using SHA-256.\n\nPACK-*.PACK FILES HAVE THE FOLLOWING FORMAT:\n•   A header appears at the beginning and consists of the following:\n\n4-byte signature:\nThe signature is: {'P', 'A', 'C', 'K'}\n\n4-byte version number (network byte order):\nGit currently accepts version number 2 or 3 but\ngenerates version 2 only.\n\n4-byte number of objects contained in the pack (network byte order)\n\nObservation: we cannot have more than 4G versions ;-) and\nmore than 4G objects in a pack.\n\n•   The header is followed by a number of object entries, each of which looks like this:\n\n(undeltified representation)\nn-byte type and length (3-bit type, (n-1)*7+4-bit length)\ncompressed data\n\n(deltified representation)\nn-byte type and length (3-bit type, (n-1)*7+4-bit length)\nbase object name if OBJREFDELTA or a negative relative\noffset from the delta object's position in the pack if this\nis an OBJOFSDELTA object\ncompressed delta data\n\nObservation: the length of each object is encoded in a variable\nlength format and is not constrained to 32-bit or anything.\n\n•   The trailer records a pack checksum of all of the above.\n",
            "subsections": [
                {
                    "name": "Object types",
                    "content": "Valid object types are:\n\n•   OBJCOMMIT (1)\n\n•   OBJTREE (2)\n\n•   OBJBLOB (3)\n\n•   OBJTAG (4)\n\n•   OBJOFSDELTA (6)\n\n•   OBJREFDELTA (7)\n\nType 5 is reserved for future expansion. Type 0 is invalid.\n"
                },
                {
                    "name": "Size encoding",
                    "content": "This document uses the following \"size encoding\" of non-negative integers: From each byte,\nthe seven least significant bits are used to form the resulting integer. As long as the most\nsignificant bit is 1, this process continues; the byte with MSB 0 provides the last seven\nbits. The seven-bit chunks are concatenated. Later values are more significant.\n\nThis size encoding should not be confused with the \"offset encoding\", which is also used in\nthis document.\n"
                },
                {
                    "name": "Deltified representation",
                    "content": "Conceptually there are only four object types: commit, tree, tag and blob. However to save\nspace, an object could be stored as a \"delta\" of another \"base\" object. These representations\nare assigned new types ofs-delta and ref-delta, which is only valid in a pack file.\n\nBoth ofs-delta and ref-delta store the \"delta\" to be applied to another object (called base\nobject) to reconstruct the object. The difference between them is, ref-delta directly encodes\nbase object name. If the base object is in the same pack, ofs-delta encodes the offset of the\nbase object in the pack instead.\n\nThe base object could also be deltified if it’s in the same pack. Ref-delta can also refer to\nan object outside the pack (i.e. the so-called \"thin pack\"). When stored on disk however, the\npack should be self contained to avoid cyclic dependency.\n\nThe delta data starts with the size of the base object and the size of the object to be\nreconstructed. These sizes are encoded using the size encoding from above. The remainder of\nthe delta data is a sequence of instructions to reconstruct the object from the base object.\nIf the base object is deltified, it must be converted to canonical form first. Each\ninstruction appends more and more data to the target object until it’s complete. There are\ntwo supported instructions so far: one for copying a byte range from the source object and\none for inserting new data embedded in the instruction itself.\n\nEach instruction has variable length. Instruction type is determined by the seventh bit of\nthe first octet. The following diagrams follow the convention in RFC 1951 (Deflate compressed\ndata format).\n"
                },
                {
                    "name": "Instruction to copy from base object",
                    "content": "+----------+---------+---------+---------+---------+-------+-------+-------+\n| 1xxxxxxx | offset1 | offset2 | offset3 | offset4 | size1 | size2 | size3 |\n+----------+---------+---------+---------+---------+-------+-------+-------+\n\nThis is the instruction format to copy a byte range from the source object. It encodes\nthe offset to copy from and the number of bytes to copy. Offset and size are in\nlittle-endian order.\n\nAll offset and size bytes are optional. This is to reduce the instruction size when\nencoding small offsets or sizes. The first seven bits in the first octet determine which\nof the next seven octets is present. If bit zero is set, offset1 is present. If bit one\nis set offset2 is present and so on.\n\nNote that a more compact instruction does not change offset and size encoding. For\nexample, if only offset2 is omitted like below, offset3 still contains bits 16-23. It\ndoes not become offset2 and contains bits 8-15 even if it’s right next to offset1.\n\n+----------+---------+---------+\n| 10000101 | offset1 | offset3 |\n+----------+---------+---------+\n\nIn its most compact form, this instruction only takes up one byte (0x80) with both offset\nand size omitted, which will have default values zero. There is another exception: size\nzero is automatically converted to 0x10000.\n"
                },
                {
                    "name": "Instruction to add new data",
                    "content": "+----------+============+\n| 0xxxxxxx |    data    |\n+----------+============+\n\nThis is the instruction to construct the target object without the base object. The\nfollowing data is appended to the target object. The first seven bits of the first octet\ndetermine the size of data in bytes. The size must be non-zero.\n"
                },
                {
                    "name": "Reserved instruction",
                    "content": "+----------+============\n| 00000000 |\n+----------+============\n\nThis is the instruction reserved for future expansion.\n\nORIGINAL (VERSION 1) PACK-*.IDX FILES HAVE THE FOLLOWING FORMAT:\n•   The header consists of 256 4-byte network byte order integers. N-th entry of this table\nrecords the number of objects in the corresponding pack, the first byte of whose object\nname is less than or equal to N. This is called the first-level fan-out table.\n\n•   The header is followed by sorted 24-byte entries, one entry per object in the pack. Each\nentry is:\n\n4-byte network byte order integer, recording where the\nobject is stored in the packfile as the offset from the\nbeginning.\n\none object name of the appropriate size.\n\n•   The file is concluded with a trailer:\n\nA copy of the pack checksum at the end of the corresponding\npackfile.\n\nIndex checksum of all of the above.\n\nPack Idx file:\n\n--  +--------------------------------+\nfanout      | fanout[0] = 2 (for example)    |-.\ntable       +--------------------------------+ |\n| fanout[1]                      | |\n+--------------------------------+ |\n| fanout[2]                      | |\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |\n| fanout[255] = total objects    |---.\n--  +--------------------------------+ | |\nmain        | offset                         | | |\nindex       | object name 00XXXXXXXXXXXXXXXX | | |\ntable       +--------------------------------+ | |\n| offset                         | | |\n| object name 00XXXXXXXXXXXXXXXX | | |\n+--------------------------------+<+ |\n.-| offset                         |   |\n| | object name 01XXXXXXXXXXXXXXXX |   |\n| +--------------------------------+   |\n| | offset                         |   |\n| | object name 01XXXXXXXXXXXXXXXX |   |\n| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   |\n| | offset                         |   |\n| | object name FFXXXXXXXXXXXXXXXX |   |\n--| +--------------------------------+<--+\ntrailer   | | packfile checksum              |\n| +--------------------------------+\n| | idxfile checksum               |\n| +--------------------------------+\n.-------.\n|\nPack file entry: <+\n\npacked object header:\n1-byte size extension bit (MSB)\ntype (next 3 bit)\nsize0 (lower 4-bit)\nn-byte sizeN (as long as MSB is set, each 7-bit)\nsize0..sizeN form 4+7+7+..+7 bit integer, size0\nis the least significant part, and sizeN is the\nmost significant part.\npacked object data:\nIf it is not DELTA, then deflated bytes (the size above\nis the size before compression).\nIf it is REFDELTA, then\nbase object name (the size above is the\nsize of the delta data that follows).\ndelta data, deflated.\nIf it is OFSDELTA, then\nn-byte offset (see below) interpreted as a negative\noffset from the type-byte of the header of the\nofs-delta entry (the size above is the size of\nthe delta data that follows).\ndelta data, deflated.\n\noffset encoding:\nn bytes with MSB set in all but the last one.\nThe offset is then the number constructed by\nconcatenating the lower 7 bit of each byte, and\nfor n >= 2 adding 2^7 + 2^14 + ... + 2^(7*(n-1))\nto the result.\n\nVERSION 2 PACK-*.IDX FILES SUPPORT PACKS LARGER THAN 4 GIB, AND\nhave some other reorganizations.  They have the format:\n\n•   A 4-byte magic number \\377tOc which is an unreasonable fanout[0] value.\n\n•   A 4-byte version number (= 2)\n\n•   A 256-entry fan-out table just like v1.\n\n•   A table of sorted object names. These are packed together without offset values to reduce\nthe cache footprint of the binary search for a specific object name.\n\n•   A table of 4-byte CRC32 values of the packed object data. This is new in v2 so compressed\ndata can be copied directly from pack to pack during repacking without undetected data\ncorruption.\n\n•   A table of 4-byte offset values (in network byte order). These are usually 31-bit pack\nfile offsets, but large offsets are encoded as an index into the next table with the\nmsbit set.\n\n•   A table of 8-byte offset entries (empty for pack files less than 2 GiB). Pack files are\norganized with heavily used objects toward the front, so most object references should\nnot need to refer to this table.\n\n•   The same trailer as a v1 pack file:\n\nA copy of the pack checksum at the end of the\ncorresponding packfile.\n\nIndex checksum of all of the above.\n\nPACK-*.REV FILES HAVE THE FORMAT:\n•   A 4-byte magic number 0x52494458 (RIDX).\n\n•   A 4-byte version identifier (= 1).\n\n•   A 4-byte hash function identifier (= 1 for SHA-1, 2 for SHA-256).\n\n•   A table of index positions (one per packed object, numobjects in total, each a 4-byte\nunsigned integer in network order), sorted by their corresponding offsets in the\npackfile.\n\n•   A trailer, containing a:\n\nchecksum of the corresponding packfile, and\n\na checksum of all of the above.\n\nAll 4-byte numbers are in network order.\n\nPACK-*.MTIMES FILES HAVE THE FORMAT:\nAll 4-byte numbers are in network byte order.\n\n•   A 4-byte magic number 0x4d544d45 (MTME).\n\n•   A 4-byte version identifier (= 1).\n\n•   A 4-byte hash function identifier (= 1 for SHA-1, 2 for SHA-256).\n\n•   A table of 4-byte unsigned integers. The ith value is the modification time (mtime) of\nthe ith object in the corresponding pack by lexicographic (index) order. The mtimes count\nstandard epoch seconds.\n\n•   A trailer, containing a checksum of the corresponding packfile, and a checksum of all of\nthe above (each having length according to the specified hash function).\n\nMULTI-PACK-INDEX (MIDX) FILES HAVE THE FOLLOWING FORMAT:\nThe multi-pack-index files refer to multiple pack-files and loose objects.\n\nIn order to allow extensions that add extra data to the MIDX, we organize the body into\n\"chunks\" and provide a lookup table at the beginning of the body. The header includes certain\nlength values, such as the number of packs, the number of base MIDX files, hash lengths and\ntypes.\n\nAll 4-byte numbers are in network order.\n\nHEADER:\n\n4-byte signature:\nThe signature is: {'M', 'I', 'D', 'X'}\n\n1-byte version number:\nGit only writes or recognizes version 1.\n\n1-byte Object Id Version\nWe infer the length of object IDs (OIDs) from this value:\n1 => SHA-1\n2 => SHA-256\nIf the hash type does not match the repository's hash algorithm,\nthe multi-pack-index file should be ignored with a warning\npresented to the user.\n\n1-byte number of \"chunks\"\n\n1-byte number of base multi-pack-index files:\nThis value is currently always zero.\n\n4-byte number of pack files\n\nCHUNK LOOKUP:\n\n(C + 1) * 12 bytes providing the chunk offsets:\nFirst 4 bytes describe chunk id. Value 0 is a terminating label.\nOther 8 bytes provide offset in current file for chunk to start.\n(Chunks are provided in file-order, so you can infer the length\nusing the next chunk position if necessary.)\n\nThe CHUNK LOOKUP matches the table of contents from\nthe chunk-based file format, see linkgit:gitformat-chunk[5].\n\nThe remaining data in the body is described one chunk at a time, and\nthese chunks may be given in any order. Chunks are required unless\notherwise specified.\n\nCHUNK DATA:\n\nPackfile Names (ID: {'P', 'N', 'A', 'M'})\nStore the names of packfiles as a sequence of NUL-terminated\nstrings. There is no extra padding between the filenames,\nand they are listed in lexicographic order. The chunk itself\nis padded at the end with between 0 and 3 NUL bytes to make the\nchunk size a multiple of 4 bytes.\n\nOID Fanout (ID: {'O', 'I', 'D', 'F'})\nThe ith entry, F[i], stores the number of OIDs with first\nbyte at most i. Thus F[255] stores the total\nnumber of objects.\n\nOID Lookup (ID: {'O', 'I', 'D', 'L'})\nThe OIDs for all objects in the MIDX are stored in lexicographic\norder in this chunk.\n\nObject Offsets (ID: {'O', 'O', 'F', 'F'})\nStores two 4-byte values for every object.\n1: The pack-int-id for the pack storing this object.\n2: The offset within the pack.\nIf all offsets are less than 2^32, then the large offset chunk\nwill not exist and offsets are stored as in IDX v1.\nIf there is at least one offset value larger than 2^32-1, then\nthe large offset chunk must exist, and offsets larger than\n2^31-1 must be stored in it instead. If the large offset chunk\nexists and the 31st bit is on, then removing that bit reveals\nthe row in the large offsets containing the 8-byte offset of\nthis object.\n\n[Optional] Object Large Offsets (ID: {'L', 'O', 'F', 'F'})\n8-byte offsets into large packfiles.\n\n[Optional] Bitmap pack order (ID: {'R', 'I', 'D', 'X'})\nA list of MIDX positions (one per object in the MIDX, numobjects in\ntotal, each a 4-byte unsigned integer in network byte order), sorted\naccording to their relative bitmap/pseudo-pack positions.\n\nTRAILER:\n\nIndex checksum of the above contents.\n"
                }
            ]
        },
        "MULTI-PACK-INDEX REVERSE INDEXES": {
            "content": "Similar to the pack-based reverse index, the multi-pack index can also be used to generate a\nreverse index.\n\nInstead of mapping between offset, pack-, and index position, this reverse index maps between\nan object’s position within the MIDX, and that object’s position within a pseudo-pack that\nthe MIDX describes (i.e., the ith entry of the multi-pack reverse index holds the MIDX\nposition of ith object in pseudo-pack order).\n\nTo clarify the difference between these orderings, consider a multi-pack reachability bitmap\n(which does not yet exist, but is what we are building towards here). Each bit needs to\ncorrespond to an object in the MIDX, and so we need an efficient mapping from bit position to\nMIDX position.\n\nOne solution is to let bits occupy the same position in the oid-sorted index stored by the\nMIDX. But because oids are effectively random, their resulting reachability bitmaps would\nhave no locality, and thus compress poorly. (This is the reason that single-pack bitmaps use\nthe pack ordering, and not the .idx ordering, for the same purpose.)\n\nSo we’d like to define an ordering for the whole MIDX based around pack ordering, which has\nfar better locality (and thus compresses more efficiently). We can think of a pseudo-pack\ncreated by the concatenation of all of the packs in the MIDX. E.g., if we had a MIDX with\nthree packs (a, b, c), with 10, 15, and 20 objects respectively, we can imagine an ordering\nof the objects like:\n\n|a,0|a,1|...|a,9|b,0|b,1|...|b,14|c,0|c,1|...|c,19|\n\nwhere the ordering of the packs is defined by the MIDX’s pack list, and then the ordering of\nobjects within each pack is the same as the order in the actual packfile.\n\nGiven the list of packs and their counts of objects, you can naïvely reconstruct that\npseudo-pack ordering (e.g., the object at position 27 must be (c,1) because packs \"a\" and \"b\"\nconsumed 25 of the slots). But there’s a catch. Objects may be duplicated between packs, in\nwhich case the MIDX only stores one pointer to the object (and thus we’d want only one slot\nin the bitmap).\n\nCallers could handle duplicates themselves by reading objects in order of their bit-position,\nbut that’s linear in the number of objects, and much too expensive for ordinary bitmap\nlookups. Building a reverse index solves this, since it is the logical inverse of the index,\nand that index has already removed duplicates. But, building a reverse index on the fly can\nbe expensive. Since we already have an on-disk format for pack-based reverse indexes, let’s\nreuse it for the MIDX’s pseudo-pack, too.\n\nObjects from the MIDX are ordered as follows to string together the pseudo-pack. Let pack(o)\nreturn the pack from which o was selected by the MIDX, and define an ordering of packs based\non their numeric ID (as stored by the MIDX). Let offset(o) return the object offset of o\nwithin pack(o). Then, compare o1 and o2 as follows:\n\n•   If one of pack(o1) and pack(o2) is preferred and the other is not, then the preferred one\nsorts first.\n\n(This is a detail that allows the MIDX bitmap to determine which pack should be used by\nthe pack-reuse mechanism, since it can ask the MIDX for the pack containing the object at\nbit position 0).\n\n•   If pack(o1) ≠ pack(o2), then sort the two objects in descending order based on the pack\nID.\n\n•   Otherwise, pack(o1) = pack(o2), and the objects are sorted in pack-order (i.e., o1 sorts\nahead of o2 exactly when offset(o1) < offset(o2)).\n\nIn short, a MIDX’s pseudo-pack is the de-duplicated concatenation of objects in packs stored\nby the MIDX, laid out in pack order, and the packs arranged in MIDX order (with the preferred\npack coming first).\n\nThe MIDX’s reverse index is stored in the optional RIDX chunk within the MIDX itself.\n",
            "subsections": []
        },
        "CRUFT PACKS": {
            "content": "The cruft packs feature offer an alternative to Git’s traditional mechanism of removing\nunreachable objects. This document provides an overview of Git’s pruning mechanism, and how a\ncruft pack can be used instead to accomplish the same.\n",
            "subsections": [
                {
                    "name": "Background",
                    "content": "To remove unreachable objects from your repository, Git offers git repack -Ad (see git-\nrepack(1)). Quoting from the documentation:\n\n[...] unreachable objects in a previous pack become loose, unpacked objects,\ninstead of being left in the old pack. [...] loose unreachable objects will be\npruned according to normal expiry rules with the next 'git gc' invocation.\n\n\nUnreachable objects aren’t removed immediately, since doing so could race with an incoming\npush which may reference an object which is about to be deleted. Instead, those unreachable\nobjects are stored as loose objects and stay that way until they are older than the\nexpiration window, at which point they are removed by git-prune(1).\n\nGit must store these unreachable objects loose in order to keep track of their per-object\nmtimes. If these unreachable objects were written into one big pack, then either freshening\nthat pack (because an object contained within it was re-written) or creating a new pack of\nunreachable objects would cause the pack’s mtime to get updated, and the objects within it\nwould never leave the expiration window. Instead, objects are stored loose in order to keep\ntrack of the individual object mtimes and avoid a situation where all cruft objects are\nfreshened at once.\n\nThis can lead to undesirable situations when a repository contains many unreachable objects\nwhich have not yet left the grace period. Having large directories in the shards of\n.git/objects can lead to decreased performance in the repository. But given enough\nunreachable objects, this can lead to inode starvation and degrade the performance of the\nwhole system. Since we can never pack those objects, these repositories often take up a large\namount of disk space, since we can only zlib compress them, but not store them in delta\nchains.\n"
                },
                {
                    "name": "Cruft packs",
                    "content": "A cruft pack eliminates the need for storing unreachable objects in a loose state by\nincluding the per-object mtimes in a separate file alongside a single pack containing all\nloose objects.\n\nA cruft pack is written by git repack --cruft when generating a new pack. git-pack-\nobjects(1)'s --cruft option. Note that git repack --cruft is a classic all-into-one repack,\nmeaning that everything in the resulting pack is reachable, and everything else is\nunreachable. Once written, the --cruft option instructs git repack to generate another pack\ncontaining only objects not packed in the previous step (which equates to packing all\nunreachable objects together). This progresses as follows:\n\n1. Enumerate every object, marking any object which is (a) not contained in a kept-pack, and\n(b) whose mtime is within the grace period as a traversal tip.\n\n2. Perform a reachability traversal based on the tips gathered in the previous step, adding\nevery object along the way to the pack.\n\n3. Write the pack out, along with a .mtimes file that records the per-object timestamps.\n\nThis mode is invoked internally by git-repack(1) when instructed to write a cruft pack.\nCrucially, the set of in-core kept packs is exactly the set of packs which will not be\ndeleted by the repack; in other words, they contain all of the repository’s reachable\nobjects.\n\nWhen a repository already has a cruft pack, git repack --cruft typically only adds objects to\nit. An exception to this is when git repack is given the --cruft-expiration option, which\nallows the generated cruft pack to omit expired objects instead of waiting for git-gc(1) to\nexpire those objects later on.\n\nIt is git-gc(1) that is typically responsible for removing expired unreachable objects.\n"
                },
                {
                    "name": "Alternatives",
                    "content": "Notable alternatives to this design include:\n\n•   The location of the per-object mtime data.\n\nOn the location of mtime data, a new auxiliary file tied to the pack was chosen to avoid\ncomplicating the .idx format. If the .idx format were ever to gain support for optional\nchunks of data, it may make sense to consolidate the .mtimes format into the .idx itself.\n"
                }
            ]
        },
        "GIT": {
            "content": "Part of the git(1) suite\n\nGit 2.43.0                                   07/02/2025                            GITFORMAT-PACK(5)",
            "subsections": []
        }
    },
    "summary": "gitformat-pack - Git pack format",
    "flags": [],
    "examples": [],
    "see_also": []
}