Aller au contenu

Migrer un dépôt CodeCommit vers GitHub — refs, LFS, hooks et la redirection post-bascule

Une migration CodeCommit-vers-GitHub propre déplace toutes les refs, les objets LFS et les contrats de hooks. Voici le motif mirror-push, la liste de validation et la redirection pour les retardataires.

La décision est prise — le dépôt passe de CodeCommit à GitHub. Le plan naïf est git clone depuis CodeCommit, git remote add vers GitHub, git push. Ça fait traverser la branche par défaut et les tags. Ça rate toutes les autres refs que l’équipe a accumulées : les branches de fonctionnalité en vol, les objets LFS, le déclencheur CodePipeline qui se déclenche à chaque push, les quatre développeurs dont les IDE sont encore configurés contre l’ancienne origine, les scripts CI qui codent en dur l’URL CodeCommit. Une bascule propre traite tous ces points. Une bascule précipitée laisse des branches orphelines dans CodeCommit, un pipeline de build qui échoue soudainement parce que la source a bougé, et trois semaines de messages Slack « euh, où est ma branche ? ».

Ce qui se passe

Un dépôt Git est un graphe d’objets (commits, arbres, blobs) plus un ensemble de références nommées (branches, tags, notes, parfois refs personnalisées). Un git clone par défaut ne copie que l’historique de la branche par défaut plus les tags. Un git clone --mirror copie chaque ref, y compris les branches de suivi distantes et les notes — c’est le bon point de départ pour une migration.

Les objets LFS vivent en dehors du store d’objets Git. Ils sont suivis par des fichiers pointeurs dans le dépôt et stockés séparément (le point de terminaison LFS de CodeCommit, dans ce cas). Pousser les refs Git vers GitHub sans pousser explicitement les objets LFS vous laisse avec un dépôt rempli de pointeurs cassés. git lfs fetch --all suivi de git lfs push --all est le volet LFS de la migration.

Les « hooks » de CodeCommit ne sont pas des hooks Git au sens traditionnel — il n’y a pas de scripts pre-receive à l’intérieur du dépôt. L’équivalent est un RepositoryTrigger : une action configurée qui se déclenche sur les événements de push vers un topic SNS, un Lambda ou un CodePipeline. Ceux-ci ne migrent pas automatiquement. Le CI de l’équipe est piloté par ces déclencheurs ; sur GitHub, l’équivalent est un webhook, une GitHub App ou un workflow Actions sur l’événement push. Mapper les déclencheurs vers les équivalents GitHub est la deuxième moitié de la migration.

La redirection pour les retardataires est la partie que les équipes oublient. Après la bascule, l’ancienne URL CodeCommit existe toujours. Les développeurs qui n’ont pas mis à jour leurs remotes continueront de pousser vers CodeCommit et perdront leur travail quand il finira par disparaître. Le plan de bascule a besoin d’une façon de faire échouer l’ancien point de terminaison fortement (pas silencieusement) pour que le développeur affecté soit forcé de mettre à jour.

Comment vérifier

Faites l’inventaire du dépôt avant d’y toucher :

# Obtenir un miroir propre ; toutes les refs, pas d'arbre de travail
git clone --mirror codecommit::us-east-1://my-repo /tmp/my-repo-mirror
cd /tmp/my-repo-mirror

# Refs : combien de branches, tags, notes, refs personnalisées ?
git for-each-ref --format='%(refname:short)' | wc -l
git for-each-ref --format='%(refname)' | awk -F/ '{print $2}' | sort | uniq -c

# Taille des objets
du -sh objects/
git count-objects -v

# Inventaire LFS
git lfs ls-files --all | wc -l
git lfs ls-files --all --size | head -20

Le compte de la première commande est le total des refs — plusieurs centaines est normal pour un dépôt longue durée. La deuxième vous dit la structure (heads, tags, remotes). La troisième vous dit si la taille va tenir dans les quotas GitHub sans activer LFS ou demander une exception (la limite dure de GitHub est 5 Go par dépôt ; recommandé sous 1 Go). La quatrième vous dit si LFS est en jeu.

Faites l’inventaire des déclencheurs actifs :

aws codecommit get-repository-triggers --repository-name my-repo \
  --query 'triggers[].{Name:name,Destination:destinationArn,Events:events}' \
  --output table

Chaque ligne de déclencheur est un élément de migration : un Lambda, un topic SNS ou un CodePipeline qui se déclenche au push. Chacun a besoin d’un équivalent côté GitHub avant la bascule, ou d’une décision délibérée de retraite.

Identifiez les pipelines CodePipeline branchés au dépôt :

aws codepipeline list-pipelines --query 'pipelines[].name' --output text | \
  while read p; do
    src=$(aws codepipeline get-pipeline --name "$p" \
      --query 'pipeline.stages[?name==`Source`].actions[].configuration' \
      --output json)
    echo "$p: $src" | grep -i my-repo && echo "  ^^ utilise my-repo"
  done

Tout ce qui affiche ^^ utilise my-repo doit être reconfiguré contre la source GitHub (via l’action source AWS CodeStar Connections ou GitHub) avant que les anciens déclencheurs s’éteignent.

La correction

La séquence de bascule, dans l’ordre :

  1. Préalable côté GitHub. Créez le dépôt cible sur GitHub. Configurez la protection de branche (le modèle IAM CodeCommit pour les refs protégées se traduit en règles de protection de branche GitHub — réviseurs requis, vérifications de statut requises, pas de force-push sur main). Ajoutez l’équipe et son équipe GitHub équivalente. Ajoutez une confiance OIDC vers votre compte AWS pour qu’Actions puisse assumer des rôles sans clés longue durée.

  2. Geler les écritures sur CodeCommit. Communiquez une fenêtre de bascule à l’équipe. Optionnellement, attachez une stratégie de refus qui bloque codecommit:GitPush sur le dépôt pour la durée :

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "FreezeCodeCommitForMigration",
    "Effect": "Deny",
    "Action": "codecommit:GitPush",
    "Resource": "arn:aws:codecommit:us-east-1:123456789012:my-repo"
  }]
}

Attachez au groupe ingénierie pendant la fenêtre ; détachez après. Ça empêche les push qui se précipitent pendant le miroir.

  1. Mirror-clone et push. Depuis le miroir créé pendant l’étape d’inventaire :
cd /tmp/my-repo-mirror

# Re-fetch au cas où il y aurait eu des changements pendant la mise en place du gel
git fetch --all --prune
git fetch --tags

# Objets LFS d'abord
git lfs fetch --all

# Ajouter le remote GitHub
git remote add github git@github.com:my-org/my-repo.git

# Pousser toutes les refs
git push github --mirror

# Pousser les objets LFS
git lfs push --all github

git push --mirror est le bon drapeau — il pousse toutes les refs exactement comme elles sont sur la source, y compris les suppressions. Le --mirror est destructif sur la destination : si le dépôt GitHub n’est pas vide (par exemple à cause d’une erreur « créer avec README »), le push écrasera. Créez le dépôt GitHub vide.

  1. Valider après push. Comparez les comptes de refs et un échantillon de SHA de commits :
# Sur le miroir source
git for-each-ref --format='%(refname) %(objectname)' | sort > /tmp/source-refs

# Cloner le dépôt GitHub frais
git clone --mirror git@github.com:my-org/my-repo.git /tmp/dest-mirror
cd /tmp/dest-mirror
git for-each-ref --format='%(refname) %(objectname)' | sort > /tmp/dest-refs

diff /tmp/source-refs /tmp/dest-refs

Le diff doit être vide. Si LFS est en usage, validez aussi que les fichiers pointeurs résolvent :

# Dans le clone destination (pas miroir)
git clone git@github.com:my-org/my-repo.git /tmp/dest-clone
cd /tmp/dest-clone
git lfs pull
# Vérifier ponctuellement un fichier LFS connu
file path/to/large.bin   # doit signaler le vrai type, pas "ASCII text" d'un pointeur
  1. Reconfigurer le CI et les déclencheurs. Pour chaque entrée de l’inventaire de déclencheurs :

    • Actions source CodePipeline : permuter de la source CodeCommit à une CodeStar Connection ou une source GitHub pointant vers le nouveau dépôt. Le rôle IAM sur le pipeline a besoin de codestar-connections:UseConnection au lieu de codecommit:GitPull. Utilisez un projet CodeBuild pour exécuter le build de la même façon qu’avant, ou migrez le build vers GitHub Actions.
    • Déclencheurs Lambda : réécrivez comme gestionnaires de webhook GitHub (API Gateway → Lambda, avec vérification HMAC utilisant le secret de webhook GitHub) ou comme workflows Actions qui appellent le Lambda via aws lambda invoke. La version basée sur Actions est plus propre et retire l’API Gateway du chemin.
    • Notifications SNS : GitHub ne publie pas nativement vers SNS. Remplacez par un workflow qui utilise aws-actions/configure-aws-credentials et aws sns publish depuis une étape.
  2. Couper DNS, config IDE et docs. Mettez à jour README.md, le doc d’onboarding développeur, tout fichier .iml IDE commité au dépôt et tous les docs internes qui référencent l’URL CodeCommit. Mettez à jour le portail de docs central de l’équipe. Envoyez un courriel et un message Slack avec la nouvelle URL de clone.

  3. Faire échouer l’ancienne URL CodeCommit fortement. C’est la partie qui empêche la dérive. Deux motifs :

    • Suppression dure. Une fois la migration validée et une période de grâce passée (nous utilisons 30 jours), supprimez le dépôt CodeCommit. L’ancienne URL retourne une erreur claire. Exécutez après les étapes de validation, pas avant.
    • Blocage doux. Gardez le dépôt CodeCommit comme archive lecture seule. Attachez une stratégie de refus sur codecommit:GitPush pour tout le monde sauf un rôle bris-de-glace. Les développeurs qui tentent de pousser obtiennent une erreur de permission refusée qui apparaît dans leur terminal — ils mettent alors à jour le remote.

    Le blocage doux est le défaut plus sûr. Convertissez en suppression dure après un trimestre sans incident.

  4. Exécuter un push de fumée par un seul développeur. Avant d’annoncer la migration comme terminée, faites pousser un commit trivial par un développeur sur une branche de fonctionnalité du nouveau dépôt GitHub. Vérifiez que le workflow Actions se déclenche, que le CI tourne, que les ressources AWS (s’il y en a) obtiennent le bon IAM via OIDC. De bout en bout sur un seul développeur fait émerger les problèmes avant que le reste de l’équipe ne les heurte.

Deux règles que nous tenons :

Bascule dans une seule journée de travail, pas une fin de semaine. Une bascule en fin de semaine signifie que les problèmes émergent lundi matin au pire moment possible. Une bascule mardi matin donne à l’équipe le reste de la semaine pour gérer les retardataires.

Garder le miroir source pour 90 jours. Le /tmp/my-repo-mirror local est la vérité de terrain de ce qui était sur CodeCommit au moment de la bascule. Si un client réclame une branche manquante, le miroir est l’arbitre. Déplacez-le de /tmp vers un stockage durable avant qu’il ne s’efface.

La séquence entière est une demi-journée de travail actif pour un seul dépôt, plus un trimestre de période de grâce avant que l’ancienne origine ne disparaisse. Pour une flotte de dépôts, parallélisez l’étape 3 (le mirror-push est indépendant par dépôt), mais séquencez la reconfiguration CI — c’est là que vit la dette de migration.


Stack Harbor opère CodePipeline + CodeCommit (et les variantes GitHub sur AWS) dans le cadre de l’onboarding Gestion AWS et des Environnements infogérés en continu. Si vous avez une flotte de dépôts CodeCommit à migrer avant que l’horizon de dépréciation ne se resserre, commencez par une consultation d’infrastructure.