Rebuild a Git Pack Index with git index-pack

git index-pack rebuilds the .idx file a pack needs, or checks a pack you just received before you trust it. A missing or corrupt index will stop a pack dead until you run it. The examples match Git 2.43.0 from Ubuntu package git-man 1:2.43.0-1ubuntu7.3, installed on the system used for this guide. Allow about fifteen minutes.

1. Check the installed command

Confirm the version and syntax before touching a pack. These are ordinary, read-only commands:

$ git --version
git version 2.43.0
$ git index-pack -h
usage: git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--[no-]rev-index] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])

The command reads a .pack file and builds its matching .idx file. It does not unpack objects into loose files. A pack and its index can then live in a repository's objects/pack/ directory.

Checkpoint: identify the exact pack you intend to process. Do not use a wildcard until you have inspected what it matches.

$ PACK=/path/to/objects/pack/pack-0123456789abcdef0123456789abcdef01234567.pack
$ test -f "$PACK" && printf 'pack found: %s\n' "$PACK"
pack found: /path/to/objects/pack/pack-0123456789abcdef0123456789abcdef01234567.pack

2. Rebuild the index beside an existing pack

When the file name ends in .pack, the default output name is the same basename with .idx. If the index is missing or damaged, rebuilding it changes that directory, so take a backup or make sure the pack is recoverable first.

$ git index-pack --strict --rev-index "$PACK"
0123456789abcdef0123456789abcdef01234567

The hexadecimal line is the pack checksum used in the pack and index names. With --strict, Git rejects broken objects or links rather than creating an index for a suspect pack. --rev-index also creates a reverse index beside it:

$ test -f "${PACK%.pack}.idx" && echo 'index created'
index created
$ test -f "${PACK%.pack}.rev" && echo 'reverse index created'
reverse index created
$ git verify-pack -v "${PACK%.pack}.idx" | tail -n 1
non delta: 3 objects

The final verify-pack line is data-dependent, so your object count will differ. A successful command and an existing index are the checks that matter. Skip --rev-index if you do not need reverse-index data; the option overrides the repository's pack.writeReverseIndex setting for this run.

3. Choose a separate index path when required

Use -o when the generated index must not sit beside the pack. This suits staging or testing, but it leaves the original pack untouched and does not make the custom index the repository's active one:

$ INDEX=/tmp/pack-check.idx
$ git index-pack --strict --rev-index -o "$INDEX" "$PACK"
0123456789abcdef0123456789abcdef01234567
$ test -f "$INDEX" && echo 'custom index created'
custom index created

Do not point -o at an index already used by a different pack. An index describes one particular pack, so overwriting a valid index with an unrelated one can make later Git operations fail. If this was only a test, remove the temporary file after inspection:

$ rm -f -- "$INDEX"
$ test ! -e "$INDEX" && echo 'temporary index removed'
temporary index removed

4. Import a pack from standard input

Use --stdin when another process or a file transfer supplies the pack stream. Git writes a copy to the destination you provide, then builds the index from that copy. The destination must be writable:

$ mkdir -p /path/to/objects/pack
$ cat /path/to/incoming.pack | git index-pack --stdin --strict --rev-index \
    /path/to/objects/pack/received.pack
0123456789abcdef0123456789abcdef01234567
$ ls -1 /path/to/objects/pack/received.*
received.idx
received.pack
received.rev

For a real transfer, replace cat with the actual producer. Git's output is the checksum, not a success message you can rely on parsing as a file name, so check the expected files explicitly.

If you omit the destination, Git chooses a pack name from the content and writes into the current repository's objects/pack/ directory. That suits Git's own receive workflows, but it makes the destination less obvious. Use an explicit path when working by hand.

5. Protect an imported pack during ref updates

A concurrent git repack can remove a newly imported pack before a reference points to its objects. Add a keep file while another process completes that hand-off:

$ cat /path/to/incoming.pack | git index-pack --stdin \
    --strict --rev-index --keep='manual import 2026-09-24' \
    /path/to/objects/pack/received.pack
keep	0123456789abcdef0123456789abcdef01234567
$ ls -1 /path/to/objects/pack/received.*
received.idx
received.keep
received.pack
received.rev

The .keep file is a coordination lock, not permanent metadata. Finish the reference update or other consumer operation first, then remove only the keep file you created:

$ rm -f -- /path/to/objects/pack/received.keep
$ test ! -e /path/to/objects/pack/received.keep && echo 'keep file removed'
keep file removed

Warning: do not remove another process's keep file to make a repack proceed. If you are unsure who owns it, leave it in place and investigate. A stale keep file normally just costs storage; deleting an active one can create a race.

6. Handle thin packs and hash formats deliberately

A thin pack omits base objects that the receiving repository is expected to already have. It can only be repaired while reading from standard input:

$ git pack-objects --stdout --thin < object-list \
    | git index-pack --stdin --fix-thin --strict \
      /path/to/objects/pack/repaired.pack

That placeholder input is deliberately not a complete producer. Use the exact pack-producing workflow that created the thin pack, and make sure the required base objects are already available. --fix-thin is unnecessary with a normal complete pack, and using it without --stdin is invalid.

Outside a repository, Git assumes SHA-1 unless you specify another supported object format. Inside a repository it follows extensions.objectFormat. SHA-1 and SHA-256 repositories are not interchangeable, and --object-format cannot be combined with --stdin in this Git release. Do not guess the hash format from a shortened checksum.

Common traps

Done means