git bundle is a surprisingly powerful tool that lets you treat Git repositories like tarballs, enabling offline transfers and even versioned backups.

Imagine you’re on a plane with no Wi-Fi, but you need to share a Git history with a colleague. git bundle is your ticket. You can create a single file containing a specific range of commits, which your colleague can then "unbundle" into their own repository.

Let’s see it in action. Suppose you have a repository my-project and you want to bundle commits from tag v1.0 up to the latest commit on main.

First, on the sender’s machine:

git bundle create my-project.bundle v1.0..main

This creates a file named my-project.bundle containing all commits reachable from main that are not reachable from v1.0. This is a common and efficient way to send incremental updates.

Now, on the receiver’s machine, they can clone this bundle as if it were a remote repository:

git clone my-project.bundle my-project-cloned

This creates a new directory my-project-cloned with a local repository containing the bundled history.

What if you want to bundle everything from a specific tag onwards? You can use an "any" ref:

Sender:

git bundle create my-project-full.bundle v1.0

This bundles all commits reachable from v1.0 and its history.

Receiver:

git clone my-project-full.bundle my-project-full-cloned

This gives them a complete copy of the repository from that point.

The real magic happens when you want to update an existing repository. Instead of cloning anew, you can fetch from the bundle.

On the receiver’s machine, assuming they already have my-project-cloned and you’ve created an updated my-project-update.bundle (e.g., from v1.0 to a new v1.1 on main):

cd my-project-cloned
git remote add bundle-update ../my-project-update.bundle
git fetch bundle-update
git checkout main
git merge bundle-update/main

This adds the bundle as a temporary remote, fetches its contents, and then merges the new commits into the local main branch.

The core concept is that git bundle creates a "packed" repository file. It serializes Git objects (commits, trees, blobs) and refs into a single file. When you git clone a bundle, Git treats it like a bare repository and sets up a remote pointing to it. When you git fetch from a bundle, Git reads the refs and objects from the bundle file and updates your local refs accordingly.

You can also use git bundle create --all to bundle all refs, or git bundle create --branches --tags to include all branches and tags. The command git bundle verify my-project.bundle is crucial for checking the integrity of a bundle file before attempting to use it.

One of the most counterintuitive aspects of git bundle is how it handles ref updates. When you create a bundle using a range like v1.0..main, Git doesn’t just dump every object between those two points. It carefully calculates the differences needed to get from the "from" ref’s history to the "to" ref’s history. This means that a bundle created from v1.0 to main will contain only the commits and objects that are new since v1.0, making incremental updates incredibly efficient. If you then create another bundle from v1.1 to a newer main, it will contain only the objects needed to bridge the gap from v1.1 to the latest main, not re-bundling everything from v1.0.

The next step is often exploring how to create signed bundles for security.

Want structured learning?

Take the full Git course →