Git: share a full repository as a file with git fast-export

Typically, we share repositories through a Git host, like GitHub, allowing others to clone the repository to get a copy. But sometimes that’s not an option, for example when trying to get someone started on your project when corporate onboarding processes take days to grant GitHub access.
In such cases, you can share a repository as a single file, including its entire history across all branches, using git fast-export. The receiver can unpack this file into a local repository using git fast-import. Let’s see how.
Export a repository
Use this command to export the current repository to a single gzipped file:
$ git fast-export --all | gzip > super-duper-project.gz
Replace super-duper-project.gz with the desired filename.
--all makes git fast-export export all branches and tags. Compressing with gzip can reduces the file size significantly because the output is text-based and contains a lot of repetition.
Import a repository file
As a receiver, you need to take a few steps to import the gzipped repository file.
First, create a new empty repository:
$ git init super-duper-project
$ cd super-duper-project
Second, import the gzipped file into the new repository:
$ gzip -dc ../super-duper-project.gz | git fast-import
fast-import statistics:
---------------------------------------------------------------------
Alloc'd objects: 5000
Total objects: 3124 ( 5 duplicates )
blobs : 1394 ( 0 duplicates 681 deltas of 1388 attempts)
trees : 1118 ( 5 duplicates 980 deltas of 1090 attempts)
commits: 611 ( 0 duplicates 0 deltas of 0 attempts)
tags : 1 ( 0 duplicates 0 deltas of 0 attempts)
Total branches: 38 ( 37 loads )
...
---------------------------------------------------------------------
Replace ../super-duper-project.gz with the path to the received file.
The output shows a bunch of statistics, some of which I snipped above. It isn’t particularly friendly, but it at least gives you an idea that the import worked, and contained a bunch of commits, branches, and tags.
Third, restore the working tree and staging area with:
$ git restore --staged --worktree .
This step is necessary because while git fast-import imports the repository history, it doesn’t check out files. Without this step, Git will detect all files as deleted:
$ git status
Found existing alias for "git status". You should use: "gst"
On branch main
Changes to be committed:
deleted: .editorconfig
deleted: .gitignore
deleted: CHANGELOG.rst
...
After running the git restore command, Git should report a clean status:
$ git status
On branch main
nothing to commit, working tree clean
You can now start exploring the repository as usual, such as with git log.
Configure a remote later
If you later gain access to the Git host, there’s no need to re-clone. You can add a remote to the existing repository with:
$ git remote add origin https://example.com/acme/super-duper-project.git
Replacing the URL with the actual URL of the remote repository.
Test that works with a fetch:
$ git fetch
remote: Enumerating objects: 14313, done.
remote: Counting objects: 100% (4127/4127), done.
...
From https://example.com/acme/super-duper-project
...
Then you can pull any newer changes to the main branch with:
$ git switch main
$ git pull --set-upstream origin main
From https://example.com/acme/super-duper-project
* branch main -> FETCH_HEAD
Successfully rebased and updated refs/heads/mains.
😸😸😸 Check out my new book on using GitHub effectively, Boost Your GitHub DX! 😸😸😸
One summary email a week, no spam, I pinky promise.
Related posts:
- Git: fix a filename case collision
- Git: count commits with
rev-list - Git: Improve diff generation with
diff.algorithm=histogram
Tags: git