Migrating CI and hooks with a repository Jump to heading
Moving a repository’s Git data is the easy part of a migration: push every branch and tag, and history arrives intact. Everything around it does not move by itself. Pipelines are written in the old platform’s syntax. Branch protection, required checks and code owner rules live in the old host’s settings. Server-side hooks run on the old server. Secrets, deploy keys, webhooks to chat and issue trackers, status badges — all are attached to the old location. A migration that moves only the Git data leaves the new repository unprotected and untested on day one. This page inventories the automation, translates it, runs old and new in parallel, compares results, and cuts over with nothing left behind, within repository migration and consolidation.
When to use this approach Jump to heading
- A repository is moving to a different hosting provider or CI system.
- The repository’s quality gates must keep working through the move.
- Previous migrations left gaps — missing checks, broken deploys, lost webhooks.
- The Git data move itself is covered in moving a repository between hosting providers.
Step 1 — Inventory every piece of automation Jump to heading
List everything attached to the repository, not just the pipeline file. Each item needs an owner and a target on the new platform.
# Pipelines and hooks in the repository
git ls-files | grep -E '^(\.github/workflows/|\.gitlab-ci\.yml|Jenkinsfile|\.circleci/|azure-pipelines\.yml|\.githooks/|\.husky/|\.pre-commit-config\.yaml)'
# Settings on the old host (GitHub example)
gh api "repos/$OWNER/$REPO/rulesets" --jq '.[].name'
gh api "repos/$OWNER/$REPO/hooks" --jq '.[] | .config.url'
gh secret list; gh variable list
gh api "repos/$OWNER/$REPO/keys" --jq '.[].title' Step 2 — Translate pipelines job by job Jump to heading
Rewrite each pipeline in the new platform’s syntax, keeping job names and commands the same so results can be compared. Move logic out of platform syntax into scripts in the repository where possible — scripts migrate unchanged.
# Old (GitLab CI)
test:
script: ["./ci/test.sh"]
rules: [{ if: '$CI_PIPELINE_SOURCE == "merge_request_event"' }] # New (GitHub Actions)
on: { pull_request: {} }
jobs:
test:
runs-on: ubuntu-latest
steps: [{ uses: actions/checkout@v4 }, { run: ./ci/test.sh }] Trigger mapping between platforms is covered in mapping GitLab CI rules to branch and path changes.
Step 3 — Recreate rules and server hooks Jump to heading
Recreate branch protection, required checks and code owner enforcement on the new host. Server-side hooks often have no direct equivalent on hosted platforms; translate each into a ruleset, a required CI check or a push rule.
# Old pre-receive hook rejected unsigned commits on main →
# new: ruleset requiring signed commits on main
# Old hook rejected files over 10 MB →
# new: push rule for max file size, or a required CI check
# Old hook enforced commit message format →
# new: required CI check on pull requests The options are compared in server-side hook enforcement.
Step 4 — Recreate secrets, never copy them Jump to heading
Secrets cannot usually be read back from the old host, and should not be. Issue new credentials for the new platform, scoped as narrowly as possible, and revoke the old ones after cutover.
gh secret set DEPLOY_TOKEN < /dev/stdin # paste a newly issued token; do not reuse the old one
gh variable set DEPLOY_ENV --body production Deploy keys, signing identities and cloud trust relationships (such as OIDC trust policies naming the old repository) must be recreated too. Scoping is covered in scoping deploy keys and tokens.
Step 5 — Run old and new in parallel Jump to heading
Before cutover, mirror pushes to the new host and run both pipelines on the same commits. Compare job results; any difference is a translation gap.
# Mirror from old to new on each push (old host's push mirror, or a scheduled job)
git push --mirror https://git.new.example/org/app.git
# Compare results for a commit
sha=$(git rev-parse HEAD)
gh run list --commit "$sha" --json name,conclusion --jq '.[] | "\(.name) \(.conclusion)"' | sort ⚠️ SAFETY WARNING: During parallel running, make sure only one platform deploys. Disable deploy jobs on the new platform, or point them at a test environment, until cutover — two pipelines deploying the same commit to production can conflict.
Step 6 — Cut over and switch off the old automation Jump to heading
At cutover, make the old repository read-only, enable deploys on the new platform, update webhooks and badges, and disable the old pipelines so they cannot run against stale code.
# Old host: archive or restrict pushes; disable pipelines
# New host: enable deploy jobs, required checks, webhooks
git remote set-url origin https://git.new.example/org/app.git # each developer Step 7 — Revoke and clean up Jump to heading
After a short grace period, revoke the old secrets and deploy keys, delete webhooks on the old host, and remove trust relationships naming the old repository.
# Checklist driven by the Step 1 inventory: every old item marked replaced, then removed
awk -F'\t' '$3 != "removed" {print "still open:", $1, $2}' migration-inventory.tsv Validation checklist Jump to heading
Frequently Asked Questions Jump to heading
Can we migrate pipelines automatically? Jump to heading
Converters exist for common platform pairs and give a useful first draft. Review every converted job; platform semantics such as triggers, caching and secret scoping rarely map one to one.
How long should parallel running last? Jump to heading
Long enough to see every pipeline run at least once — including scheduled and release jobs. One to two weeks is typical.
What about open pull requests? Jump to heading
Merge or close as many as possible before cutover. Recreate the rest on the new host from their branches, as described in preserving pull request history in a migration.
Related Jump to heading
- Repository Migration & Consolidation — the parent topic.
- Migrating from Mercurial to Git — when the version control system changes too.
- Merge Queues and Required Checks — recreating gates on the new host.
- Rotating Credentials After a History Rewrite — revoking credentials systematically.