Shipping a Repo as One File with `git bundle`
No network access, no shared server, no GitHub — just a USB stick and a deadline. git bundle packs an entire repository, branches, tags, and full history, into one file you can clone straight from.

An air-gapped environment needs your code — a customer site with no internet access, a security-cleared machine that can't reach GitHub, a handoff to a contractor who isn't on your org's network yet. Zipping the working directory throws away every commit, every branch, every tag. What you actually want to hand over is the repository itself.
git bundle packages a full repository — history, branches, tags, everything git clone would give you — into one ordinary file. Copy it over USB, email it, drop it in a shared folder; on the other end, it clones exactly like a remote would.
Pack it up
A small repo with two commits and a tag:
git log --oneline
# c5ea3ce second commit
# 5f83d23 initial commit
git tag
# v1.0Bundle everything reachable from every ref:
git bundle create project.bundle --allgit bundle verify project.bundleproject.bundle is okay
The bundle contains these 3 refs:
c5ea3ce refs/heads/main
5f83d23 refs/tags/v1.0
c5ea3ce HEAD
The bundle records a complete history."The bundle records a complete history" is the important line — this isn't a diff or a patch series, it's every commit needed to reconstruct the repository from nothing, self-contained in a single file. On a normal repo it's typically a similar size to .git itself, since it's the same packed objects.
Clone straight from it
The receiving end doesn't need a server, a URL, or even network access — a bundle is a valid clone source:
git clone project.bundle myappcd myapp
git log --oneline
# c5ea3ce second commit
# 5f83d23 initial commit
git tag
# v1.0
git remote -v
# origin /path/to/project.bundle (fetch)
# origin /path/to/project.bundle (push)Full history, the tag, everything intact. Git even sets the bundle itself as origin, though in practice you'd repoint that at a real remote once one exists on the receiving side.
Handing off only what's new
Bundling --all every time works, but for a repository that already exists on the other end, you can bundle just the commits it's missing. Say the far side already has v1.0:
git bundle create update.bundle v1.0..mainThat produces a bundle containing only the commits between v1.0 and the tip of main — useful for periodic drops into an environment you can't push to directly, where re-shipping the entire history every time would be wasteful.
Checking a bundle before you trust it
git bundle verify isn't just a sanity check on the file — it also tells you what the bundle assumes the receiving repository already has. An incremental bundle built with v1.0..main needs v1.0 to already exist on the far side, and verify will say so explicitly if you run it against a repo that's missing that prerequisite. Run it before you ship the file, not after someone on the other end reports a confusing error.
Where this actually gets used
- Air-gapped or offline handoffs — the case above. No shared server required on either side.
- Backups outside your normal remote. A bundle is a complete, restorable snapshot;
git clonefrom it works even if the original remote is long gone. - Getting a repo through a network you don't control. If corporate policy blocks git protocols but allows file transfer, a bundle sidesteps the restriction entirely — it's just a file.
- Sending a branch for review without pushing it anywhere.
git bundle create review.bundle main..feature-branchhands someone exactly the commits in question, nothing more.
A bundle isn't a live connection — it's a snapshot at the moment you created it. Fetching from one later won't pick up commits made afterward; you'd generate a new incremental bundle for that, the same way you'd git fetch from a real remote. Once the destination has its own proper remote set up, there's no reason to keep treating the bundle file as origin — it did its one job of getting the history there.
Next time "how do I get this repository onto a machine with no network access" comes up, skip the zip file. git bundle create gives you the actual repository, portable as a single file, cloneable the moment it arrives.