Migrating GitHub Gists to OpenGist with metadata preservation
On migrating GitHub Gists to a self-hosted OpenGist instance, with metadata preservation.
Like many software engineers, I’ve accumulated a lot of GitHub Gists over the years. They’re handy for sharing code, snippets, configs, and quick notes.
In an attempt to self-host more and more services in order to have more control, I stumbled upon OpenGist: a self-hosted alternative to GitHub Gists that one can run in a private setup.
I found OpenGist to be almost compatible with GitHub Gists, since it is also powered by Git under the hood. So this should make it easy to migrate from one service to the other. More importantly, some of the GitHub gists are "secret", so ideally they should keep the same level of visibility once migrated.
This post walks through migrating all your GitHub Gists to an OpenGist instance while preserving their metadata. Let's get started.
Goals
When migrating, I wanted to:
- Keep the original visibility (public vs. secret).
- Preserve the title and description.
- Migrate the actual Git repositories intact.
Prerequisites
- An OpenGist instance running with a user configured. See Install OpenGist for more details.
- The GitHub CLI (a.k.a.,
gh
) installed. - Git installed.
Migration Script
Here is the migration script (stored on my OpenGist instance of course):
The approach here is quite straightforward:
- Use
gh api
to list all gists along with their metadata - Clone each gist locally
- Inside each gist clone, add the OpenGist instance as a remote (the
/init
endpoint is a special endpoint that triggers the creation of a new gist) - Push with metadata options (
git push -o visibility=... -o title=... -o description=...
).
Once you export the OPENGIST_USER
and OPENGIST_PASSWORD
environment variables in your terminal and run the script, you should get all your GitHub gists imported into your OpenGist instance:

OpenGist interprets the push options provided and applies them to each new gist imported.
A few things to note however:
- Visibility mapping: GitHub has only
public
andsecret
gists. OpenGist supportspublic
,unlisted
, andprivate
. In the script, I an mapping everything that is not public in GitHub asprivate
in OpenGist. You can change this tounlisted
if that’s more appropriate for your use case. - Title: GitHub Gists don’t have a dedicated
title
field. The convention is to use the first filename in the gist, which is what the script extracts. - Description: Pulled directly from GitHub’s gist metadata.
- Branch names: I ran into an error where some gists were using
master
. The script detects the current branch automatically. - Authentication: Make sure both
gh
and yourgit
client are authenticated with GitHub. The script uses the OpenGist HTTPS URL with both the username and password, but feel free to rely on the SSH URL instead if needed. - Non-idempotent: Running the script twice will create new gists in your OpenGist instance. This was fine for my use case of a one-off migration script.
Wrapping Up
With this script, I was able to migrate my entire gist library to my self-hosted OpenGist in one shot, while keeping the important metadata intact. Now I have my code snippets under my own control.
If you’re running OpenGist and have old GitHub Gists lying around, feel free to give this approach a try.
As usual, feel free to share your thoughts in the comments.