GitGit Bundles

git bundle: Offline Repository Transfer

A Git bundle is a single binary file that packages a complete or partial Git repository — including all object data (commits, trees, blobs) and ref pointers — into one portable file. Unlike a zip of source code, a bundle preserves the full Git history and allows the recipient to perform real Git operations such as clone, fetch, and pull directly from that file. Think of it as a portable, self-contained Git remote that travels as a regular file.

Why Use Bundles?

Bundles shine in situations where a network connection to a Git remote is unavailable or restricted. Common scenarios include transferring a repository to an air-gapped server (a machine with no internet access), moving a repo via USB stick, emailing an incremental update to a collaborator behind a strict firewall, or carrying a project backup on physical media. Because a bundle is a regular file, it can travel through any channel that can carry files.

  • Air-gapped servers with no outbound internet access

  • USB stick or physical media transfers between offices

  • Email attachments for small incremental updates

  • Offline backup of a repository at a specific point in time

  • Bootstrapping a new clone in a restricted CI environment

Creating a Full Bundle

To package every branch, tag, and commit in your repository into a single bundle file, use the --all flag. The resulting file can be used to recreate the entire repository from scratch on any machine — no network required.

Create a complete bundle of all refs

Bash
git bundle create repo.bundle --all

Terminal output

Text
Enumerating objects: 1847, done.
Counting objects: 100% (1847/1847), done.
Delta compression using up to 10 threads
Compressing objects: 100% (923/923), done.
Writing objects: 100% (1847/1847), 2.34 MiB | 0 bytes/s, done.

The file repo.bundle now contains every object reachable from any branch or tag in the repository. You can copy this file to any destination and restore the full repository from it.

Creating a Bundle from a Specific Ref

If you only need to transfer one branch, specify just that ref. This produces a smaller file that includes only objects reachable from the named branch — not the entire repository.

Bundle only the main branch

Bash
git bundle create main.bundle main
Creating an Incremental (Update) Bundle

One of the most powerful features of bundles is incremental updates. If the recipient already has commits up to a certain point (for example up to the v1.0 tag), you only need to send them the new work. The range syntax works exactly like git log range syntax — use two dots to specify "commits reachable from HEAD but not from v1.0".

Create an incremental bundle (commits after v1.0 up to HEAD)

Bash
git bundle create update.bundle v1.0..HEAD

Create an incremental bundle since a specific commit hash

Bash
git bundle create patch.bundle abc1234..HEAD

This bundle contains only objects introduced after the v1.0 tag. The recipient must already have the prerequisite commits; Git will verify this automatically when they try to use the bundle and refuse to apply it if the prerequisites are missing.

Verifying a Bundle

Before sending a bundle — or upon receiving one — always verify it. Verification confirms that the bundle file is not corrupt and that any prerequisite commits it requires already exist in your repository.

Verify bundle integrity and check prerequisites

Bash
git bundle verify repo.bundle

Successful verification output

Text
The bundle contains these 2 refs:
        a3f1c2d83e4f5a6b7c8d9e0f refs/heads/main
        7890abcd7890abcd7890abcd refs/heads/feature/auth
The bundle requires these 0 prerequisite commits.
repo.bundle is okay

Incremental bundle verification (shows prerequisites)

Text
The bundle contains these 1 refs:
        a3f1c2d83e4f5a6b7c8d9e0f refs/heads/main
The bundle requires these 1 prerequisite commits:
        v1.0 (9e2b0f1c2d3e4f5a6b7c8d9e)
repo.bundle is okay
Listing Bundle Contents

To inspect what refs a bundle contains without extracting anything, use list-heads. This shows the SHA hashes and ref names packaged inside — useful as a quick sanity check before handing the bundle to a recipient.

List all refs inside a bundle

Bash
git bundle list-heads repo.bundle

Example output

Text
a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2 refs/heads/main
7890abcd7890abcd7890abcd7890abcd7890abcd refs/heads/feature/auth
deadbeef1234deadbeef1234deadbeef12345678 refs/tags/v1.0
Warning
A bundle only includes the refs and objects you explicitly specify when creating it. Always run git bundle list-heads before sending a bundle to confirm it contains everything the recipient expects. If you forgot to include a tag or a branch, the recipient will see an incomplete history with no error message explaining why.
Cloning from a Bundle

The recipient can treat the bundle file exactly like a remote URL. To create a brand-new local repository from a full bundle, use git clone with the bundle file path as the source. Git will populate the entire repository from the bundle.

Clone a new repository from a bundle file

Bash
git clone repo.bundle my-project
cd my-project
git log --oneline

After cloning, the remote named origin will point to the bundle file path on disk. You can update origin to point to a real remote server once one is available:

Update origin after cloning from a bundle

Bash
git remote set-url origin git@github.com:org/my-project.git
Fetching from a Bundle (Incremental Update)

For applying incremental updates to an existing repository, use git fetch with the bundle as the remote source. You map bundle refs to local refs using a refspec, just as you would with a regular remote.

Fetch the main branch from a bundle into your local main

Bash
git fetch ../repo.bundle main:main

Fetch all refs from a full bundle

Bash
git fetch ../repo.bundle '*:*'
Tip
You can also add a bundle as a named remote so you can fetch from it repeatedly without typing the path each time: git remote add offline-remote /path/to/repo.bundle
Full Air-Gapped Workflow Example

Complete offline transfer workflow

Bash
# ── On the source machine ──────────────────────────────────

# Step 1: Create a full bundle covering all refs
git bundle create /media/usb/project.bundle --all

# Step 2: Verify before handing over
git bundle verify /media/usb/project.bundle

# Step 3: List contents as a sanity check
git bundle list-heads /media/usb/project.bundle

# ── Copy USB drive to target machine ───────────────────────

# Step 4: On the target machine, clone from the bundle
git clone /media/usb/project.bundle ~/project
cd ~/project
git log --oneline --graph --all

# Step 5: Update origin to point to real remote (when available)
git remote set-url origin git@intranet-server:project.git

# ── Later, send only new commits ───────────────────────────

# Tag the last sync point on the source machine
git tag last-transfer HEAD

# Create bundle with only new work since the last transfer
git bundle create /media/usb/update.bundle last-transfer..HEAD

# On target machine: verify and apply the update
git bundle verify /media/usb/update.bundle
git fetch /media/usb/update.bundle main:main
git merge --ff-only main
Comparing Transfer Methods

Feature

git bundle

git archive

git clone --mirror

Contains full Git history

Yes

No — snapshot only

Yes

Output type

Single binary .bundle file

tar / zip archive

Full .git directory

Supports incremental updates

Yes — via range syntax

No

Yes — via fetch

Recipient can git clone from it

Yes

No

Yes

Works without network

Yes — designed for this

Yes

No — needs SSH/HTTPS

Includes working tree files

Yes (as blob objects)

Yes (as plain files)

No (objects only)

Useful for deployment artifacts

No

Yes — clean source tree

No

File size vs full repo

Similar — pack format

Smaller — no history

Similar or larger

Note
Bundles use the same packfile format as Git network transfers internally. This means they are highly compressed and efficient — a bundle of a large repository will be roughly the same size as what you would download with git clone over HTTPS.