Skip to content
masterclass Buddy

Git · Command

git bundle

git bundle packs Git objects and refs into a single file. You can move that file by USB, email or any other channel and clone or fetch from it later, with no network connection between the two repositories.

Last updated

How it works

git bundle create takes rev-list style arguments, such as branch names, --all or ranges like old..new. It writes a pack file with a header that lists the refs in the bundle. If you give exclusions such as ^old or old..new, those commits become prerequisites, and the receiving repository must already have them. On the receiving side the bundle works like a read-only remote: you can clone from it, fetch from it, or list its refs. verify checks that the file is valid and that the prerequisites are present, list-heads prints the refs, and unbundle stores the objects through index-pack.

Syntax

git bundle create [-q | --quiet | --progress] [--version=<version>] <file> <git-rev-list-args>
git bundle verify [-q | --quiet] <file>
git bundle list-heads <file> [<refname>…]
git bundle unbundle [--progress] <file> [<refname>…]

Parameters

NameTypeDescription
<file>pathThe bundle file to write or read. Use - to write to stdout (create) or read from stdin (verify, list-heads, unbundle).
<git-rev-list-args>rev-list argumentsArguments that git rev-parse and git rev-list accept, including at least one named ref. They choose which refs and objects go into the bundle, for example master, --all or master~10..master.
[<refname>…]ref namesLimits which refs list-heads and unbundle report. This is mainly used by git fetch.
--progressflagShows progress on stderr even when stderr is not a terminal.
--version=<version>integer (2 or 3)Sets the bundle format version. Version 2 works only with SHA-1 repositories. Version 3 supports capabilities. The default is the oldest format that works with the repository's hash algorithm.
-q, --quietflagTurns off progress reporting on stderr.

Returns

create writes a bundle file. verify exits with 0 if the bundle is valid and can be applied, and prints any missing prerequisite commits. list-heads and unbundle print the refs defined in the bundle.

Key points

  • After you have the bundle file, the receiving repository treats it like any other read-only remote. You can map refs while fetching, for example git fetch mybundle master:localRef, or run git ls-remote on it.
  • A bare commit ID is not enough. The arguments must name at least one ref, or you can use --all to include every ref.
  • Run verify before applying a bundle that has prerequisites. It checks the file format and confirms that the commits the bundle depends on are already present in the receiving repository.
  • The exit status tells you whether the bundle is valid, so git bundle verify works well as a check in scripts or CI before an import.
  • Incremental bundles built with exclusions are stored as thin packs, which makes them smaller than full bundles. You cannot choose a thick pack in this case, and you don't need to.
  • The v2 format works only with SHA-1. Repositories that use another hash algorithm need v3, which supports capabilities such as an object filter.
  • You don't need to know exactly which objects the receiver is missing. Including too much is safe, because objects the destination already has are skipped when the bundle is unpacked.
  • You rarely need git bundle unbundle yourself. Use git fetch or git clone, which call it for you.

Common mistakes

  • A bundle is read-only. You can fetch and clone from it, but you cannot push into it. To send updates, create a new bundle.
  • A backup made with --all contains only refs and the commits reachable from them. Local configuration, hooks, stashes, the index and uncommitted work are not included.
  • If you pass a raw SHA, or a range whose right side is not a ref (such as master~10..master~5), the command fails with 'Refusing to create empty bundle'.
  • Don't back up a live repository with cp -r. Git might write to it during the copy and leave a corrupted copy. A bundle is the safer option.

Example: Full bundle, then an incremental update via a tag marker

#!/usr/bin/env bash
set -euo pipefail
cd "$(mktemp -d)"

# Source repository
git init -q -b main src && cd src
git commit -q --allow-empty -m "first"

# Full, self-contained bundle + remember what was sent
git bundle create ../full.bundle main
git tag -f lastSent main
cd ..

# Offline side: clone straight from the file
git bundle verify full.bundle
git clone -q -b main full.bundle dst

# More work on the source, then an incremental bundle
cd src
git commit -q --allow-empty -m "second"
git bundle create ../full.bundle lastSent..main
git tag -f lastSent main
cd ..

# Receiver checks prerequisites, then pulls from the replaced file
cd dst
git bundle verify ../full.bundle
git bundle list-heads ../full.bundle
git pull -q
git log --oneline

The script sends a self-contained bundle first, then sends only the new commits in a replacement bundle, which the clone picks up with git pull because its origin remote points at the bundle file.

When to use it

Air-gapped transfer

Move the history of a branch from a machine on a restricted network to an isolated one by carrying bundle files on removable media, and update with incremental ranges.

Consistent repository backup

Run git bundle create backup.bundle --all from a scheduled job, then restore later with git clone backup.bundle <dir>.

Sharing commits without a shared server

Email a colleague a bundle of a few local commits (for example main ^origin/main), which they can verify and fetch into a separate branch.

Streaming through pipes

Use - as the file name to write a bundle to stdout or read one from stdin, so you can chain it with compression, encryption or ssh.

Interview questions

QWhat is a Git bundle, and how does someone use one?

A bundle is a pack file with a header that lists the refs it contains, created with git bundle create <file> <rev-list-args>. The receiver treats the file as a remote: they can git clone it, git fetch from it, or run git ls-remote against it. This lets you move history between repositories with no network connection or server.

Follow-up: Can you push into a bundle? No. Bundles support only reading, so to send newer history you create a new bundle file and replace the old one.

QHow do you create an incremental bundle, and what risk does it bring?

Exclude commits the receiver already has, either with a range like lastSent..main or with options like ^old, --since or -10. Those excluded commits become prerequisites that must already be in the receiving repository. To check for them, the receiver runs git bundle verify, which lists any missing commits and exits with a nonzero code if the bundle cannot be applied.

Follow-up: How can you keep track of the cut-off point between bundles? Move a tag (for example git tag -f lastR2bundle master) after each bundle and use it as the left side of the next range.

QWhy does git bundle create x.bundle $(git rev-parse HEAD) fail?

The bundle has to record refs. A raw commit ID does not resolve to a ref name, so Git refuses with 'Refusing to create empty bundle'. Give a branch or tag name, or use --all. The same error happens if the right side of a range is not a ref.

Follow-up: Which arguments give a bundle the same refs a normal clone would get? Use --branches --tags as the rev-list arguments.

  • git clone
  • git fetch
  • git ls-remote
  • git pack-objects
  • git index-pack
  • git rev-list
  • git fetch-pack
  • gitformat-bundle

Source: Git - git-bundle Documentation. Checked 2026-11-02.