BusinessFramework16 min readPublished August 17, 2026

Ten layers inventoried · 1 fully portable · coexistence is the realistic near-term pattern

What Moving Off GitHub Actually Costs

Cursor’s Origin entered early beta today, and the “should we leave GitHub” conversation restarted on cue. So we did the boring, accurate thing: read GitHub’s own documentation layer by layer and recorded which parts of a GitHub footprint live in git, which live in GitHub’s account infrastructure, and which live on a third party’s side of a trust relationship. The result is an inventory and a decision frame — not a migration pitch.

DA
Digital Applied Team
Senior strategists · Published Aug 17, 2026
PublishedAugust 17, 2026
Read time16 min
Sources14 primary docs
Layers inventoried
10
verified against vendor docs
Fully portable layers
1
git history — a clone carries it
Rulesets per repository
75
GitHub’s documented cap
config outside git
GitLab import ceiling
~30K
comments per repo, skipped by default
documented loss

The cost of migrating off GitHub has almost nothing to do with moving your code. Git was designed to be portable — a clone carries every commit, every branch, every tag, and a push deposits all of it on any host you point it at. The bill sits in everything built around the repository: CI workflows and the runners that execute them, package registries, deploy integrations and their OIDC trust relationships, branch-protection rules, years of issue and pull-request history, installed apps and webhooks, code-owner enforcement, and single sign-on wiring.

This matters today because teams have a concrete, news-driven reason to ask the question. Cursor’s Origin code hosting entered early beta on Monday, August 17, 2026, rolling out on all paid plans — and notably, its own release keeps GitHub as the source of truth for synced repos rather than asking anyone to leave. That design choice is itself evidence about where the switching costs sit.

What follows is an inventory, not a pitch. We read GitHub’s own documentation for each layer of a typical footprint, recorded where each one physically lives, and judged honestly which are portable, which are re-buildable, and which never leave. We deliberately publish no cost figures, hour estimates, or team-size thresholds — any such number would be invented. The deliverable is a grid you can hold your own footprint against, and a decision frame for what to do about it.

Key takeaways
  1. 01
    Git history is the one layer that leaves cleanly.A clone or push carries full source and commit history to any host. Of the ten layers we inventoried against GitHub’s own docs, it is the only one that is portable in full, function included.
  2. 02
    Most of the footprint is settings, not files.Branch rulesets, environments, secrets, webhook registrations, app installations and SSO enforcement are account or org settings in GitHub’s infrastructure — GitHub’s docs state directly that environments are stored outside version control history.
  3. 03
    Deploy trust is bound to GitHub’s identity, by design.OIDC trust relationships on AWS, Azure or GCP are configured against subject claims naming a specific GitHub org and repo. Our inference from that binding: moving hosts means reconfiguring trust on the cloud-provider side — there is nothing to copy.
  4. 04
    The richest importer we checked still documents its losses.Of the three importer pages we checked, GitLab’s is by far the most detailed. It moves issues, PRs, reviews, labels and milestones — and names what it drops: the required-status-checks rule is not imported, and comments beyond roughly 30,000 per repo are skipped by default.
  5. 05
    For most teams, coexistence beats migration.Origin’s own release describes two-way sync with GitHub, not replacement. Unless a contract or sovereignty mandate forces a move, the realistic near-term pattern is running both — with GitHub as source of truth.

01The News PegWhy this question, today.

The trigger is simple: a credible new code host shipped today. Cursor’s changelog states that “Origin begins rolling out today in early beta on all paid plans” — and our companion piece, our coverage of Origin’s early-beta launch, covers the release itself, so this post stays on the economics.

What makes the release relevant to a cost analysis is one sentence of Cursor’s own copy: for repos synced from GitHub, “pushes keep going to GitHub, which stays the source of truth for anything started there.” A vendor with every incentive to move workloads onto its own infrastructure chose two-way sync over migration as the on-ramp. That is not modesty; it is an engineering reading of the same inventory this post lays out. The git data is easy to sync. Everything else is not, so the product syncs the git data and leaves everything else where it is.

When a credible new host launches, teams start asking “what would it take to move?” The honest answer requires separating three different kinds of cost, layer by layer: things that travel with the repository, things that must be rebuilt by hand on the other side, and things that are not properties of the code at all and simply get reconstructed from zero. Vendor marketing tends to blur those categories. GitHub’s own documentation, read carefully, does not.

What shipped, in one paragraph
Per Cursor’s changelog, published the day of this writing: Origin is in early beta on all paid plans, with repos, pull requests, code browsing and two-way GitHub sync — “comment in Cursor and it posts to GitHub, react or reply on GitHub and it shows up in Cursor within seconds” — plus CLI push and clone. Cursor’s own copy says “Agent-native features ship soon,” so the agent-native part is explicitly not in this release, and no separate Origin price was stated on the changelog page we checked.

02The Easy PartWhat a git clone actually carries.

Start with what genuinely moves. A git clone followed by a git push to a new remote carries the complete object database: every commit with its full history, every branch, every tag, and every file at every revision. This is not a migration feature any vendor built — it is the design of git itself, which predates GitHub and treats every full clone as a peer. Nothing about this layer requires an importer, an API, or anyone’s permission.

A few configuration files ride along because they live inside the repository. GitHub Actions workflow definitions are YAML files in the repo’s .github/workflows directory, per GitHub’s own Actions documentation. CODEOWNERS is a plain file at .github/CODEOWNERS, the repo root, or docs/CODEOWNERS, mapping paths to reviewers with gitignore-style patterns. Both travel with a clone byte-for-byte.

Here is the trap: the files travel, but their function does not. A workflow YAML on a host with no Actions-compatible runner is inert text. A CODEOWNERS file only has teeth when branch protection or a ruleset requires code-owner approval — and that enforcement, per GitHub’s docs, is a repository setting layered on top of the file, not part of the file. The pattern repeats across the whole inventory: the closer a thing sits to git’s object database, the more portable it is; the closer it sits to GitHub’s account model, the less.

03The InventoryTen layers, three verdicts.

The grid below is the core of this post. Each row is one layer of a typical GitHub footprint. The “where it lives” column is sourced from GitHub’s own documentation for that feature, checked at the time of writing — the registry and integration rows draw on GitHub’s Packages and webhooks documentation respectively. The verdict column and the “what has to happen instead” column are our editorial synthesis on top of those sourced facts — judgment calls, clearly ours, not vendor claims. Where GitHub’s docs are silent on migration, we say so rather than inferring capability in either direction.

Portability inventory of ten layers in a typical GitHub footprint, grouped into layers that travel with the repository, layers that must be rebuilt by hand on a new host, and layers that never leave. Each row states where the layer lives per GitHub’s own documentation and what has to happen in a migration. The verdicts and the migration steps are Digital Applied’s editorial synthesis.
LayerWhere it lives (per GitHub’s docs)Portability verdict (ours)What has to happen instead
Travels with the repository
Git history and codeThe git object database itself — commits, branches, tags, full file historyPortable in fullA clone and a push. No importer needed; git’s own design
Code ownership (CODEOWNERS)A plain file in the repo (.github/, root, or docs/); under 3 MBFile portable; function is notEnforcement is a branch-protection setting layered on top — re-created on the new host, if it has an equivalent
Rebuilt by hand on the other side
CI workflows and runnersYAML in .github/workflows (in-repo); runners, marketplace actions and GITHUB_TOKEN context are GitHub infrastructureSplit — files travel, execution does notRewrite for the new host’s CI (GitLab’s equivalent is .gitlab-ci.yml); re-provision or re-register runners
Packages and registriesGitHub Packages (npm, RubyGems, Maven, Gradle, NuGet, containers); permissions inherited from the repo or set per-user/orgRe-buildableRepublish artifacts elsewhere, repoint every consumer, rebuild the permission model
Deploy integrations and OIDC trustOn the cloud provider’s side, bound to subject claims naming the GitHub org, repo and environmentRe-buildable, never automaticReconfigure the trust relationship against the new host’s identity — there is nothing to copy
Branch protection and rulesetsAdministrative settings, not git history; up to 75 rulesets per repo; org-level rulesets are an Enterprise-plan featureRe-buildable by handRe-created in the new host’s model; GitLab’s importer names the required-status-checks rule as not imported
Issues and PR historyGitHub’s database, referenced daily by engineers — not part of the git dataRe-buildable with lossA rich importer (GitLab’s) moves most of it with documented gaps; a bare git migration moves none of it
Third-party apps and webhooksApps installed per-account, scoped to selected repos; webhooks registered at repo, org or app levelRe-buildableReinstall equivalents where they exist on the new host; re-register every webhook URL, secret and event subscription
Never leaves — reconstructed from zero
Environments and secrets“Stored in GitHub’s infrastructure, not in version control history” — GitHub’s own wording on environmentsNot exportable (our inference — no bulk-read path is described on the pages we checked)Re-entered on the new host from your own vault or records — never migrated
Identity and SSOAn organization-account setting enforced through your IdP; repositories don’t store these policiesNot a property of the code at allRebuilt on the IdP side against the new host’s SSO model, from scratch

Read as a whole, the grid explains why “we moved our repos” and “we moved off GitHub” are different sentences. One layer out of ten is portable in full. One more carries its file but not its function, and CI splits down the middle. The remaining seven are either hand-rebuilt on the destination or reconstructed from zero on a system that was never GitHub’s to begin with. The sections below walk the heaviest rows in detail, because the details are where migration plans go wrong.

04CI and RunnersThe workflow file travels. The factory does not.

GitHub’s own Actions documentation describes the anatomy plainly: workflows are YAML files in .github/workflows, triggered by repository events, manual dispatch or a schedule, and executed on runners — either GitHub-hosted Linux, Windows and macOS machines provisioned fresh per run, or self-hosted runners a team registers on its own infrastructure. Workflows routinely call reusable actions pulled from the GitHub Marketplace or third-party repos, referenced by name and version inside the YAML rather than vendored into it.

Decompose that into portable and non-portable parts and the split is stark. The YAML itself lives in git and travels with every clone. Everything the YAML depends on stays behind: the hosted runner fleet, the marketplace actions it references, and the GitHub-specific execution context — the automatic GITHUB_TOKEN, Actions expression syntax, event payloads. On a different host, the equivalent pipeline is a rewrite into that host’s format; GitLab’s, per its own CI/CD documentation, is a .gitlab-ci.yml file at the project root. On the GitLab CI/CD overview page we checked, no automatic converter from Actions YAML is mentioned — which is a statement about that page, not proof no tool exists anywhere.

Travels
Workflow YAML
.github/workflows/*.yml · in-repo

Lives in git, so a clone carries every workflow definition byte-for-byte. On a host without an Actions-compatible executor, it is documentation of what your pipeline used to do.

Portable as text
Stays behind
The runner fleet
GitHub-hosted or self-registered

Hosted runners are GitHub infrastructure, provisioned per run. Self-hosted runners are your machines, but their registration is with GitHub — a new host means new registration against a new control plane.

Re-provisioned
Stays behind
Actions and context
Marketplace refs · GITHUB_TOKEN

Marketplace actions are referenced by name, not vendored. The token, expressions and event payloads are GitHub’s execution context. Each dependency becomes a find-an-equivalent-or-rewrite line item.

Rewritten per step

05Deploy TrustOIDC trust is identity-shaped, and secrets never leave.

The sharpest example of a cost that is invisible until migration day is deploy trust. GitHub’s OIDC security-hardening documentation describes the modern pattern: “After you have established a trust connection with a cloud provider that supports OIDC, you can configure your workflow to request a short-lived access token directly from the cloud provider” — no long-lived stored secret at all. It is genuinely better security, and it is the recommended practice across AWS, Azure and GCP deployments.

But look at where the trust actually lives. The relationship is configured on the cloud provider’s side, bound to a subject claim that identifies a specific GitHub org, repository and optionally environment — GitHub’s own documented example claim is repo:octo-org/octo-repo:environment:prod. That string is GitHub-identity-shaped. Move the code to another host and the cloud provider has never heard of the new identity; the trust relationship is not copied, exported or translated. It is reconfigured, deployment by deployment, on the AWS, Azure or GCP side — an inference from how the subject-claim binding works, and consistent with how OIDC federation works generally.

Sitting next to OIDC are environments and secrets. GitHub’s deployment documentation states that environments — with their protection rules, wait timers, up to six required reviewers, and environment-scoped secrets — are “stored in GitHub’s infrastructure, not in version control history.” And on the pages we checked, GitHub describes no bulk-read or export path for secrets: the documented model is write-only — set, update, delete. We flag the conclusion as our inference rather than a vendor sentence, but it matches how secret stores are deliberately built: if your team’s secrets exist only inside GitHub, the migration step is re-entering them from your own vault or records, not exporting them.

The invisible-until-migration-day layer
The better your security practice, the more of it is wired to GitHub’s identity. OIDC replaced stored secrets with trust relationships bound to claims like repo:octo-org/octo-repo:environment:prod — which means every deployment target holds a GitHub-shaped lock on its door. None of it blocks a migration. All of it is work that appears on no repository-size estimate.

06GovernanceRules, owners and SSO live in the account, not the code.

Governance is where years of accumulated team decisions hide. GitHub’s rulesets documentation describes what these settings can require: passing status checks, a minimum number of PR reviews, signed commits, linear history, restrictions on force-pushes and branch or tag deletion. None of it is git data — rulesets and the older branch protection rules are administrative settings. The docs also note that “Multiple rulesets can apply to the same branch at the same time, while only one branch protection rule applies,” with the more restrictive setting winning where both exist — and that rulesets targeting multiple repositories at the org level are a GitHub Enterprise-plan feature. A repository can carry up to 75 rulesets. Every one of them would be re-expressed by hand in a new host’s governance model, which will not map one-to-one.

CODEOWNERS, covered in Section 02, is the near-miss of the inventory: the file travels, the enforcement does not. GitHub’s code-owners documentation is explicit that the file alone auto-requests review, while making code-owner approval a merge gate is a separate protection setting — and that where several owners are listed, “an approval from any of the owners is sufficient.”

Identity sits above all of it. GitHub’s SAML documentation states that with SSO enforced, “All members of the organization must authenticate through your IdP to access the organization’s resources,” and that repositories don’t store or manage these authentication policies — with an enterprise-level SAML requirement able to override org-level configuration on Enterprise accounts. SSO wiring is a relationship between your identity provider and your GitHub organization. On a new host it is not migrated, translated or lossily imported; it is built again, against a different SSO implementation, from zero.

Rulesets cap
Per repository
75

GitHub’s documented ceiling on rulesets a single repo can carry. Each active one is a governance decision that exists only as a GitHub setting — re-expressed by hand in any new host’s model.

Admin settings, not git data
Required reviewers
Per environment
6

GitHub’s documented maximum for required reviewers on a deployment environment — one of several protection rules stored, per GitHub’s own wording, in its infrastructure rather than version control.

Environments layer
CODEOWNERS limit
File size ceiling
3MB

The one governance artifact that lives in the repo itself and travels with a clone. Its enforcement as a merge gate, however, is a branch-protection setting that stays behind.

File travels, teeth don’t

07The Importer EvidenceWhat importers actually move.

The best evidence for what portability looks like in practice is not a thought experiment — it is what a mature importer documents about itself. Of the three importer pages we checked, GitLab’s is by far the most detailed. GitLab’s GitHub importer, per GitLab’s own docs, moves a substantially wider slice than a bare clone: branches and git data, issues, pull requests as merge requests, comments, reviewers, reviews and review comments, labels, milestones, release notes, attachments and Git LFS objects. That list is the strongest documented proof that most issue and PR history can move — with effort, to a host that built the machinery.

The same page is equally valuable for what it concedes. GitLab states plainly that “The Require status checks to pass before merging GitHub rule is not imported” — a branch-protection setting singled out by name as left behind. The importer skips comments beyond roughly 30,000 per repo by default, due to GitHub API limitations, and cannot always tell whether a GitHub cross-reference points to an issue or a PR, limiting link reconstruction. GitHub Enterprise Cloud’s custom repository roles are explicitly unsupported and “cause partially completed imports.” And on the importer page we fetched, GitLab’s docs do not mention importing Actions workflows, GitHub Packages, webhooks or GitHub App installations — an absence on that page, not a statement that it can never be done.

The other two importers frame the range. GitHub’s own Importer, per the page we checked, migrates source code and commit history from external hosts into GitHub — the opposite direction — and does not enumerate exclusions on that page, so we make no claim about what it drops. Bitbucket Cloud’s import page, as fetched, describes accepting a source URL and optional credentials for a Git-based host and states nothing on that page about issues, PRs or wikis transferring — which we report as exactly that, not as proof of absence. The pattern across all three: every importer moves the git data; the richest one documents both a long list of extras and its specific losses; and nothing on any page we checked claims to move CI execution, packages, webhooks, deploy trust or SSO.

Richest of the three
GitLab’s importer
Issues, MRs, reviews, labels, LFS

Moves most collaboration history and documents its own losses by name: required-status-checks not imported, a roughly 30,000-comment default ceiling, custom repo roles unsupported. The honest benchmark for re-buildable with loss.

Vendor-documented gaps
Opposite direction
GitHub Importer
Into GitHub, not out

Migrates source and commit history from external hosts into GitHub. The page we checked lists what it imports and does not enumerate exclusions — a useful comparison for what a git-data-only migration covers, not an exit tool.

Source + history, inbound
Thinnest page
Bitbucket Cloud
URL + credentials, per page fetched

The import page we fetched describes only accepting a Git source URL and credentials, and is silent on issues, PRs and wikis. We claim nothing beyond that page — silence is not a capability statement either way.

Narrowed absence claim

08The Decision FrameFor most teams, the honest answer is don’t.

Now the part a vendor-adjacent post would skip. Run the inventory against a typical team’s footprint and the conclusion for most of them is that a full migration is not justified today. Not because GitHub is irreplaceable, but because the one layer a new host competes on — repository hosting — is the one layer that was never the lock-in. The switching cost is the other nine rows, and nothing about a new host’s launch week changes what they cost to rebuild. A post that pretends otherwise would be selling something.

This is also exactly what the week’s news actually says. Origin’s own release describes two-way sync with GitHub as the on-ramp and keeps GitHub as the source of truth for synced repos — which makes coexistence, not migration, the realistic near-term pattern: work moves fluidly between hosts while the integration stack stays where it is. Meanwhile the direction of travel is more coupling, not less — GitHub keeps building higher-level layers on top of the repo, as we covered in GitHub’s own multi-agent platform push. Every year, the inventory above gets longer.

The decision, then, is not “migrate or stay” — it is which of four postures fits your constraints. The same logic we laid out in our build-vs-buy decision framework applies: switching costs are a fact to be priced, not an argument to be won. And because vendor lock-in is a procurement question as much as a technical one, the inventory belongs in your vendor-management file, not just your engineering backlog. When clients ask us to evaluate a move like this, our AI transformation engagements start with precisely this kind of layer-by-layer audit — because the audit usually ends the conversation cheaper than the migration would have.

Most teams
No mandate, no migration

If no contract, compliance or sovereignty requirement forces a move, the inventory is your answer: one portable layer does not justify rebuilding nine. Bank this audit, revisit when constraints change.

Stay — and stop re-litigating it
Cursor-heavy teams
Coexist via two-way sync

Origin’s release model — GitHub stays source of truth, changes sync both directions — lets teams adopt a new surface without touching CI, deploy trust or governance. You get the new workflow; the integration stack stays put.

Sync, don’t migrate
Mandated moves
Migrate deliberately, inventory-first

When a move is genuinely required, scope it against all ten rows before committing dates. The rows marked never-leaves — secrets, SSO — need your own records and IdP work no importer will do for you.

Plan from the grid, not the repo count
New projects
Buy optionality cheaply

Portability is cheapest at design time: keep pipeline logic in scripts your CI YAML merely calls, vendor critical dependencies, and document every trust relationship and webhook as you create it.

Design for the exit you may never use

One projection worth making explicitly: the interesting competition over the next year is unlikely to be host-versus-host migration at all. If two-way sync becomes a normal capability — and a major vendor just shipped it as the on-ramp — the pressure on GitHub comes from coexistence eroding exclusivity, not from exits. Teams will keep the GitHub integration stack and grow new workflows beside it, and the “should we migrate” question quietly becomes “which host earns which workflow.” That is a better question, and the inventory above is how you answer it per workflow instead of per slogan.

09ConclusionPrice the wiring, not the repo.

The framework in three sentences

Git history is the easy part — and everyone selling a migration knows it.

Of the ten layers in a typical GitHub footprint, exactly one — the git data itself — moves with a clone, function included. Workflow YAML and CODEOWNERS travel as files and leave their meaning behind. Everything else is either rebuilt by hand on the destination or reconstructed from zero on systems that were never part of the repository: runner fleets, package permissions, OIDC trust on the cloud-provider side, branch rulesets, issue history, app installations, webhooks, secrets, SSO.

The evidence for that split is not our opinion — it is what the vendors themselves document. GitHub’s docs state which layers live outside version control. GitLab’s importer, the richest of the three we checked, names its own losses. And the newest entrant’s launch copy keeps GitHub as the source of truth rather than asking anyone to leave — the clearest signal available that the people closest to the problem read the inventory the same way we do.

So price the wiring, not the repo. For most teams that pricing ends the migration conversation, and coexistence through two-way sync becomes the realistic way to try a new host without paying the full bill. For the teams that genuinely must move, the same grid is the honest project plan. Either way, the repository was never the cost — and any estimate that starts from repo count is measuring the one thing that was free to begin with.

Audit before you migrate

Know what a platform move costs before you commit to it.

Our team runs layer-by-layer audits of developer platforms, CI/CD stacks and vendor dependencies — so decisions about hosts, tools and integrations get made on priced switching costs, not launch-week momentum.

Free consultationExpert guidanceTailored solutions
What we work on

Platform & tooling engagements

  • Switching-cost audits for developer platforms
  • CI/CD portability reviews — pipelines, runners, trust
  • Vendor lock-in assessment for procurement teams
  • Coexistence architectures — two-host workflows
  • Migration planning when a move is truly mandated
FAQ · Code-host migration costs

The questions teams ask before they migrate.

The complete git object database: every commit with full history, every branch, every tag, and every file at every revision. That is git’s own design — a full clone is a peer, and a push deposits all of it on any remote. In-repo configuration files ride along too, notably GitHub Actions workflow YAML in .github/workflows and the CODEOWNERS file. What does not move is anything stored as a GitHub account or organization setting: branch rulesets, environments, secrets, webhook registrations, app installations and SSO enforcement — plus everything that lives on a third party’s side, like OIDC trust relationships configured on your cloud provider. The files that do travel can also lose their function on arrival: workflow YAML needs a compatible executor, and CODEOWNERS needs a host setting to enforce it.
Related dispatches

Continue exploring platform decisions.