Home / Alt manpages / git-pack-objects(1)

  • git-pack-objects(1)
  • User command
  • linux

Build and Verify Git Pack Files with git pack-objects

You will create a self-contained Git pack from the objects reachable in a repository, then verify that the resulting pack can be indexed. This is useful when you need the plumbing command behind a transport or archival workflow, rather than the higher-level behaviour of git repack or git bundle. Allow about fifteen minutes, plus the time needed to pack a large repository.

The examples were checked with Git 2.43.0 from Ubuntu package git 1:2.43.0-1ubuntu7.3. They use a temporary output directory and do not need root. Work in a repository whose objects you are allowed to read.

1. Check the installed command

Confirm which Git will run and record the version before relying on a detail in a script:

$ command -v git
/usr/bin/git
$ git --version
git version 2.43.0
$ git pack-objects -h | sed -n '1,8p'
usage: git pack-objects --stdout [<options>] [< <ref-list> | < <object-list>]
   or: git pack-objects [<options>] <base-name> [< <ref-list> | < <object-list>]

git pack-objects reads object names or revision arguments from standard input. With --stdout, it writes the pack data to standard output. With a base name, it creates indexed .pack and .idx files and prints the pack's object-name hash.

2. Check what will be packed

For a normal repository transfer, start with objects reachable from every reference. git rev-list --objects --all prints the object IDs and, where available, paths. Inspect the list before sending it into the packer:

$ git rev-list --objects --all | sed -n '1,12p'
3a1f... commit
9b2c... file.txt
7d4e... file.txt

The abbreviated IDs above are illustrative. Your output contains full object IDs and depends on the repository. An empty list means there are no reachable objects under the references that --all selected. Do not quietly replace it with an unrelated directory or assume that unreferenced objects are included.

Checkpoint: if you need a particular branch or tag rather than every reference, replace --all with an explicit revision such as refs/heads/main, and inspect the resulting list again. The revision walk chooses the input set; pack-objects then writes that set efficiently.

3. Write a pack to standard output

Use a new destination when producing a stream. The pack is binary, so redirect it to a file rather than viewing it in a terminal:

$ git rev-list --objects --all \
    | git pack-objects --stdout > /tmp/repository.pack
pack 7d29f3bc5f8ade1de2284ae71add4fc957a69f02

The pack data and diagnostic output are separate streams. In this installed Git, the pack hash is printed on standard error while the binary pack uses standard output. If you need a clean log in a script, keep the data stream and diagnostic stream separate explicitly:

$ git rev-list --objects --all \
    | git pack-objects --stdout >/tmp/repository.pack \
    2>/tmp/repository.pack.log
$ test -s /tmp/repository.pack && echo 'pack is non-empty'
pack is non-empty
$ file /tmp/repository.pack
/tmp/repository.pack: Git pack, version 2, 6 objects

Progress is normally shown on standard error only when it is attached to a terminal. Use -q for quiet operation, or --progress when a progress meter is useful in a non-terminal job.

4. Create indexed files with a base name

For a pack that Git can open from an object store, provide a base name in a writable directory. Git appends a content hash and creates matching .pack and .idx files:

$ mkdir -p /tmp/git-pack-output
$ git rev-list --objects --all \
    | git pack-objects /tmp/git-pack-output/repository
949ce5640979d46a2495e132170d07cbdc8af475
$ find /tmp/git-pack-output -maxdepth 1 -type f -printf '%f\n' | sort
repository-949ce5640979d46a2495e132170d07cbdc8af475.idx
repository-949ce5640979d46a2495e132170d07cbdc8af475.pack

The exact hash and object count will differ. The index is for fast random access, while the pack holds the compressed objects. To make Git discover these files as repository objects, place both files in the repository's object store, normally its objects/pack/ directory. That changes repository state and may affect later maintenance, so use git repack for ordinary repository maintenance unless you specifically need this plumbing workflow.

5. Verify the pack before using it

For a pack written to a file, create or obtain an index and ask Git to inspect it. In the base-name workflow, verify the generated index directly:

$ git verify-pack -v /tmp/git-pack-output/repository-*.idx | tail -3
non delta: 3 objects
repository-949ce5640979d46a2495e132170d07cbdc8af475.pack: ok

For a standard-output pack, git index-pack can read the stream and check its structure:

$ git index-pack --stdin < /tmp/repository.pack
7d29f3bc5f8ade1de2284ae71add4fc957a69f02

Run the check before copying the pack into a service or removing the source repository. A successful index operation confirms that Git can parse the pack; it does not prove that you selected every reference or that a receiving repository has the history you intended.

6. Keep thin packs inside a complete workflow

Do not add --thin to a standalone archive. A thin pack omits objects that the receiver is expected to already have, so it is not self-contained. It only makes sense with --stdout in a sender and receiver workflow that knows the common objects. The receiver must use git index-pack --fix-thin to restore the self-contained property before treating the pack as ordinary Git data.

Likewise, --delta-base-offset can make packs smaller, but old Git versions may not understand that representation. Modern porcelain commands pass it by default. If an old consumer is part of the workflow, check its compatibility before selecting the option.

7. Avoid accidental loss and resource surprises

Shell redirection with > truncates an existing file before Git starts. Use a new temporary name, verify it, then replace the destination deliberately:

$ git rev-list --objects --all \
    | git pack-objects --stdout >/tmp/repository.pack.new
$ git index-pack --stdin </tmp/repository.pack.new
$ mv /tmp/repository.pack.new /tmp/repository.pack

The final mv changes state and overwrites the destination if it already exists. Keep a backup or choose a new name when the old pack matters. If packing fails before the move, the previous file remains. Remove an unwanted temporary file only after checking which path it names.

Large delta windows can consume substantial memory and CPU. The documented defaults are a window of 10 objects and a maximum delta depth of 50. Start with defaults, measure the result, and tune --window, --depth or --window-memory only for a demonstrated need. --max-pack-size can split output, but smaller independent packs may be larger and slower overall.

Done means

  • The installed Git version and selected revision set were checked.
  • The pack was written as binary output to a deliberate destination.
  • A matching index was created or verified successfully.
  • --thin was used only when a receiver can fix the thin pack.
  • No existing pack or output file was overwritten without an intentional replacement step.