Skip to main content
Code Storage can keep a repository in sync with an external Git host while still exposing the Code Storage remote to your tools, automations, and users. Use Git Sync when you want to:
  • mirror a repository from GitHub, GitLab, Bitbucket, Gitea, Forgejo, Codeberg, or SourceHut
  • push to Code Storage and have those writes forwarded to the upstream provider
  • keep using Code Storage APIs, JWT-backed remotes, ephemeral branches, and webhooks on the mirrored repo

Sync modes

Code Storage currently supports three Git Sync modes:
ModeBest forAuthentication
GitHub AppPrivate GitHub repositories and webhook-driven syncGitHub App installation token
Public GitHubPublic GitHub repositories you want to pull from without credentialsNo GitHub credentials
Generic HTTPS GitGitLab, Bitbucket, Gitea, Forgejo, Codeberg, SourceHut, and similar hostsStored username/password or token

GitHub App sync

GitHub has the most direct SDK flow today. Create the repository with a GitHub base, then call pullUpstream() whenever you want to force a refresh.
const repo = await store.createRepo({
  id: 'my-synced-repo',
  baseRepo: {
    owner: 'your-github-org',
    name: 'repository-name',
    defaultBranch: 'main',
  },
  defaultBranch: 'main',
});

await repo.pullUpstream();
Code Storage treats GitHub as the source of truth for synced repositories:
  • reads come from Code Storage
  • pushes to Code Storage are forwarded to GitHub
  • successful pushes trigger a background sync back into Code Storage storage nodes

Public GitHub mode

If the upstream repository is public, you can skip GitHub App auth and create a synced repository in public mode.
const repo = await store.createRepo({
  id: 'public-upstream-repo',
  baseRepo: {
    owner: 'octocat',
    name: 'hello-world',
    defaultBranch: 'main',
    auth: {
      authType: 'public',
    },
  },
});

await repo.pullUpstream();
Public mode is useful for templates and open-source repositories, but it is intentionally limited:
  • no GitHub App webhooks
  • no authenticated access to private repositories
  • no write-through pushes back to GitHub
Use GitHub Sync when you need ongoing bidirectional behavior with GitHub.

Generic HTTPS Git sync

Generic Git Sync covers named providers that authenticate over HTTPS using a username/password pair or a token:
  • gitlab
  • bitbucket
  • gitea
  • forgejo
  • codeberg
  • sr.ht or sourcehut
For some providers, Code Storage can derive the public upstream host automatically:
  • gitlab -> gitlab.com
  • bitbucket -> bitbucket.org
  • codeberg -> codeberg.org
  • sr.ht -> git.sr.ht
For self-hosted providers, and for providers without a fixed public host like gitea and forgejo, pass upstream_host when you create the repo.

Generic Git setup

Generic provider setup happens in three steps:
  1. create the Code Storage repository with a generic Git base
  2. store the HTTPS credential for that repo
  3. trigger an initial pull

1. Create the synced repository

This example creates a repository backed by GitLab. For self-hosted instances, include upstreamHost / upstream_host.
const repo = await store.createRepo({
  id: 'my-gitlab-repo',
  baseRepo: {
    provider: 'gitlab',
    owner: 'your-group',
    name: 'your-repo',
    defaultBranch: 'main',
  },
  defaultBranch: 'main',
});
For a self-hosted provider, add upstreamHost / upstream_host:
const repo = await store.createRepo({
  id: 'my-gitea-repo',
  baseRepo: {
    provider: 'gitea',
    owner: 'your-org',
    name: 'your-repo',
    defaultBranch: 'main',
    upstreamHost: 'git.example.com',
  },
  defaultBranch: 'main',
});
The response includes the internal repo_id. Use that value in the next step.

2. Store the Git credential

Create a credential record for the repository. username is optional for providers that accept a token on its own.
await store.createGitCredential({
  repoId: repo.id,
  username: 'john_doe',
  password: 'YOUR_ACCESS_TOKEN_OR_PASSWORD',
});

3. Trigger the initial pull

await repo.pullUpstream();

How Git Sync behaves

Once a repository is configured for Git Sync:
  • git clone, git fetch, and git pull read from Code Storage
  • repo.pullUpstream() and POST /api/v1/repos/pull-upstream trigger an async refresh from the configured provider
  • git push to the default remote is forwarded to the external Git host
  • successful pushes trigger background sync so Code Storage storage nodes stay current
This lets you keep Code Storage as the stable endpoint for your app while still mirroring changes to and from the external host.

Git Sync vs Forking vs Imports

WorkflowSourceOngoing connectionBest for
Git SyncExternal Git providerYesRepositories that should stay mirrored
ForkingCode Storage repositoryNoTemplates, snapshots, isolated copies
ImportsExternal or local Git repoNoOne-time ingestion and migration
Use Git Sync when the source repository should stay connected. Use Forking when you want an independent copy. Use Imports when you want a one-time push into Code Storage.