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

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

Recover Git Objects from a Pack with git unpack-objects

You will check a Git .pack file, expand its objects into the loose-object store of a chosen repository, and verify what arrived. The examples use Git 2.43.0 from Debian package git-man 1:2.43.0-1ubuntu7.3 and the matching git package on this machine.

Allow about fifteen minutes. You need a shell, Git, a readable pack file, and a target repository. This command reads the pack from standard input. It does not create branches, move HEAD, populate a working tree or install the pack as a normal indexed pack. Work on a copy of valuable data first. No command below needs sudo.

1. Confirm the installed command

Check the version and the local option syntax before handling the pack:

$ git --version
git version 2.43.0
$ git unpack-objects -h
usage: git unpack-objects [-n] [-q] [-r] [--strict]

The installed manual also documents --max-input-size=<size>, which limits the size of input accepted. The short help output above is not a complete substitute for the manual. Keep the input path and target repository explicit while you work.

Checkpoint: identify the exact pack and make sure it is really a pack file:

$ ls -lh /path/to/incoming.pack
$ file /path/to/incoming.pack
/path/to/incoming.pack: Git pack, version 2, 6 objects

The wording from file varies. A missing file, an unreadable file or an ordinary archive is an input problem; do not try progressively more privileged commands until the path has been checked.

2. Select the target repository

Run the command from, or point it at, the repository that should receive the objects. A bare repository is valid. For an ordinary checkout, verify the repository before changing it:

$ git -C /path/to/target rev-parse --git-dir
/path/to/target/.git
$ git -C /path/to/target status --short

If the last command prints changes, stop and record them before recovery. git unpack-objects writes into the object database, so keep a backup or snapshot of the target if it matters. The operation does not normally alter tracked files, the index or refs, but the new objects become part of the repository's stored data.

3. Dry-run the pack

Use -n first. It checks the pack without unpacking its objects:

$ git -C /path/to/target unpack-objects -n < /path/to/incoming.pack
$ printf 'dry-run status: %s\n' "$?"
dry-run status: 0

Silence and status 0 mean that this check completed successfully. The command reads standard input, so the shell redirection is part of the example. If you see a pack-format or checksum error, keep the original pack and obtain it again from its producer. Do not use -r merely to suppress an error: it asks Git to continue past corruption and make a best-effort recovery.

4. Limit a potentially untrusted input

A pack can be much larger than expected. Set an input limit when the source is untrusted or the available storage is constrained:

$ git -C /path/to/target unpack-objects --max-input-size=500m < /path/to/incoming.pack
fatal: pack exceeds maximum allowed size

The error above is expected only when the pack is larger than the chosen limit. Pick a limit that fits the job rather than copying this value blindly. This check does not make a malformed pack safe, and it does not limit every resource used while processing an accepted pack. Use normal filesystem quotas and operational isolation for hostile inputs.

5. Unpack into the repository

After the dry-run passes, send the pack to the target without -n:

$ git -C /path/to/target unpack-objects -q < /path/to/incoming.pack
$ printf 'unpack status: %s\n' "$?"
unpack status: 0

-q suppresses the normal percentage progress. Leave it out when you want to watch progress on a large pack. The command expands objects into loose files. Objects already present in the target are skipped, so feeding a pack that already belongs to that repository can appear to do nothing. That is normal and is not proof that the input was ignored accidentally.

Git may print notices if the target has no refs, such as an empty repository with an unborn HEAD. Those notices do not mean that the pack failed. They describe the target's refs, which this command does not create.

6. Verify objects, then find the missing ref

Run Git's object check against the target:

$ git -C /path/to/target fsck --full --no-progress
Checking object directories: 100% (256/256), done.

Exact progress and diagnostic lines depend on the repository. The useful result is an exit status of 0 and no corruption error. You may also inspect the object count:

$ find /path/to/target/.git/objects -mindepth 2 -maxdepth 2 -type f | wc -l
6

Do not expect git log to show a recovered commit until a ref points to it. If you know the commit ID, inspect it directly:

$ git -C /path/to/target cat-file -t COMMIT_ID
commit
$ git -C /path/to/target show --stat COMMIT_ID

Only after verifying the object should you restore a branch or tag, using the ref name and object ID supplied by your recovery record. For example, git -C /path/to/target update-ref refs/heads/recovered COMMIT_ID changes repository state and should be reviewed as a separate, deliberate action. If you create the wrong ref, remove that exact ref with git -C /path/to/target update-ref -d refs/heads/recovered.

7. Handle corruption and security boundaries

By default, a corrupt pack stops at the first corruption. The -r option keeps going and tries to recover as many objects as possible. Treat the result as partial: run git fsck --full, compare the recovered object IDs with an independent copy, and do not build a release or restore a branch from it until the missing objects are understood.

--strict refuses to write objects with broken content or links. Use it when accepting a pack where object validity matters. Neither -r nor --strict repairs a damaged source or proves that a commit is trustworthy. A pack can contain perfectly valid objects from an unwanted or compromised history, so verify its provenance before making any recovered ref visible to other users.

Do not overwrite the only copy of the pack, delete the original repository, or run recovery as root to bypass an access error. Check ownership and permissions first. If you must undo the object write, restore the target from the snapshot or disposable clone taken before step 5; deleting individual loose objects by hand is unsafe because other refs or objects may depend on them.

Done means

  • The Git version, pack path and target repository were confirmed.
  • A dry-run completed successfully before any objects were written.
  • The pack was unpacked through standard input, with a deliberate input-size limit where appropriate.
  • git fsck --full completed without corruption errors.
  • You understand that unpacking creates objects, not refs, branches or working-tree files.
  • The original pack and a recovery snapshot remain available until the result is verified.