Skip to main content
Code Storage can keep a repository in sync with GitHub. Your tools, automations, and users still use the Code Storage remote. Git Sync mirrors the default-namespace branches and tags. It does not mirror ephemeral refs. Use GitHub Sync when you want to:
  • Mirror a repository from GitHub
  • Push to Code Storage and let Code Storage forward those writes to GitHub
  • Continue to use Code Storage APIs, JWT-backed remotes, ephemeral branches, and webhooks on the mirrored repository

Sync modes

Code Storage currently supports three Git Sync modes: This page covers the two GitHub modes. For every other host, see Generic Sync.

GitHub App sync

The SDK has a direct setup flow for GitHub App sync. Create the repository with a GitHub base. Call pullUpstream() when you must force a refresh.
How it works:
  • Code Storage links the repository to GitHub when you create it with baseRepo
  • pullUpstream() gets the latest changes from GitHub
  • All SDK features work with the synced content, such as diffs, commits, and file access
  • Code Storage sets the provider to "github" when baseRepo contains owner and name
Code Storage treats GitHub as the source of truth for synced repositories. Code Storage sends all pushes directly to GitHub. It then copies all changes back from GitHub. During the initial sync, API calls for the repository return a 409 Conflict:
Add retry logic for this response to your repository creation flow. Code Storage emits push webhook events after the initial sync finishes. After the initial sync, reads do not wait for later upstream syncs and may temporarily be stale. To read the latest upstream content, wait for the repo.sync.succeeded webhook.

Git LFS on GitHub App sync

GitHub App sync repositories support Git LFS over the same Code Storage remote:
  • Downloads: Code Storage serves an object that it already stores. If the object is absent, the LFS client gets it from GitHub. Code Storage copies the object in the background for the next request.
  • Uploads: The client sends object bytes directly to GitHub. Code Storage does not store the upload.
Public GitHub sync and generic HTTPS Git sync do not support LFS.

Public GitHub mode

If the upstream repository is public, you can skip GitHub App auth and create a synced repository in public mode.
Public mode runs one sync or import. It does not keep a continuous sync. Use it for templates and public repositories. Public mode has these limits:
  • Code Storage does not subscribe to GitHub webhooks
  • Code Storage does not keep a continuous, two-way sync with GitHub
  • Code Storage does not automatically copy changes from GitHub
  • Code Storage does not automatically send changes to GitHub
  • The GitHub repository must remain public. If it becomes private, use authenticated mode before you sync it again
Use GitHub App mode when you need a continuous, two-way sync with GitHub.

Public mode vs GitHub App sync

Set up a GitHub App

Set up a GitHub App before you enable GitHub App sync.
1

Create the app

Open Settings -> Developer settings -> GitHub Apps. Create a new GitHub App.
2

Set permissions

Repository permissions:
  • Metadata: Read (required)
  • Contents: Read for one-way sync from GitHub, or Read and write for bidirectional sync
  • Workflows: Read and write (only if pushes will change files under .github/workflows/)
Code Storage requests no fixed permission set when it creates an installation token. The connection uses the permissions that the installation grants. If a permission is absent, the related push fails. The setup can still succeed.
Webhook events:
  • Push
  • Create
  • Pull Request (optional, if you want PR sync)
To let Code Storage receive the events, use this webhook callback URL:
Or use your own handler.
3

Record credentials

Save these values for the Code Storage configuration:
  • GitHub App ID
  • Private Key
  • Webhook Secret

Automatic sync with webhooks

GitHub sends webhook events when the repository changes. Handle the events in your service, or let Code Storage handle them.

Option A: handle webhooks yourself

To use your own webhook handler, set the callback URL to its endpoint. Process each GitHub event. Call Code Storage as necessary.
Call repo.pullUpstream() from your handler to start a GitHub sync. GitHub sends the x-hub-signature-256 header. GitHub uses your GitHub App webhook secret to sign the payload. Use the GitHub documentation to check this signature. Code Storage also sends events for pushes and each sync stage. See Webhooks for the event list, payloads, headers, and HMAC check.

Option B: let Code Storage handle webhooks

If you do not want to run your own webhook handler:
  1. In your GitHub App settings, set the webhook URL to https://[your-organization].code.storage/webhooks/github
  2. Generate a webhook secret and save it.
  3. In the Code Storage dashboard, open the Integrations tab.
  4. Enter your webhook secret and save it.
Code Storage receives GitHub events and starts syncs automatically.

How Git Sync behaves

After you configure Git Sync, these rules apply:
  • git clone, git fetch, and git pull read from Code Storage
  • repo.pullUpstream() and POST /api/repos/{repo_name}/pull-upstream start an asynchronous refresh from GitHub
  • Code Storage forwards each git push to GitHub
  • A successful push starts a background sync to keep the Code Storage nodes current
Your app can use Code Storage as its stable endpoint. Code Storage still copies changes to and from GitHub. Only pushes to the normal remote reach GitHub. Pushes to the +ephemeral remote stay in Code Storage. A sync from GitHub copies only refs/heads/* and refs/tags/*. Put machine state on ephemeral branches to keep it out of GitHub. Machine state includes agent snapshots, preview builds, and scratch commits. Git LFS is the exception on GitHub App sync repositories: LFS uploads pass through to GitHub from every ref, ephemeral refs included.

Support

For help, email jacob@pierre.co.