Repository files navigation

GitHub Backup

Automatically backup your GitHub repositories to your local machine.

This tool is designed to automatically pull the list of GitHub repositories from one, or more, GitHub organizations and clone (or fetch) them to your local machine. It is designed to be run as part of a scheduled backup process with the ultimate goal of ensuring that you have a local copy of all of your GitHub repositories should the unthinkable happen.

Installation

Install with Homebrew:

brew install sierrasoftworks/tap/github-backup

Features

  • Backup Multiple Organizations, automatically gathering the full list of repositories for each organization through the GitHub API.
  • Backup Starred Repos, automatically gathering the full list of your starred repositories
  • Repo Allowlists/Denylists to provide fine-grained control over which repositories are backed up and which are not.
  • GitHub Enterprise Support for those of you running your own GitHub instances and not relying on GitHub.com.

Example

# Run the tool directly
./github-backup --config config.yaml
# Or run it in a container
docker run \
-v $(pwd)/config.yaml:/config.yaml \
-v $(pwd)/backups:/backups \
ghcr.io/SierraSoftworks/github-backup:latest \
--config /config.yaml

Configuration

# Run a backup every hour (will use `git fetch` for existing copies)# You can also omit this if you want to run a one-shot backupschedule: "0 * * * *"backups:
- kind: github/repofrom: user # The user associated with the provided credentialsto: /backups/personalcredentials: !UsernamePassword { username: "<your username>", password: "<your personal access token>" }properties:
query: "affiliation=owner"# Additional query parameters to pass to GitHub when fetching repositories
- kind: github/repofrom: "users/another-user"to: /backups/friendcredentials: !Token "your_github_token"
- kind: github/repofrom: "orgs/my-org"to: /backups/workfilter: '!repo.fork && repo.name contains "awesome"'
- kind: github/releasefrom: "orgs/my-org"to: /backups/releasesfilter: '!release.prerelease && !asset.source-code'# You can also backup single repositories directly if you wish
- kind: github/repofrom: "repos/my-org/repo"to: /backups/work# This is particularly useful for backing up release artifacts for# specific projects.
- kind: github/releasefrom: "repos/my-org/repo"to: /backups/releasesfilter: '!release.prerelease'# Backup all repositories starred by the currently authenticated user
- kind: github/repofrom: "starred"to: /backups/starred/reposcredentials: !Token "your_github_pat"# Backup all GitHub Gists for your authenticated user
- kind: github/gistfrom: "user"to: /backups/gists/usercredentials: !Token "your_github_token"# Backup all Gists starred by the currently authenticated user
- kind: github/gistfrom: "starred"to: /backups/starred/gistscredentials: !Token "your_github_pat"# Backup public GitHub Gist of another user
- kind: github/gistfrom: "users/another-user"to: /backups/gists/another-user

Backing up to a Forgejo instance

In addition to writing backups to the local filesystem, the to field can describe a remote Forgejo instance. Repositories are mirrored using Forgejo's repository migration API, while release artifacts are uploaded as release attachments.

backups:
# Mirror a repository to a Forgejo instance
- kind: github/repofrom: repos/SierraSoftworks/github-backupto:
kind: forgejo/repoaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"# Upload release artifacts to a Forgejo instance
- kind: github/releasefrom: repos/SierraSoftworks/github-backupto:
kind: forgejo/releaseaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"filter: '!release.prerelease'

The owner field selects the Forgejo user or organization which should own the mirrored repositories (and host the releases). The credentials field accepts the same !Token and !UsernamePassword forms as GitHub credentials.

Backing up to multiple destinations

The to field also accepts a list of targets, allowing a single policy to mirror its source to several destinations at once. The source (for example the GitHub API) is queried only once, and each resulting repository or release is written to every configured target. You can freely mix filesystem paths and remote targets within the same list.

backups:
# Back up a repository to the local filesystem *and* a Forgejo instance
- kind: github/repofrom: repos/SierraSoftworks/github-backupto:
- /backups/github
- kind: forgejo/repoaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"

When to is omitted it defaults to a single ./backups filesystem target, and a single target (a path string or a remote map) continues to work exactly as before.

OpenTelemetry Reporting

In addition to the standard logging output, this tool also supports reporting metrics to an OpenTelemetry-compatible backend. This can be useful for tracking the performance of the tool over time and configuring monitoring in case backups start to fail.

Configuration is conducted through the use of environment variables:

OTEL_EXPORTER_OTLP_ENDPOINT=https://your-otel-collector:4317
OTEL_EXPORTER_OTLP_HEADERS=X-API-KEY=your-api-key
OTEL_TRACES_SAMPLER=traceidratio
OTEL_TRACES_SAMPLER_ARG=1.0

Cron Monitoring

If you run this tool on a schedule, you'll often want to be alerted when a backup run fails to start or complete. To support this, GitHub Backup can report the state of each scheduled run to an HTTP-based cron monitoring service such as Sentry Cron Monitors or healthchecks.io.

Monitoring is configured under the top-level ping key, where you can provide a separate URL for each state you care about. Each URL is fetched with a simple HTTP GET request when the corresponding state is reached, and any state you omit is simply not reported.

ping:
# Fetched when a backup run starts.start: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=in_progress# Fetched when a backup run completes successfully.success: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=ok# Fetched when a backup run completes with one or more errors.failure: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=error

A run is reported as a failure if any policy reports one or more errors, and as a success otherwise. Reporting is best-effort: if the monitoring service can't be reached, a warning is logged but the backup run itself is unaffected.

Filters

This tool allows you to configure filters to control which GitHub repositories are backed up and which are not. Filters are used within the backups section of your configuration file and can be specified on a per-user or per-organization basis.

When writing a filter, the goal is to write a logical expression which evaluates to true when you wish to include a repository and false when you wish to exclude it. The filter language supports several operators and properties which can be used to control this process.

Available filters

For kind: github/repo and kind: github/star

FieldTypeDescription (Example)
repo.namestringThe name of the repository (Hello-World)
repo.fullnamestringThe full-name of the repository (octocat/Hello-World)
repo.privatebooleanWhether the repository is private
repo.publicbooleanWhether the repository is public
repo.forkbooleanWhether the repository is a fork
repo.sizeintegerThe size of the repository, in kilobytes (1024).
repo.archivedbooleanWhether the repository is archived
repo.disabledbooleanReturns whether or not this repository disabled
repo.default_branchstringThe default branch of the repository (main)
repo.emptybooleanWhether the repository is empty (When a repository is initially created, repo.empty is true)
repo.templatebooleanWhether this repository acts as a template that can be used to generate new repositories
repo.forksintegerThe number of times this repository is forked
repo.stargazersintegerThe number of people starred this repository

For kind: github/release

FieldTypeDescription (Example)
release.tagstringThe name of the tag (v1.0.0)
release.namestringThe name of the release (v1.0.0)
release.draftbooleanWhether the release is a draft (unpublished) release
release.prereleasebooleanWhether to identify the release as a prerelease or a full release
release.publishedbooleanWhether the release is a published (not a draft) release
asset.namestringThe file name of the asset (github-backup-darwin-arm64)
asset.sizeintegerThe size of the asset, in kilobytes. (1024)
asset.downloadedbooleanIf the asset was downloaded at least once from the GitHub Release

For kind: github/gist

FieldTypeDescription
gist.publicbooleanWhether the gist is public
gist.privatebooleanWhether the gist is private
gist.comments_enabledbooleanWhether comments are enabled for the gist
gist.commentsintegerNumber of comments on the gist
gist.filesintegerNumber of files in the gist
gist.file_namesarrayList of file names in the gist
gist.languagesarrayList of programming languages used in the gist
gist.typestringType of content in the gist

Examples

Here are some examples of filters you might choose to use:

  • !repo.fork || !repo.archived || !repo.empty - Do not include repositories which are forks, archived, or empty.
  • repo.private - Only include private repositories in your list.
  • repo.public && !repo.fork - Only include public repositories which are not forks.
  • repo.name contains "awesome" - Only include repositories which have "awesome" in their name.
  • (repo.name contains "awesome" || repo.name contains "cool") && !repo.fork - Only include repositories which have "awesome" or "cool" in their name and are not forks.
  • !release.prerelease && !asset.source-code - Only include release artifacts which are not marked as pre-releases and are not source code archives.
  • repo.name in ["git-tool", "grey"] - Only include repositories with the names "git-tool" or "grey".
  • repo.stargazers >= 5 - Only include repositories with at least 5 stars.

About

Automatically backup your GitHub repositories

Topics

Resources

Stars

37 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

GitHub Backup

Automatically backup your GitHub repositories to your local machine.

This tool is designed to automatically pull the list of GitHub repositories from one, or more, GitHub organizations and clone (or fetch) them to your local machine. It is designed to be run as part of a scheduled backup process with the ultimate goal of ensuring that you have a local copy of all of your GitHub repositories should the unthinkable happen.

Installation

Install with Homebrew:

brew install sierrasoftworks/tap/github-backup

Features

  • Backup Multiple Organizations, automatically gathering the full list of repositories for each organization through the GitHub API.
  • Backup Starred Repos, automatically gathering the full list of your starred repositories
  • Repo Allowlists/Denylists to provide fine-grained control over which repositories are backed up and which are not.
  • GitHub Enterprise Support for those of you running your own GitHub instances and not relying on GitHub.com.

Example

# Run the tool directly
./github-backup --config config.yaml
# Or run it in a container
docker run \
-v $(pwd)/config.yaml:/config.yaml \
-v $(pwd)/backups:/backups \
ghcr.io/SierraSoftworks/github-backup:latest \
--config /config.yaml

Configuration

# Run a backup every hour (will use `git fetch` for existing copies)# You can also omit this if you want to run a one-shot backupschedule: "0 * * * *"backups:
- kind: github/repofrom: user # The user associated with the provided credentialsto: /backups/personalcredentials: !UsernamePassword { username: "<your username>", password: "<your personal access token>" }properties:
query: "affiliation=owner"# Additional query parameters to pass to GitHub when fetching repositories
- kind: github/repofrom: "users/another-user"to: /backups/friendcredentials: !Token "your_github_token"
- kind: github/repofrom: "orgs/my-org"to: /backups/workfilter: '!repo.fork && repo.name contains "awesome"'
- kind: github/releasefrom: "orgs/my-org"to: /backups/releasesfilter: '!release.prerelease && !asset.source-code'# You can also backup single repositories directly if you wish
- kind: github/repofrom: "repos/my-org/repo"to: /backups/work# This is particularly useful for backing up release artifacts for# specific projects.
- kind: github/releasefrom: "repos/my-org/repo"to: /backups/releasesfilter: '!release.prerelease'# Backup all repositories starred by the currently authenticated user
- kind: github/repofrom: "starred"to: /backups/starred/reposcredentials: !Token "your_github_pat"# Backup all GitHub Gists for your authenticated user
- kind: github/gistfrom: "user"to: /backups/gists/usercredentials: !Token "your_github_token"# Backup all Gists starred by the currently authenticated user
- kind: github/gistfrom: "starred"to: /backups/starred/gistscredentials: !Token "your_github_pat"# Backup public GitHub Gist of another user
- kind: github/gistfrom: "users/another-user"to: /backups/gists/another-user

Backing up to a Forgejo instance

In addition to writing backups to the local filesystem, the to field can describe a remote Forgejo instance. Repositories are mirrored using Forgejo's repository migration API, while release artifacts are uploaded as release attachments.

backups:
# Mirror a repository to a Forgejo instance
- kind: github/repofrom: repos/SierraSoftworks/github-backupto:
kind: forgejo/repoaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"# Upload release artifacts to a Forgejo instance
- kind: github/releasefrom: repos/SierraSoftworks/github-backupto:
kind: forgejo/releaseaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"filter: '!release.prerelease'

The owner field selects the Forgejo user or organization which should own the mirrored repositories (and host the releases). The credentials field accepts the same !Token and !UsernamePassword forms as GitHub credentials.

Backing up to multiple destinations

The to field also accepts a list of targets, allowing a single policy to mirror its source to several destinations at once. The source (for example the GitHub API) is queried only once, and each resulting repository or release is written to every configured target. You can freely mix filesystem paths and remote targets within the same list.

backups:
# Back up a repository to the local filesystem *and* a Forgejo instance
- kind: github/repofrom: repos/SierraSoftworks/github-backupto:
- /backups/github
- kind: forgejo/repoaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"

When to is omitted it defaults to a single ./backups filesystem target, and a single target (a path string or a remote map) continues to work exactly as before.

OpenTelemetry Reporting

In addition to the standard logging output, this tool also supports reporting metrics to an OpenTelemetry-compatible backend. This can be useful for tracking the performance of the tool over time and configuring monitoring in case backups start to fail.

Configuration is conducted through the use of environment variables:

OTEL_EXPORTER_OTLP_ENDPOINT=https://your-otel-collector:4317
OTEL_EXPORTER_OTLP_HEADERS=X-API-KEY=your-api-key
OTEL_TRACES_SAMPLER=traceidratio
OTEL_TRACES_SAMPLER_ARG=1.0

Cron Monitoring

If you run this tool on a schedule, you'll often want to be alerted when a backup run fails to start or complete. To support this, GitHub Backup can report the state of each scheduled run to an HTTP-based cron monitoring service such as Sentry Cron Monitors or healthchecks.io.

Monitoring is configured under the top-level ping key, where you can provide a separate URL for each state you care about. Each URL is fetched with a simple HTTP GET request when the corresponding state is reached, and any state you omit is simply not reported.

ping:
# Fetched when a backup run starts.start: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=in_progress# Fetched when a backup run completes successfully.success: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=ok# Fetched when a backup run completes with one or more errors.failure: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=error

A run is reported as a failure if any policy reports one or more errors, and as a success otherwise. Reporting is best-effort: if the monitoring service can't be reached, a warning is logged but the backup run itself is unaffected.

Filters

This tool allows you to configure filters to control which GitHub repositories are backed up and which are not. Filters are used within the backups section of your configuration file and can be specified on a per-user or per-organization basis.

When writing a filter, the goal is to write a logical expression which evaluates to true when you wish to include a repository and false when you wish to exclude it. The filter language supports several operators and properties which can be used to control this process.

Available filters

For kind: github/repo and kind: github/star

FieldTypeDescription (Example)
repo.namestringThe name of the repository (Hello-World)
repo.fullnamestringThe full-name of the repository (octocat/Hello-World)
repo.privatebooleanWhether the repository is private
repo.publicbooleanWhether the repository is public
repo.forkbooleanWhether the repository is a fork
repo.sizeintegerThe size of the repository, in kilobytes (1024).
repo.archivedbooleanWhether the repository is archived
repo.disabledbooleanReturns whether or not this repository disabled
repo.default_branchstringThe default branch of the repository (main)
repo.emptybooleanWhether the repository is empty (When a repository is initially created, repo.empty is true)
repo.templatebooleanWhether this repository acts as a template that can be used to generate new repositories
repo.forksintegerThe number of times this repository is forked
repo.stargazersintegerThe number of people starred this repository

For kind: github/release

FieldTypeDescription (Example)
release.tagstringThe name of the tag (v1.0.0)
release.namestringThe name of the release (v1.0.0)
release.draftbooleanWhether the release is a draft (unpublished) release
release.prereleasebooleanWhether to identify the release as a prerelease or a full release
release.publishedbooleanWhether the release is a published (not a draft) release
asset.namestringThe file name of the asset (github-backup-darwin-arm64)
asset.sizeintegerThe size of the asset, in kilobytes. (1024)
asset.downloadedbooleanIf the asset was downloaded at least once from the GitHub Release

For kind: github/gist

FieldTypeDescription
gist.publicbooleanWhether the gist is public
gist.privatebooleanWhether the gist is private
gist.comments_enabledbooleanWhether comments are enabled for the gist
gist.commentsintegerNumber of comments on the gist
gist.filesintegerNumber of files in the gist
gist.file_namesarrayList of file names in the gist
gist.languagesarrayList of programming languages used in the gist
gist.typestringType of content in the gist

Examples

Here are some examples of filters you might choose to use:

  • !repo.fork || !repo.archived || !repo.empty - Do not include repositories which are forks, archived, or empty.
  • repo.private - Only include private repositories in your list.
  • repo.public && !repo.fork - Only include public repositories which are not forks.
  • repo.name contains "awesome" - Only include repositories which have "awesome" in their name.
  • (repo.name contains "awesome" || repo.name contains "cool") && !repo.fork - Only include repositories which have "awesome" or "cool" in their name and are not forks.
  • !release.prerelease && !asset.source-code - Only include release artifacts which are not marked as pre-releases and are not source code archives.
  • repo.name in ["git-tool", "grey"] - Only include repositories with the names "git-tool" or "grey".
  • repo.stargazers >= 5 - Only include repositories with at least 5 stars.

About

Automatically backup your GitHub repositories

Topics

Resources

Stars

37 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

GitHub Backup

Automatically backup your GitHub repositories to your local machine.

This tool is designed to automatically pull the list of GitHub repositories from one, or more, GitHub organizations and clone (or fetch) them to your local machine. It is designed to be run as part of a scheduled backup process with the ultimate goal of ensuring that you have a local copy of all of your GitHub repositories should the unthinkable happen.

Installation

Install with Homebrew:

brew install sierrasoftworks/tap/github-backup

Features

  • Backup Multiple Organizations, automatically gathering the full list of repositories for each organization through the GitHub API.
  • Backup Starred Repos, automatically gathering the full list of your starred repositories
  • Repo Allowlists/Denylists to provide fine-grained control over which repositories are backed up and which are not.
  • GitHub Enterprise Support for those of you running your own GitHub instances and not relying on GitHub.com.

Example

# Run the tool directly
./github-backup --config config.yaml
# Or run it in a container
docker run \
-v $(pwd)/config.yaml:/config.yaml \
-v $(pwd)/backups:/backups \
ghcr.io/SierraSoftworks/github-backup:latest \
--config /config.yaml

Configuration

# Run a backup every hour (will use `git fetch` for existing copies)# You can also omit this if you want to run a one-shot backupschedule: "0 * * * *"backups:
- kind: github/repofrom: user # The user associated with the provided credentialsto: /backups/personalcredentials: !UsernamePassword { username: "<your username>", password: "<your personal access token>" }properties:
query: "affiliation=owner"# Additional query parameters to pass to GitHub when fetching repositories
- kind: github/repofrom: "users/another-user"to: /backups/friendcredentials: !Token "your_github_token"
- kind: github/repofrom: "orgs/my-org"to: /backups/workfilter: '!repo.fork && repo.name contains "awesome"'
- kind: github/releasefrom: "orgs/my-org"to: /backups/releasesfilter: '!release.prerelease && !asset.source-code'# You can also backup single repositories directly if you wish
- kind: github/repofrom: "repos/my-org/repo"to: /backups/work# This is particularly useful for backing up release artifacts for# specific projects.
- kind: github/releasefrom: "repos/my-org/repo"to: /backups/releasesfilter: '!release.prerelease'# Backup all repositories starred by the currently authenticated user
- kind: github/repofrom: "starred"to: /backups/starred/reposcredentials: !Token "your_github_pat"# Backup all GitHub Gists for your authenticated user
- kind: github/gistfrom: "user"to: /backups/gists/usercredentials: !Token "your_github_token"# Backup all Gists starred by the currently authenticated user
- kind: github/gistfrom: "starred"to: /backups/starred/gistscredentials: !Token "your_github_pat"# Backup public GitHub Gist of another user
- kind: github/gistfrom: "users/another-user"to: /backups/gists/another-user

Backing up to a Forgejo instance

In addition to writing backups to the local filesystem, the to field can describe a remote Forgejo instance. Repositories are mirrored using Forgejo's repository migration API, while release artifacts are uploaded as release attachments.

backups:
# Mirror a repository to a Forgejo instance
- kind: github/repofrom: repos/SierraSoftworks/github-backupto:
kind: forgejo/repoaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"# Upload release artifacts to a Forgejo instance
- kind: github/releasefrom: repos/SierraSoftworks/github-backupto:
kind: forgejo/releaseaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"filter: '!release.prerelease'

The owner field selects the Forgejo user or organization which should own the mirrored repositories (and host the releases). The credentials field accepts the same !Token and !UsernamePassword forms as GitHub credentials.

Backing up to multiple destinations

The to field also accepts a list of targets, allowing a single policy to mirror its source to several destinations at once. The source (for example the GitHub API) is queried only once, and each resulting repository or release is written to every configured target. You can freely mix filesystem paths and remote targets within the same list.

backups:
# Back up a repository to the local filesystem *and* a Forgejo instance
- kind: github/repofrom: repos/SierraSoftworks/github-backupto:
- /backups/github
- kind: forgejo/repoaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"

When to is omitted it defaults to a single ./backups filesystem target, and a single target (a path string or a remote map) continues to work exactly as before.

OpenTelemetry Reporting

In addition to the standard logging output, this tool also supports reporting metrics to an OpenTelemetry-compatible backend. This can be useful for tracking the performance of the tool over time and configuring monitoring in case backups start to fail.

Configuration is conducted through the use of environment variables:

OTEL_EXPORTER_OTLP_ENDPOINT=https://your-otel-collector:4317
OTEL_EXPORTER_OTLP_HEADERS=X-API-KEY=your-api-key
OTEL_TRACES_SAMPLER=traceidratio
OTEL_TRACES_SAMPLER_ARG=1.0

Cron Monitoring

If you run this tool on a schedule, you'll often want to be alerted when a backup run fails to start or complete. To support this, GitHub Backup can report the state of each scheduled run to an HTTP-based cron monitoring service such as Sentry Cron Monitors or healthchecks.io.

Monitoring is configured under the top-level ping key, where you can provide a separate URL for each state you care about. Each URL is fetched with a simple HTTP GET request when the corresponding state is reached, and any state you omit is simply not reported.

ping:
# Fetched when a backup run starts.start: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=in_progress# Fetched when a backup run completes successfully.success: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=ok# Fetched when a backup run completes with one or more errors.failure: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=error

A run is reported as a failure if any policy reports one or more errors, and as a success otherwise. Reporting is best-effort: if the monitoring service can't be reached, a warning is logged but the backup run itself is unaffected.

Filters

This tool allows you to configure filters to control which GitHub repositories are backed up and which are not. Filters are used within the backups section of your configuration file and can be specified on a per-user or per-organization basis.

When writing a filter, the goal is to write a logical expression which evaluates to true when you wish to include a repository and false when you wish to exclude it. The filter language supports several operators and properties which can be used to control this process.

Available filters

For kind: github/repo and kind: github/star

FieldTypeDescription (Example)
repo.namestringThe name of the repository (Hello-World)
repo.fullnamestringThe full-name of the repository (octocat/Hello-World)
repo.privatebooleanWhether the repository is private
repo.publicbooleanWhether the repository is public
repo.forkbooleanWhether the repository is a fork
repo.sizeintegerThe size of the repository, in kilobytes (1024).
repo.archivedbooleanWhether the repository is archived
repo.disabledbooleanReturns whether or not this repository disabled
repo.default_branchstringThe default branch of the repository (main)
repo.emptybooleanWhether the repository is empty (When a repository is initially created, repo.empty is true)
repo.templatebooleanWhether this repository acts as a template that can be used to generate new repositories
repo.forksintegerThe number of times this repository is forked
repo.stargazersintegerThe number of people starred this repository

For kind: github/release

FieldTypeDescription (Example)
release.tagstringThe name of the tag (v1.0.0)
release.namestringThe name of the release (v1.0.0)
release.draftbooleanWhether the release is a draft (unpublished) release
release.prereleasebooleanWhether to identify the release as a prerelease or a full release
release.publishedbooleanWhether the release is a published (not a draft) release
asset.namestringThe file name of the asset (github-backup-darwin-arm64)
asset.sizeintegerThe size of the asset, in kilobytes. (1024)
asset.downloadedbooleanIf the asset was downloaded at least once from the GitHub Release

For kind: github/gist

FieldTypeDescription
gist.publicbooleanWhether the gist is public
gist.privatebooleanWhether the gist is private
gist.comments_enabledbooleanWhether comments are enabled for the gist
gist.commentsintegerNumber of comments on the gist
gist.filesintegerNumber of files in the gist
gist.file_namesarrayList of file names in the gist
gist.languagesarrayList of programming languages used in the gist
gist.typestringType of content in the gist

Examples

Here are some examples of filters you might choose to use:

  • !repo.fork || !repo.archived || !repo.empty - Do not include repositories which are forks, archived, or empty.
  • repo.private - Only include private repositories in your list.
  • repo.public && !repo.fork - Only include public repositories which are not forks.
  • repo.name contains "awesome" - Only include repositories which have "awesome" in their name.
  • (repo.name contains "awesome" || repo.name contains "cool") && !repo.fork - Only include repositories which have "awesome" or "cool" in their name and are not forks.
  • !release.prerelease && !asset.source-code - Only include release artifacts which are not marked as pre-releases and are not source code archives.
  • repo.name in ["git-tool", "grey"] - Only include repositories with the names "git-tool" or "grey".
  • repo.stargazers >= 5 - Only include repositories with at least 5 stars.

About

Automatically backup your GitHub repositories

Topics

Resources

Stars

37 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

GitHub Backup

Automatically backup your GitHub repositories to your local machine.

This tool is designed to automatically pull the list of GitHub repositories from one, or more, GitHub organizations and clone (or fetch) them to your local machine. It is designed to be run as part of a scheduled backup process with the ultimate goal of ensuring that you have a local copy of all of your GitHub repositories should the unthinkable happen.

Installation

Install with Homebrew:

brew install sierrasoftworks/tap/github-backup

Features

  • Backup Multiple Organizations, automatically gathering the full list of repositories for each organization through the GitHub API.
  • Backup Starred Repos, automatically gathering the full list of your starred repositories
  • Repo Allowlists/Denylists to provide fine-grained control over which repositories are backed up and which are not.
  • GitHub Enterprise Support for those of you running your own GitHub instances and not relying on GitHub.com.

Example

# Run the tool directly
./github-backup --config config.yaml
# Or run it in a container
docker run \
-v $(pwd)/config.yaml:/config.yaml \
-v $(pwd)/backups:/backups \
ghcr.io/SierraSoftworks/github-backup:latest \
--config /config.yaml

Configuration

# Run a backup every hour (will use `git fetch` for existing copies)# You can also omit this if you want to run a one-shot backupschedule: "0 * * * *"backups:
- kind: github/repofrom: user # The user associated with the provided credentialsto: /backups/personalcredentials: !UsernamePassword { username: "<your username>", password: "<your personal access token>" }properties:
query: "affiliation=owner"# Additional query parameters to pass to GitHub when fetching repositories
- kind: github/repofrom: "users/another-user"to: /backups/friendcredentials: !Token "your_github_token"
- kind: github/repofrom: "orgs/my-org"to: /backups/workfilter: '!repo.fork && repo.name contains "awesome"'
- kind: github/releasefrom: "orgs/my-org"to: /backups/releasesfilter: '!release.prerelease && !asset.source-code'# You can also backup single repositories directly if you wish
- kind: github/repofrom: "repos/my-org/repo"to: /backups/work# This is particularly useful for backing up release artifacts for# specific projects.
- kind: github/releasefrom: "repos/my-org/repo"to: /backups/releasesfilter: '!release.prerelease'# Backup all repositories starred by the currently authenticated user
- kind: github/repofrom: "starred"to: /backups/starred/reposcredentials: !Token "your_github_pat"# Backup all GitHub Gists for your authenticated user
- kind: github/gistfrom: "user"to: /backups/gists/usercredentials: !Token "your_github_token"# Backup all Gists starred by the currently authenticated user
- kind: github/gistfrom: "starred"to: /backups/starred/gistscredentials: !Token "your_github_pat"# Backup public GitHub Gist of another user
- kind: github/gistfrom: "users/another-user"to: /backups/gists/another-user

Backing up to a Forgejo instance

In addition to writing backups to the local filesystem, the to field can describe a remote Forgejo instance. Repositories are mirrored using Forgejo's repository migration API, while release artifacts are uploaded as release attachments.

backups:
# Mirror a repository to a Forgejo instance
- kind: github/repofrom: repos/SierraSoftworks/github-backupto:
kind: forgejo/repoaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"# Upload release artifacts to a Forgejo instance
- kind: github/releasefrom: repos/SierraSoftworks/github-backupto:
kind: forgejo/releaseaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"filter: '!release.prerelease'

The owner field selects the Forgejo user or organization which should own the mirrored repositories (and host the releases). The credentials field accepts the same !Token and !UsernamePassword forms as GitHub credentials.

Backing up to multiple destinations

The to field also accepts a list of targets, allowing a single policy to mirror its source to several destinations at once. The source (for example the GitHub API) is queried only once, and each resulting repository or release is written to every configured target. You can freely mix filesystem paths and remote targets within the same list.

backups:
# Back up a repository to the local filesystem *and* a Forgejo instance
- kind: github/repofrom: repos/SierraSoftworks/github-backupto:
- /backups/github
- kind: forgejo/repoaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"

When to is omitted it defaults to a single ./backups filesystem target, and a single target (a path string or a remote map) continues to work exactly as before.

OpenTelemetry Reporting

In addition to the standard logging output, this tool also supports reporting metrics to an OpenTelemetry-compatible backend. This can be useful for tracking the performance of the tool over time and configuring monitoring in case backups start to fail.

Configuration is conducted through the use of environment variables:

OTEL_EXPORTER_OTLP_ENDPOINT=https://your-otel-collector:4317
OTEL_EXPORTER_OTLP_HEADERS=X-API-KEY=your-api-key
OTEL_TRACES_SAMPLER=traceidratio
OTEL_TRACES_SAMPLER_ARG=1.0

Cron Monitoring

If you run this tool on a schedule, you'll often want to be alerted when a backup run fails to start or complete. To support this, GitHub Backup can report the state of each scheduled run to an HTTP-based cron monitoring service such as Sentry Cron Monitors or healthchecks.io.

Monitoring is configured under the top-level ping key, where you can provide a separate URL for each state you care about. Each URL is fetched with a simple HTTP GET request when the corresponding state is reached, and any state you omit is simply not reported.

ping:
# Fetched when a backup run starts.start: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=in_progress# Fetched when a backup run completes successfully.success: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=ok# Fetched when a backup run completes with one or more errors.failure: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=error

A run is reported as a failure if any policy reports one or more errors, and as a success otherwise. Reporting is best-effort: if the monitoring service can't be reached, a warning is logged but the backup run itself is unaffected.

Filters

This tool allows you to configure filters to control which GitHub repositories are backed up and which are not. Filters are used within the backups section of your configuration file and can be specified on a per-user or per-organization basis.

When writing a filter, the goal is to write a logical expression which evaluates to true when you wish to include a repository and false when you wish to exclude it. The filter language supports several operators and properties which can be used to control this process.

Available filters

For kind: github/repo and kind: github/star

FieldTypeDescription (Example)
repo.namestringThe name of the repository (Hello-World)
repo.fullnamestringThe full-name of the repository (octocat/Hello-World)
repo.privatebooleanWhether the repository is private
repo.publicbooleanWhether the repository is public
repo.forkbooleanWhether the repository is a fork
repo.sizeintegerThe size of the repository, in kilobytes (1024).
repo.archivedbooleanWhether the repository is archived
repo.disabledbooleanReturns whether or not this repository disabled
repo.default_branchstringThe default branch of the repository (main)
repo.emptybooleanWhether the repository is empty (When a repository is initially created, repo.empty is true)
repo.templatebooleanWhether this repository acts as a template that can be used to generate new repositories
repo.forksintegerThe number of times this repository is forked
repo.stargazersintegerThe number of people starred this repository

For kind: github/release

FieldTypeDescription (Example)
release.tagstringThe name of the tag (v1.0.0)
release.namestringThe name of the release (v1.0.0)
release.draftbooleanWhether the release is a draft (unpublished) release
release.prereleasebooleanWhether to identify the release as a prerelease or a full release
release.publishedbooleanWhether the release is a published (not a draft) release
asset.namestringThe file name of the asset (github-backup-darwin-arm64)
asset.sizeintegerThe size of the asset, in kilobytes. (1024)
asset.downloadedbooleanIf the asset was downloaded at least once from the GitHub Release

For kind: github/gist

FieldTypeDescription
gist.publicbooleanWhether the gist is public
gist.privatebooleanWhether the gist is private
gist.comments_enabledbooleanWhether comments are enabled for the gist
gist.commentsintegerNumber of comments on the gist
gist.filesintegerNumber of files in the gist
gist.file_namesarrayList of file names in the gist
gist.languagesarrayList of programming languages used in the gist
gist.typestringType of content in the gist

Examples

Here are some examples of filters you might choose to use:

  • !repo.fork || !repo.archived || !repo.empty - Do not include repositories which are forks, archived, or empty.
  • repo.private - Only include private repositories in your list.
  • repo.public && !repo.fork - Only include public repositories which are not forks.
  • repo.name contains "awesome" - Only include repositories which have "awesome" in their name.
  • (repo.name contains "awesome" || repo.name contains "cool") && !repo.fork - Only include repositories which have "awesome" or "cool" in their name and are not forks.
  • !release.prerelease && !asset.source-code - Only include release artifacts which are not marked as pre-releases and are not source code archives.
  • repo.name in ["git-tool", "grey"] - Only include repositories with the names "git-tool" or "grey".
  • repo.stargazers >= 5 - Only include repositories with at least 5 stars.

About

Automatically backup your GitHub repositories

Topics

Resources

Stars

37 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

GitHub Backup

Automatically backup your GitHub repositories to your local machine.

This tool is designed to automatically pull the list of GitHub repositories from one, or more, GitHub organizations and clone (or fetch) them to your local machine. It is designed to be run as part of a scheduled backup process with the ultimate goal of ensuring that you have a local copy of all of your GitHub repositories should the unthinkable happen.

Installation

Install with Homebrew:

brew install sierrasoftworks/tap/github-backup

Features

  • Backup Multiple Organizations, automatically gathering the full list of repositories for each organization through the GitHub API.
  • Backup Starred Repos, automatically gathering the full list of your starred repositories
  • Repo Allowlists/Denylists to provide fine-grained control over which repositories are backed up and which are not.
  • GitHub Enterprise Support for those of you running your own GitHub instances and not relying on GitHub.com.

Example

# Run the tool directly
./github-backup --config config.yaml
# Or run it in a container
docker run \
-v $(pwd)/config.yaml:/config.yaml \
-v $(pwd)/backups:/backups \
ghcr.io/SierraSoftworks/github-backup:latest \
--config /config.yaml

Configuration

# Run a backup every hour (will use `git fetch` for existing copies)# You can also omit this if you want to run a one-shot backupschedule: "0 * * * *"backups:
- kind: github/repofrom: user # The user associated with the provided credentialsto: /backups/personalcredentials: !UsernamePassword { username: "<your username>", password: "<your personal access token>" }properties:
query: "affiliation=owner"# Additional query parameters to pass to GitHub when fetching repositories
- kind: github/repofrom: "users/another-user"to: /backups/friendcredentials: !Token "your_github_token"
- kind: github/repofrom: "orgs/my-org"to: /backups/workfilter: '!repo.fork && repo.name contains "awesome"'
- kind: github/releasefrom: "orgs/my-org"to: /backups/releasesfilter: '!release.prerelease && !asset.source-code'# You can also backup single repositories directly if you wish
- kind: github/repofrom: "repos/my-org/repo"to: /backups/work# This is particularly useful for backing up release artifacts for# specific projects.
- kind: github/releasefrom: "repos/my-org/repo"to: /backups/releasesfilter: '!release.prerelease'# Backup all repositories starred by the currently authenticated user
- kind: github/repofrom: "starred"to: /backups/starred/reposcredentials: !Token "your_github_pat"# Backup all GitHub Gists for your authenticated user
- kind: github/gistfrom: "user"to: /backups/gists/usercredentials: !Token "your_github_token"# Backup all Gists starred by the currently authenticated user
- kind: github/gistfrom: "starred"to: /backups/starred/gistscredentials: !Token "your_github_pat"# Backup public GitHub Gist of another user
- kind: github/gistfrom: "users/another-user"to: /backups/gists/another-user

Backing up to a Forgejo instance

In addition to writing backups to the local filesystem, the to field can describe a remote Forgejo instance. Repositories are mirrored using Forgejo's repository migration API, while release artifacts are uploaded as release attachments.

backups:
# Mirror a repository to a Forgejo instance
- kind: github/repofrom: repos/SierraSoftworks/github-backupto:
kind: forgejo/repoaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"# Upload release artifacts to a Forgejo instance
- kind: github/releasefrom: repos/SierraSoftworks/github-backupto:
kind: forgejo/releaseaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"filter: '!release.prerelease'

The owner field selects the Forgejo user or organization which should own the mirrored repositories (and host the releases). The credentials field accepts the same !Token and !UsernamePassword forms as GitHub credentials.

Backing up to multiple destinations

The to field also accepts a list of targets, allowing a single policy to mirror its source to several destinations at once. The source (for example the GitHub API) is queried only once, and each resulting repository or release is written to every configured target. You can freely mix filesystem paths and remote targets within the same list.

backups:
# Back up a repository to the local filesystem *and* a Forgejo instance
- kind: github/repofrom: repos/SierraSoftworks/github-backupto:
- /backups/github
- kind: forgejo/repoaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"

When to is omitted it defaults to a single ./backups filesystem target, and a single target (a path string or a remote map) continues to work exactly as before.

OpenTelemetry Reporting

In addition to the standard logging output, this tool also supports reporting metrics to an OpenTelemetry-compatible backend. This can be useful for tracking the performance of the tool over time and configuring monitoring in case backups start to fail.

Configuration is conducted through the use of environment variables:

OTEL_EXPORTER_OTLP_ENDPOINT=https://your-otel-collector:4317
OTEL_EXPORTER_OTLP_HEADERS=X-API-KEY=your-api-key
OTEL_TRACES_SAMPLER=traceidratio
OTEL_TRACES_SAMPLER_ARG=1.0

Cron Monitoring

If you run this tool on a schedule, you'll often want to be alerted when a backup run fails to start or complete. To support this, GitHub Backup can report the state of each scheduled run to an HTTP-based cron monitoring service such as Sentry Cron Monitors or healthchecks.io.

Monitoring is configured under the top-level ping key, where you can provide a separate URL for each state you care about. Each URL is fetched with a simple HTTP GET request when the corresponding state is reached, and any state you omit is simply not reported.

ping:
# Fetched when a backup run starts.start: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=in_progress# Fetched when a backup run completes successfully.success: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=ok# Fetched when a backup run completes with one or more errors.failure: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=error

A run is reported as a failure if any policy reports one or more errors, and as a success otherwise. Reporting is best-effort: if the monitoring service can't be reached, a warning is logged but the backup run itself is unaffected.

Filters

This tool allows you to configure filters to control which GitHub repositories are backed up and which are not. Filters are used within the backups section of your configuration file and can be specified on a per-user or per-organization basis.

When writing a filter, the goal is to write a logical expression which evaluates to true when you wish to include a repository and false when you wish to exclude it. The filter language supports several operators and properties which can be used to control this process.

Available filters

For kind: github/repo and kind: github/star

FieldTypeDescription (Example)
repo.namestringThe name of the repository (Hello-World)
repo.fullnamestringThe full-name of the repository (octocat/Hello-World)
repo.privatebooleanWhether the repository is private
repo.publicbooleanWhether the repository is public
repo.forkbooleanWhether the repository is a fork
repo.sizeintegerThe size of the repository, in kilobytes (1024).
repo.archivedbooleanWhether the repository is archived
repo.disabledbooleanReturns whether or not this repository disabled
repo.default_branchstringThe default branch of the repository (main)
repo.emptybooleanWhether the repository is empty (When a repository is initially created, repo.empty is true)
repo.templatebooleanWhether this repository acts as a template that can be used to generate new repositories
repo.forksintegerThe number of times this repository is forked
repo.stargazersintegerThe number of people starred this repository

For kind: github/release

FieldTypeDescription (Example)
release.tagstringThe name of the tag (v1.0.0)
release.namestringThe name of the release (v1.0.0)
release.draftbooleanWhether the release is a draft (unpublished) release
release.prereleasebooleanWhether to identify the release as a prerelease or a full release
release.publishedbooleanWhether the release is a published (not a draft) release
asset.namestringThe file name of the asset (github-backup-darwin-arm64)
asset.sizeintegerThe size of the asset, in kilobytes. (1024)
asset.downloadedbooleanIf the asset was downloaded at least once from the GitHub Release

For kind: github/gist

FieldTypeDescription
gist.publicbooleanWhether the gist is public
gist.privatebooleanWhether the gist is private
gist.comments_enabledbooleanWhether comments are enabled for the gist
gist.commentsintegerNumber of comments on the gist
gist.filesintegerNumber of files in the gist
gist.file_namesarrayList of file names in the gist
gist.languagesarrayList of programming languages used in the gist
gist.typestringType of content in the gist

Examples

Here are some examples of filters you might choose to use:

  • !repo.fork || !repo.archived || !repo.empty - Do not include repositories which are forks, archived, or empty.
  • repo.private - Only include private repositories in your list.
  • repo.public && !repo.fork - Only include public repositories which are not forks.
  • repo.name contains "awesome" - Only include repositories which have "awesome" in their name.
  • (repo.name contains "awesome" || repo.name contains "cool") && !repo.fork - Only include repositories which have "awesome" or "cool" in their name and are not forks.
  • !release.prerelease && !asset.source-code - Only include release artifacts which are not marked as pre-releases and are not source code archives.
  • repo.name in ["git-tool", "grey"] - Only include repositories with the names "git-tool" or "grey".
  • repo.stargazers >= 5 - Only include repositories with at least 5 stars.

About

Automatically backup your GitHub repositories

Topics

Resources

Stars

37 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

GitHub Backup

Automatically backup your GitHub repositories to your local machine.

This tool is designed to automatically pull the list of GitHub repositories from one, or more, GitHub organizations and clone (or fetch) them to your local machine. It is designed to be run as part of a scheduled backup process with the ultimate goal of ensuring that you have a local copy of all of your GitHub repositories should the unthinkable happen.

Installation

Install with Homebrew:

brew install sierrasoftworks/tap/github-backup

Features

  • Backup Multiple Organizations, automatically gathering the full list of repositories for each organization through the GitHub API.
  • Backup Starred Repos, automatically gathering the full list of your starred repositories
  • Repo Allowlists/Denylists to provide fine-grained control over which repositories are backed up and which are not.
  • GitHub Enterprise Support for those of you running your own GitHub instances and not relying on GitHub.com.

Example

# Run the tool directly
./github-backup --config config.yaml
# Or run it in a container
docker run \
-v $(pwd)/config.yaml:/config.yaml \
-v $(pwd)/backups:/backups \
ghcr.io/SierraSoftworks/github-backup:latest \
--config /config.yaml

Configuration

# Run a backup every hour (will use `git fetch` for existing copies)# You can also omit this if you want to run a one-shot backupschedule: "0 * * * *"backups:
- kind: github/repofrom: user # The user associated with the provided credentialsto: /backups/personalcredentials: !UsernamePassword { username: "<your username>", password: "<your personal access token>" }properties:
query: "affiliation=owner"# Additional query parameters to pass to GitHub when fetching repositories
- kind: github/repofrom: "users/another-user"to: /backups/friendcredentials: !Token "your_github_token"
- kind: github/repofrom: "orgs/my-org"to: /backups/workfilter: '!repo.fork && repo.name contains "awesome"'
- kind: github/releasefrom: "orgs/my-org"to: /backups/releasesfilter: '!release.prerelease && !asset.source-code'# You can also backup single repositories directly if you wish
- kind: github/repofrom: "repos/my-org/repo"to: /backups/work# This is particularly useful for backing up release artifacts for# specific projects.
- kind: github/releasefrom: "repos/my-org/repo"to: /backups/releasesfilter: '!release.prerelease'# Backup all repositories starred by the currently authenticated user
- kind: github/repofrom: "starred"to: /backups/starred/reposcredentials: !Token "your_github_pat"# Backup all GitHub Gists for your authenticated user
- kind: github/gistfrom: "user"to: /backups/gists/usercredentials: !Token "your_github_token"# Backup all Gists starred by the currently authenticated user
- kind: github/gistfrom: "starred"to: /backups/starred/gistscredentials: !Token "your_github_pat"# Backup public GitHub Gist of another user
- kind: github/gistfrom: "users/another-user"to: /backups/gists/another-user

Backing up to a Forgejo instance

In addition to writing backups to the local filesystem, the to field can describe a remote Forgejo instance. Repositories are mirrored using Forgejo's repository migration API, while release artifacts are uploaded as release attachments.

backups:
# Mirror a repository to a Forgejo instance
- kind: github/repofrom: repos/SierraSoftworks/github-backupto:
kind: forgejo/repoaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"# Upload release artifacts to a Forgejo instance
- kind: github/releasefrom: repos/SierraSoftworks/github-backupto:
kind: forgejo/releaseaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"filter: '!release.prerelease'

The owner field selects the Forgejo user or organization which should own the mirrored repositories (and host the releases). The credentials field accepts the same !Token and !UsernamePassword forms as GitHub credentials.

Backing up to multiple destinations

The to field also accepts a list of targets, allowing a single policy to mirror its source to several destinations at once. The source (for example the GitHub API) is queried only once, and each resulting repository or release is written to every configured target. You can freely mix filesystem paths and remote targets within the same list.

backups:
# Back up a repository to the local filesystem *and* a Forgejo instance
- kind: github/repofrom: repos/SierraSoftworks/github-backupto:
- /backups/github
- kind: forgejo/repoaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"

When to is omitted it defaults to a single ./backups filesystem target, and a single target (a path string or a remote map) continues to work exactly as before.

OpenTelemetry Reporting

In addition to the standard logging output, this tool also supports reporting metrics to an OpenTelemetry-compatible backend. This can be useful for tracking the performance of the tool over time and configuring monitoring in case backups start to fail.

Configuration is conducted through the use of environment variables:

OTEL_EXPORTER_OTLP_ENDPOINT=https://your-otel-collector:4317
OTEL_EXPORTER_OTLP_HEADERS=X-API-KEY=your-api-key
OTEL_TRACES_SAMPLER=traceidratio
OTEL_TRACES_SAMPLER_ARG=1.0

Cron Monitoring

If you run this tool on a schedule, you'll often want to be alerted when a backup run fails to start or complete. To support this, GitHub Backup can report the state of each scheduled run to an HTTP-based cron monitoring service such as Sentry Cron Monitors or healthchecks.io.

Monitoring is configured under the top-level ping key, where you can provide a separate URL for each state you care about. Each URL is fetched with a simple HTTP GET request when the corresponding state is reached, and any state you omit is simply not reported.

ping:
# Fetched when a backup run starts.start: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=in_progress# Fetched when a backup run completes successfully.success: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=ok# Fetched when a backup run completes with one or more errors.failure: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=error

A run is reported as a failure if any policy reports one or more errors, and as a success otherwise. Reporting is best-effort: if the monitoring service can't be reached, a warning is logged but the backup run itself is unaffected.

Filters

This tool allows you to configure filters to control which GitHub repositories are backed up and which are not. Filters are used within the backups section of your configuration file and can be specified on a per-user or per-organization basis.

When writing a filter, the goal is to write a logical expression which evaluates to true when you wish to include a repository and false when you wish to exclude it. The filter language supports several operators and properties which can be used to control this process.

Available filters

For kind: github/repo and kind: github/star

FieldTypeDescription (Example)
repo.namestringThe name of the repository (Hello-World)
repo.fullnamestringThe full-name of the repository (octocat/Hello-World)
repo.privatebooleanWhether the repository is private
repo.publicbooleanWhether the repository is public
repo.forkbooleanWhether the repository is a fork
repo.sizeintegerThe size of the repository, in kilobytes (1024).
repo.archivedbooleanWhether the repository is archived
repo.disabledbooleanReturns whether or not this repository disabled
repo.default_branchstringThe default branch of the repository (main)
repo.emptybooleanWhether the repository is empty (When a repository is initially created, repo.empty is true)
repo.templatebooleanWhether this repository acts as a template that can be used to generate new repositories
repo.forksintegerThe number of times this repository is forked
repo.stargazersintegerThe number of people starred this repository

For kind: github/release

FieldTypeDescription (Example)
release.tagstringThe name of the tag (v1.0.0)
release.namestringThe name of the release (v1.0.0)
release.draftbooleanWhether the release is a draft (unpublished) release
release.prereleasebooleanWhether to identify the release as a prerelease or a full release
release.publishedbooleanWhether the release is a published (not a draft) release
asset.namestringThe file name of the asset (github-backup-darwin-arm64)
asset.sizeintegerThe size of the asset, in kilobytes. (1024)
asset.downloadedbooleanIf the asset was downloaded at least once from the GitHub Release

For kind: github/gist

FieldTypeDescription
gist.publicbooleanWhether the gist is public
gist.privatebooleanWhether the gist is private
gist.comments_enabledbooleanWhether comments are enabled for the gist
gist.commentsintegerNumber of comments on the gist
gist.filesintegerNumber of files in the gist
gist.file_namesarrayList of file names in the gist
gist.languagesarrayList of programming languages used in the gist
gist.typestringType of content in the gist

Examples

Here are some examples of filters you might choose to use:

  • !repo.fork || !repo.archived || !repo.empty - Do not include repositories which are forks, archived, or empty.
  • repo.private - Only include private repositories in your list.
  • repo.public && !repo.fork - Only include public repositories which are not forks.
  • repo.name contains "awesome" - Only include repositories which have "awesome" in their name.
  • (repo.name contains "awesome" || repo.name contains "cool") && !repo.fork - Only include repositories which have "awesome" or "cool" in their name and are not forks.
  • !release.prerelease && !asset.source-code - Only include release artifacts which are not marked as pre-releases and are not source code archives.
  • repo.name in ["git-tool", "grey"] - Only include repositories with the names "git-tool" or "grey".
  • repo.stargazers >= 5 - Only include repositories with at least 5 stars.

About

Automatically backup your GitHub repositories

Topics

Resources

Stars

37 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

GitHub Backup

Automatically backup your GitHub repositories to your local machine.

This tool is designed to automatically pull the list of GitHub repositories from one, or more, GitHub organizations and clone (or fetch) them to your local machine. It is designed to be run as part of a scheduled backup process with the ultimate goal of ensuring that you have a local copy of all of your GitHub repositories should the unthinkable happen.

Installation

Install with Homebrew:

brew install sierrasoftworks/tap/github-backup

Features

  • Backup Multiple Organizations, automatically gathering the full list of repositories for each organization through the GitHub API.
  • Backup Starred Repos, automatically gathering the full list of your starred repositories
  • Repo Allowlists/Denylists to provide fine-grained control over which repositories are backed up and which are not.
  • GitHub Enterprise Support for those of you running your own GitHub instances and not relying on GitHub.com.

Example

# Run the tool directly
./github-backup --config config.yaml
# Or run it in a container
docker run \
-v $(pwd)/config.yaml:/config.yaml \
-v $(pwd)/backups:/backups \
ghcr.io/SierraSoftworks/github-backup:latest \
--config /config.yaml

Configuration

# Run a backup every hour (will use `git fetch` for existing copies)# You can also omit this if you want to run a one-shot backupschedule: "0 * * * *"backups:
- kind: github/repofrom: user # The user associated with the provided credentialsto: /backups/personalcredentials: !UsernamePassword { username: "<your username>", password: "<your personal access token>" }properties:
query: "affiliation=owner"# Additional query parameters to pass to GitHub when fetching repositories
- kind: github/repofrom: "users/another-user"to: /backups/friendcredentials: !Token "your_github_token"
- kind: github/repofrom: "orgs/my-org"to: /backups/workfilter: '!repo.fork && repo.name contains "awesome"'
- kind: github/releasefrom: "orgs/my-org"to: /backups/releasesfilter: '!release.prerelease && !asset.source-code'# You can also backup single repositories directly if you wish
- kind: github/repofrom: "repos/my-org/repo"to: /backups/work# This is particularly useful for backing up release artifacts for# specific projects.
- kind: github/releasefrom: "repos/my-org/repo"to: /backups/releasesfilter: '!release.prerelease'# Backup all repositories starred by the currently authenticated user
- kind: github/repofrom: "starred"to: /backups/starred/reposcredentials: !Token "your_github_pat"# Backup all GitHub Gists for your authenticated user
- kind: github/gistfrom: "user"to: /backups/gists/usercredentials: !Token "your_github_token"# Backup all Gists starred by the currently authenticated user
- kind: github/gistfrom: "starred"to: /backups/starred/gistscredentials: !Token "your_github_pat"# Backup public GitHub Gist of another user
- kind: github/gistfrom: "users/another-user"to: /backups/gists/another-user

Backing up to a Forgejo instance

In addition to writing backups to the local filesystem, the to field can describe a remote Forgejo instance. Repositories are mirrored using Forgejo's repository migration API, while release artifacts are uploaded as release attachments.

backups:
# Mirror a repository to a Forgejo instance
- kind: github/repofrom: repos/SierraSoftworks/github-backupto:
kind: forgejo/repoaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"# Upload release artifacts to a Forgejo instance
- kind: github/releasefrom: repos/SierraSoftworks/github-backupto:
kind: forgejo/releaseaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"filter: '!release.prerelease'

The owner field selects the Forgejo user or organization which should own the mirrored repositories (and host the releases). The credentials field accepts the same !Token and !UsernamePassword forms as GitHub credentials.

Backing up to multiple destinations

The to field also accepts a list of targets, allowing a single policy to mirror its source to several destinations at once. The source (for example the GitHub API) is queried only once, and each resulting repository or release is written to every configured target. You can freely mix filesystem paths and remote targets within the same list.

backups:
# Back up a repository to the local filesystem *and* a Forgejo instance
- kind: github/repofrom: repos/SierraSoftworks/github-backupto:
- /backups/github
- kind: forgejo/repoaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"

When to is omitted it defaults to a single ./backups filesystem target, and a single target (a path string or a remote map) continues to work exactly as before.

OpenTelemetry Reporting

In addition to the standard logging output, this tool also supports reporting metrics to an OpenTelemetry-compatible backend. This can be useful for tracking the performance of the tool over time and configuring monitoring in case backups start to fail.

Configuration is conducted through the use of environment variables:

OTEL_EXPORTER_OTLP_ENDPOINT=https://your-otel-collector:4317
OTEL_EXPORTER_OTLP_HEADERS=X-API-KEY=your-api-key
OTEL_TRACES_SAMPLER=traceidratio
OTEL_TRACES_SAMPLER_ARG=1.0

Cron Monitoring

If you run this tool on a schedule, you'll often want to be alerted when a backup run fails to start or complete. To support this, GitHub Backup can report the state of each scheduled run to an HTTP-based cron monitoring service such as Sentry Cron Monitors or healthchecks.io.

Monitoring is configured under the top-level ping key, where you can provide a separate URL for each state you care about. Each URL is fetched with a simple HTTP GET request when the corresponding state is reached, and any state you omit is simply not reported.

ping:
# Fetched when a backup run starts.start: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=in_progress# Fetched when a backup run completes successfully.success: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=ok# Fetched when a backup run completes with one or more errors.failure: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=error

A run is reported as a failure if any policy reports one or more errors, and as a success otherwise. Reporting is best-effort: if the monitoring service can't be reached, a warning is logged but the backup run itself is unaffected.

Filters

This tool allows you to configure filters to control which GitHub repositories are backed up and which are not. Filters are used within the backups section of your configuration file and can be specified on a per-user or per-organization basis.

When writing a filter, the goal is to write a logical expression which evaluates to true when you wish to include a repository and false when you wish to exclude it. The filter language supports several operators and properties which can be used to control this process.

Available filters

For kind: github/repo and kind: github/star

FieldTypeDescription (Example)
repo.namestringThe name of the repository (Hello-World)
repo.fullnamestringThe full-name of the repository (octocat/Hello-World)
repo.privatebooleanWhether the repository is private
repo.publicbooleanWhether the repository is public
repo.forkbooleanWhether the repository is a fork
repo.sizeintegerThe size of the repository, in kilobytes (1024).
repo.archivedbooleanWhether the repository is archived
repo.disabledbooleanReturns whether or not this repository disabled
repo.default_branchstringThe default branch of the repository (main)
repo.emptybooleanWhether the repository is empty (When a repository is initially created, repo.empty is true)
repo.templatebooleanWhether this repository acts as a template that can be used to generate new repositories
repo.forksintegerThe number of times this repository is forked
repo.stargazersintegerThe number of people starred this repository

For kind: github/release

FieldTypeDescription (Example)
release.tagstringThe name of the tag (v1.0.0)
release.namestringThe name of the release (v1.0.0)
release.draftbooleanWhether the release is a draft (unpublished) release
release.prereleasebooleanWhether to identify the release as a prerelease or a full release
release.publishedbooleanWhether the release is a published (not a draft) release
asset.namestringThe file name of the asset (github-backup-darwin-arm64)
asset.sizeintegerThe size of the asset, in kilobytes. (1024)
asset.downloadedbooleanIf the asset was downloaded at least once from the GitHub Release

For kind: github/gist

FieldTypeDescription
gist.publicbooleanWhether the gist is public
gist.privatebooleanWhether the gist is private
gist.comments_enabledbooleanWhether comments are enabled for the gist
gist.commentsintegerNumber of comments on the gist
gist.filesintegerNumber of files in the gist
gist.file_namesarrayList of file names in the gist
gist.languagesarrayList of programming languages used in the gist
gist.typestringType of content in the gist

Examples

Here are some examples of filters you might choose to use:

  • !repo.fork || !repo.archived || !repo.empty - Do not include repositories which are forks, archived, or empty.
  • repo.private - Only include private repositories in your list.
  • repo.public && !repo.fork - Only include public repositories which are not forks.
  • repo.name contains "awesome" - Only include repositories which have "awesome" in their name.
  • (repo.name contains "awesome" || repo.name contains "cool") && !repo.fork - Only include repositories which have "awesome" or "cool" in their name and are not forks.
  • !release.prerelease && !asset.source-code - Only include release artifacts which are not marked as pre-releases and are not source code archives.
  • repo.name in ["git-tool", "grey"] - Only include repositories with the names "git-tool" or "grey".
  • repo.stargazers >= 5 - Only include repositories with at least 5 stars.

About

Automatically backup your GitHub repositories

Topics

Resources

Stars

37 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

GitHub Backup

Automatically backup your GitHub repositories to your local machine.

This tool is designed to automatically pull the list of GitHub repositories from one, or more, GitHub organizations and clone (or fetch) them to your local machine. It is designed to be run as part of a scheduled backup process with the ultimate goal of ensuring that you have a local copy of all of your GitHub repositories should the unthinkable happen.

Installation

Install with Homebrew:

brew install sierrasoftworks/tap/github-backup

Features

  • Backup Multiple Organizations, automatically gathering the full list of repositories for each organization through the GitHub API.
  • Backup Starred Repos, automatically gathering the full list of your starred repositories
  • Repo Allowlists/Denylists to provide fine-grained control over which repositories are backed up and which are not.
  • GitHub Enterprise Support for those of you running your own GitHub instances and not relying on GitHub.com.

Example

# Run the tool directly
./github-backup --config config.yaml
# Or run it in a container
docker run \
-v $(pwd)/config.yaml:/config.yaml \
-v $(pwd)/backups:/backups \
ghcr.io/SierraSoftworks/github-backup:latest \
--config /config.yaml

Configuration

# Run a backup every hour (will use `git fetch` for existing copies)# You can also omit this if you want to run a one-shot backupschedule: "0 * * * *"backups:
- kind: github/repofrom: user # The user associated with the provided credentialsto: /backups/personalcredentials: !UsernamePassword { username: "<your username>", password: "<your personal access token>" }properties:
query: "affiliation=owner"# Additional query parameters to pass to GitHub when fetching repositories
- kind: github/repofrom: "users/another-user"to: /backups/friendcredentials: !Token "your_github_token"
- kind: github/repofrom: "orgs/my-org"to: /backups/workfilter: '!repo.fork && repo.name contains "awesome"'
- kind: github/releasefrom: "orgs/my-org"to: /backups/releasesfilter: '!release.prerelease && !asset.source-code'# You can also backup single repositories directly if you wish
- kind: github/repofrom: "repos/my-org/repo"to: /backups/work# This is particularly useful for backing up release artifacts for# specific projects.
- kind: github/releasefrom: "repos/my-org/repo"to: /backups/releasesfilter: '!release.prerelease'# Backup all repositories starred by the currently authenticated user
- kind: github/repofrom: "starred"to: /backups/starred/reposcredentials: !Token "your_github_pat"# Backup all GitHub Gists for your authenticated user
- kind: github/gistfrom: "user"to: /backups/gists/usercredentials: !Token "your_github_token"# Backup all Gists starred by the currently authenticated user
- kind: github/gistfrom: "starred"to: /backups/starred/gistscredentials: !Token "your_github_pat"# Backup public GitHub Gist of another user
- kind: github/gistfrom: "users/another-user"to: /backups/gists/another-user

Backing up to a Forgejo instance

In addition to writing backups to the local filesystem, the to field can describe a remote Forgejo instance. Repositories are mirrored using Forgejo's repository migration API, while release artifacts are uploaded as release attachments.

backups:
# Mirror a repository to a Forgejo instance
- kind: github/repofrom: repos/SierraSoftworks/github-backupto:
kind: forgejo/repoaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"# Upload release artifacts to a Forgejo instance
- kind: github/releasefrom: repos/SierraSoftworks/github-backupto:
kind: forgejo/releaseaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"filter: '!release.prerelease'

The owner field selects the Forgejo user or organization which should own the mirrored repositories (and host the releases). The credentials field accepts the same !Token and !UsernamePassword forms as GitHub credentials.

Backing up to multiple destinations

The to field also accepts a list of targets, allowing a single policy to mirror its source to several destinations at once. The source (for example the GitHub API) is queried only once, and each resulting repository or release is written to every configured target. You can freely mix filesystem paths and remote targets within the same list.

backups:
# Back up a repository to the local filesystem *and* a Forgejo instance
- kind: github/repofrom: repos/SierraSoftworks/github-backupto:
- /backups/github
- kind: forgejo/repoaddress: https://forgejo.example.comowner: backupscredentials: !Token "your_forgejo_access_token"

When to is omitted it defaults to a single ./backups filesystem target, and a single target (a path string or a remote map) continues to work exactly as before.

OpenTelemetry Reporting

In addition to the standard logging output, this tool also supports reporting metrics to an OpenTelemetry-compatible backend. This can be useful for tracking the performance of the tool over time and configuring monitoring in case backups start to fail.

Configuration is conducted through the use of environment variables:

OTEL_EXPORTER_OTLP_ENDPOINT=https://your-otel-collector:4317
OTEL_EXPORTER_OTLP_HEADERS=X-API-KEY=your-api-key
OTEL_TRACES_SAMPLER=traceidratio
OTEL_TRACES_SAMPLER_ARG=1.0

Cron Monitoring

If you run this tool on a schedule, you'll often want to be alerted when a backup run fails to start or complete. To support this, GitHub Backup can report the state of each scheduled run to an HTTP-based cron monitoring service such as Sentry Cron Monitors or healthchecks.io.

Monitoring is configured under the top-level ping key, where you can provide a separate URL for each state you care about. Each URL is fetched with a simple HTTP GET request when the corresponding state is reached, and any state you omit is simply not reported.

ping:
# Fetched when a backup run starts.start: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=in_progress# Fetched when a backup run completes successfully.success: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=ok# Fetched when a backup run completes with one or more errors.failure: https://sentry.io/api/0/organizations/your-org/monitors/github-backup/checkins/?status=error

A run is reported as a failure if any policy reports one or more errors, and as a success otherwise. Reporting is best-effort: if the monitoring service can't be reached, a warning is logged but the backup run itself is unaffected.

Filters

This tool allows you to configure filters to control which GitHub repositories are backed up and which are not. Filters are used within the backups section of your configuration file and can be specified on a per-user or per-organization basis.

When writing a filter, the goal is to write a logical expression which evaluates to true when you wish to include a repository and false when you wish to exclude it. The filter language supports several operators and properties which can be used to control this process.

Available filters

For kind: github/repo and kind: github/star

FieldTypeDescription (Example)
repo.namestringThe name of the repository (Hello-World)
repo.fullnamestringThe full-name of the repository (octocat/Hello-World)
repo.privatebooleanWhether the repository is private
repo.publicbooleanWhether the repository is public
repo.forkbooleanWhether the repository is a fork
repo.sizeintegerThe size of the repository, in kilobytes (1024).
repo.archivedbooleanWhether the repository is archived
repo.disabledbooleanReturns whether or not this repository disabled
repo.default_branchstringThe default branch of the repository (main)
repo.emptybooleanWhether the repository is empty (When a repository is initially created, repo.empty is true)
repo.templatebooleanWhether this repository acts as a template that can be used to generate new repositories
repo.forksintegerThe number of times this repository is forked
repo.stargazersintegerThe number of people starred this repository

For kind: github/release

FieldTypeDescription (Example)
release.tagstringThe name of the tag (v1.0.0)
release.namestringThe name of the release (v1.0.0)
release.draftbooleanWhether the release is a draft (unpublished) release
release.prereleasebooleanWhether to identify the release as a prerelease or a full release
release.publishedbooleanWhether the release is a published (not a draft) release
asset.namestringThe file name of the asset (github-backup-darwin-arm64)
asset.sizeintegerThe size of the asset, in kilobytes. (1024)
asset.downloadedbooleanIf the asset was downloaded at least once from the GitHub Release

For kind: github/gist

FieldTypeDescription
gist.publicbooleanWhether the gist is public
gist.privatebooleanWhether the gist is private
gist.comments_enabledbooleanWhether comments are enabled for the gist
gist.commentsintegerNumber of comments on the gist
gist.filesintegerNumber of files in the gist
gist.file_namesarrayList of file names in the gist
gist.languagesarrayList of programming languages used in the gist
gist.typestringType of content in the gist

Examples

Here are some examples of filters you might choose to use:

  • !repo.fork || !repo.archived || !repo.empty - Do not include repositories which are forks, archived, or empty.
  • repo.private - Only include private repositories in your list.
  • repo.public && !repo.fork - Only include public repositories which are not forks.
  • repo.name contains "awesome" - Only include repositories which have "awesome" in their name.
  • (repo.name contains "awesome" || repo.name contains "cool") && !repo.fork - Only include repositories which have "awesome" or "cool" in their name and are not forks.
  • !release.prerelease && !asset.source-code - Only include release artifacts which are not marked as pre-releases and are not source code archives.
  • repo.name in ["git-tool", "grey"] - Only include repositories with the names "git-tool" or "grey".
  • repo.stargazers >= 5 - Only include repositories with at least 5 stars.

About

Automatically backup your GitHub repositories

Topics

Resources

Stars

37 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages