Moving Code Without a Network: Mastering Mercurial Bundles
Learn how to use Mercurial bundles to move code and history between repositories without a network connection, including practical examples for incremental syncing.
16 Jun 2026, 19:25 UTC

The 'Air-Gap' Problem
Modern version control assumes a constant connection to a central server. But what happens when you are working in a high-security environment with no internet access, dealing with strict firewall restrictions, or trying to send a specific set of changes to a colleague via a USB drive or email? Sending a raw zip of the current folder loses the commit history, and sending individual patches is tedious and error-prone.
The solution is the Mercurial Bundle. A bundle is a single portable file that contains the full history, metadata, and file contents of one or more changesets. It effectively acts as a "portable slice" of your repository that can be imported into another Mercurial repo as if it had been pulled from a server.
How Bundles Differ from Patches
While a patch file describes how to change a file, a bundle contains the actual state of the repository. Because bundles preserve the changeset IDs (the unique hashes identifying each commit), Mercurial can verify exactly where the bundled changes fit into the destination repository's timeline. This prevents the "duplicate commit" problem common when applying manual patches across different environments.
Creating and Importing Bundles
Bundling is a two-step process: creating the archive (bundling) and applying it to a target repository (unbundling). These operations are typically run from the terminal within the repository root.
Exporting Changes
To create a bundle, use the hg bundle command. You must specify the range of changesets you want to include. The syntax follows the pattern start::end.
- The Tip: To bundle everything from the current state back to the beginning of the repo:
hg bundle -o full_repo.hg . - A Specific Range: To bundle changes between two specific revisions (e.g., revision 10 to the latest):
hg bundle -o updates.hg 10::tip
Importing Changes
The recipient uses the hg unbundle command to merge the file into their local repository. This operation updates the local store but does not automatically update the working directory files; you must still perform a hg update to see the changes in your editor.
Worked Example: Incremental Sync
Imagine two developers, Alice and Bob, working on a project without a shared server. Alice has made three new commits that Bob needs.
Step 1: Alice identifies the common ancestor.
Alice knows Bob is currently at revision 100. She runs this command in her terminal (requires read permissions for the repo):
hg bundle -o feature_update.hg 100::tip
Alice sends feature_update.hg to Bob via an external drive.
Step 2: Bob imports the changes.
Bob runs the following command in his repository root:
hg unbundle feature_update.hg
Step 3: Verification.
Bob verifies the new commits are present by checking the log:
hg log -r 100::tip
If the output shows Alice's three new commits with their original hashes, the transfer was successful.
Trade-offs and Limitations
Bundles are powerful, but they are not a replacement for a full backup or a mirrored server in all cases.
- Binary Bloat: Bundles include the full contents of the files in the specified range. If you have large binary assets (like images or compiled binaries) that change frequently, the bundle file size will grow rapidly, potentially making it too large for email attachments.
- Diverged History: If Bob has made his own commits since revision 100, unbundling Alice's changes will create a branch (multiple heads). Bob will then need to perform a standard
hg mergeto unify the histories. - State Change: Because
hg unbundlemodifies the repository's history store, it is a state-changing operation. If you import a bundle that contains corrupted or unwanted history, you may need to usehg rollback(if applicable) or restore the repository from a backup.
Final Checklist for Bundle Transfers
To ensure a smooth transfer, follow these three checks:
- Verify the Range: Always double-check the revision numbers (e.g.,
100::tip) to avoid sending unnecessary history or missing critical commits. - Check File Size: Use
ls -lhon the resulting.hgfile to ensure it is manageable for your transfer method. - Update After Unbundle: Remember that
unbundleonly updates the history; runhg updateto bring those changes into your active workspace.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.