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
git bundle create repo.bundle --all
Terminal output
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
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)
git bundle create update.bundle v1.0..HEAD
Create an incremental bundle since a specific commit hash
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
git bundle verify repo.bundle
Successful verification output
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 okayIncremental bundle verification (shows prerequisites)
The bundle contains these 1 refs:
a3f1c2d83e4f5a6b7c8d9e0f refs/heads/main
The bundle requires these 1 prerequisite commits:
v1.0 (9e2b0f1c2d3e4f5a6b7c8d9e)
repo.bundle is okayListing 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
git bundle list-heads repo.bundle
Example output
a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2 refs/heads/main 7890abcd7890abcd7890abcd7890abcd7890abcd refs/heads/feature/auth deadbeef1234deadbeef1234deadbeef12345678 refs/tags/v1.0
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
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
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
git fetch ../repo.bundle main:main
Fetch all refs from a full bundle
git fetch ../repo.bundle '*:*'
Full Air-Gapped Workflow Example
Complete offline transfer workflow
# ── 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 |