git-coda — Workflow Ship en un clic
git-coda est le nom du projet ; coda (finale) est la conclusion d’un mouvement musical, qui condense toute l’histoire de développement en une note et la ramène sur main. Le verbe du workflow reste « ship ».
Objectif et critères de réussite
Amener les modifications de l’espace de travail actuel à travers le chemin complet :
Modifications actuelles → Nouvelle branche basée sur main à jour → Commit → PR → Squash merge → Retour sur main
L’appel à ship par l’utilisateur signifie qu’il autorise l’exécution complète du workflow. Le processus doit s’enchaîner sans demander de confirmation pour le nom de la branche, le message de commit, le titre de la PR, le corps de la PR, la solution de conflit, la validation ou la poursuite.
Cette autorisation inclut :
- Modifier le code actuel pour le rendre compatible avec les fonctionnalités de la dernière version de
main. - Corriger les problèmes de tests, lint, types, build et CI causés par les modifications actuelles ou les conflits.
- Créer les commits de correction nécessaires et les repousser.
- Synchroniser le dernier
mainavant le merge, résoudre les nouveaux conflits et revalider.
Le workflow n’est considéré comme terminé que si toutes les conditions suivantes sont remplies :
- La PR a été fusionnée avec succès dans
main(ne pas considérer « PR créée » ou « auto-merge activé » comme terminé). - Les vérifications obligatoires ont réussi, ou le dépôt n’a pas de vérifications exécutables.
- L’utilisateur est revenu sur
mainlocalement et a avancé jusqu’au commit fusionné.
Principes d’exécution fondamentaux
- Le résultat par défaut de
shipest « publication réussie », pas « problème détecté, je le transmets à l’utilisateur ». - En cas d’échec d’une commande, analyser la cause et reprendre le flux ; ne pas répéter mécaniquement la même commande qui a échoué.
- Utiliser les fonctionnalités existantes du dernier
origin/mainet l’objectif produit des modifications actuelles comme contraintes communes, en privilégiant leur conservation. - Corriger la cause racine, ne pas simuler un succès en ignorant les tests, en supprimant des assertions, en désactivant des règles ou en utilisant
--no-verify. - Ne pas utiliser force push,
reset --hard, abandonner des commits ou écraser les modifications de l’utilisateur. - Ne s’interrompre que pour des problèmes d’authentification/permissions, approbation nécessaire, indisponibilité persistante de la plateforme ou du réseau, ou impossibilité de déterminer l’intention de la demande à partir du code et du contexte. Dans ce cas, expliquer la seule action nécessaire de la part de l’utilisateur.
Étape 0 : Collecte d’informations
Avant de commencer, vérifier l’état actuel :
git status --short --branch
git branch --show-current
git diff --stat
git diff --cached --stat
git remote -v
gh auth status
Enregistrer la branche actuelle, les modifications non commitées et les commits non poussés pour ne pas perdre le travail de l’utilisateur. S’il n’y a aucune modification non commitée, vérifier si la branche actuelle contient des commits à publier par rapport à origin/main ; si ce n’est pas le cas non plus, indiquer qu’il n’y a rien à publier et s’arrêter.
Déterminer automatiquement les informations suivantes :
1. Nom de la branche
- Utiliser directement le nom fourni par l’utilisateur.
- Sinon, déduire le nom en fonction du contenu des modifications, au format
<type>/<short-desc>. - Respecter les préfixes de branche ou les conventions de nommage existantes dans le dépôt cible ; en l’absence de règle, utiliser un nom sémantique.
- Si une branche portant le même nom existe déjà localement ou à distance, ajouter automatiquement un suffixe court pour éviter une interruption due à un conflit de nom.
2. Message de commit
- Utiliser directement le message fourni par l’utilisateur.
- Sinon, générer un message au format Conventional Commits à partir de la totalité du diff :
<type>(<scope>): <description>.
3. Titre et corps de la PR
- Par défaut, le titre de la PR est le message de commit.
- Le corps de la PR est généré automatiquement à partir du diff : 2–3 points de résumé, aperçu des fichiers modifiés et résultats de validation.
- Ne pas demander séparément le nom ou le corps de la PR.
Une fois ces informations déterminées, indiquer brièvement à l’utilisateur la branche et le commit qui seront utilisés, puis continuer immédiatement sans attendre de réponse.
Étape 1 : Synchronisation de la branche principale
S’il y a des modifications dans l’espace de travail, créer d’abord un stash avec un identifiant unique et enregistrer la référence correspondante ; ne pas créer de stash vide s’il n’y a pas de modifications.
git stash push --include-untracked -m "git-coda: <timestamp>"
git fetch --prune origin
Après fetch, vérifier les commits à publier en utilisant la branche d’origine et HEAD d’origine enregistrés à l’étape 0. Si la branche fonctionnelle d’origine contient déjà des commits, la conserver, fusionner origin/main, puis appliquer le stash actuel ; ne pas basculer sur main avant de décider si la branche d’origine a des commits. Ce n’est que si la branche d’origine n’a aucun commit à publier que l’on crée une branche de publication à partir de origin/main.
Vérifier d’abord la branche principale cible à partir de HEAD distant ou de la configuration du dépôt ; ci-dessous, main est un nom générique, à remplacer par le nom réel si le dépôt utilise master ou autre.
Informer l’utilisateur du hash du commit de la dernière branche principale.
Si le main local ne peut pas être fast-forward :
- Vérifier les commits locaux uniques, ne pas les supprimer ni les écraser.
- Créer la branche de publication directement à partir du dernier
origin/mainet continuer le processus de publication. - En revenant finalement sur
main, conserver ces commits locaux et préciser explicitement que lemainlocal n’a pas été écrasé ; cela n’affecte pas la fusion en ligne déjà effectuée.
Étape 2 : Création de la branche
git checkout -b <branch-name> origin/main
Si le travail actuel se trouve déjà sur une branche fonctionnelle contenant des commits à publier, il est possible de continuer à l’utiliser ; fusionner d’abord le dernier origin/main et résoudre les problèmes selon le « Processus de gestion des conflits ». Ne pas re-commiter les mêmes modifications.
Étape 3 : Application des modifications et commit
git stash apply <recorded-stash>
git add -A
git commit -m "<commit-message>"
En cas de conflit lors de stash apply, le résoudre selon le « Processus de gestion des conflits ». Une fois toutes les modifications appliquées et commitées, supprimer le stash créé pour cette étape ; ne pas supprimer accidentellement un stash existant de l’utilisateur.
Si le hook de commit échoue, cela est considéré comme un échec de validation : corriger la cause racine, re-stager et re-commiter, sans utiliser --no-verify.
Processus de gestion des conflits
Ce processus s’applique à stash apply, à la fusion du dernier main, aux branches distantes non fast-forward et aux conflits de merge de PR.
-
Rassembler les faits :
git status git diff --name-only --diff-filter=U git log --oneline --left-right origin/main...HEAD -
Examiner un par un les fichiers en conflit : base, versions de la branche actuelle et de l’autre branche, ainsi que les appelants, tests, types, configurations et commits récents associés. Ne pas se contenter des marqueurs de conflit, ni choisir aveuglément
oursoutheirsfichier entier. -
Déterminer l’intention des deux côtés :
origin/mainreprésente le comportement actuel en ligne, à conserver sauf si la fonctionnalité actuelle le remplace explicitement.- La branche actuelle représente l’objectif fonctionnel actuel ; ne pas supprimer silencieusement pour éliminer un conflit.
- Si les deux côtés ajoutent des capacités valides, intégrer les interfaces, les flux de données et les conditions aux limites pour qu’ils coexistent.
- Les conflits de tests doivent être mis à jour en fonction du comportement final du produit ; les fichiers de verrouillage et les fichiers générés doivent être regénérés avec l’outil spécifié par le dépôt.
-
Éditer jusqu’à ce qu’il n’y ait plus de marqueurs de conflit, exécuter
git add, et vérifier quegit diff --name-only --diff-filter=Uest vide. -
Exécuter une validation minimale liée aux fichiers en conflit, puis la validation complète requise par le dépôt.
-
Créer un commit de merge ou de correction, et continuer le flux original.
S’il est impossible de déterminer l’intention à partir des seuls blocs de conflit, continuer à recueillir des preuves à partir de l’implémentation, des tests, de la chaîne d’appel, de l’historique des commits et de la documentation du projet. Ce n’est que si les deux comportements sont mutuellement exclusifs et que l’intention du produit reste indéterminable qu’il faut demander à l’utilisateur, en présentant clairement les options, leur impact et la recommandation.
Étape 3.5 : Validation locale
En fonction des modifications actuelles et de la documentation du dépôt, rechercher les commandes de validation existantes :
- Priorité à la lecture de
AGENTS.md,CONTRIBUTING.mdetREADME.md. - Ensuite, vérifier les fichiers du projet comme
package.json,pyproject.toml,Makefile, configuration CI. - Si nécessaire, installer les dépendances avec le gestionnaire de paquets existant du projet selon le fichier de verrouillage, sans mettre à niveau les dépendances inutilement.
- Exécuter d’abord les vérifications directement liées au périmètre des modifications, puis les vérifications requises par le dépôt (lint, typecheck, test ou build).
- Si aucune commande fiable n’est trouvée, informer clairement l’utilisateur des vérifications ignorées et de la raison, sans inventer de commande.
Boucle de correction des échecs de validation
En cas d’échec de validation, ne pas s’interrompre et suivre cette boucle :
- Conserver la sortie d’erreur complète, identifier la première cause racine, sans corriger seulement la dernière erreur en cascade.
- Déterminer si l’échec provient du code produit, des attentes des tests, des types, du formatage, des dépendances, de la configuration ou de l’environnement.
- Effectuer la correction minimale correcte pour satisfaire les fonctionnalités en ligne et actuelles :
- Utiliser en priorité le formateur ou l’autofix de lint existant du dépôt, puis traiter les problèmes restants.
- Corriger les défauts de code.
- Mettre à jour les tests uniquement si la fonctionnalité actuelle modifie intentionnellement le comportement et que l’attente d’origine est obsolète ; ne pas affaiblir, ignorer ou supprimer des tests valides.
- En cas de dépendances manquantes dans l’environnement, restaurer l’environnement selon le fichier de verrouillage du projet ; ne pas en profiter pour effectuer des mises à niveau non liées.
- Re-exécuter d’abord la vérification minimale qui a échoué, puis toutes les vérifications obligatoires.
- Si de nouveaux échecs apparaissent, continuer à diagnostiquer et corriger jusqu’à ce que tout soit réussi.
Les corrections effectuées avant le premier push peuvent être incorporées dans le commit actuel ; les corrections effectuées après le premier push créent un nouveau commit et sont poussées normalement, sans utiliser force push pour réorganiser l’historique. Tant que chaque itération apporte de nouvelles preuves ou des progrès substantiels, continuer à avancer sans abandonner en raison du nombre d’échecs.
Étape 4 : Push et création de la PR
git push -u origin <branch-name>
En cas de rejet du push, classer et traiter :
- Si une branche distante du même nom contient un contenu non lié : changer automatiquement pour un nom de branche unique et pousser.
- Si la branche distante du même nom appartient à la même fonctionnalité et contient de nouveaux commits : après fetch, fusionner la branche distante, résoudre les conflits, valider et repousser.
- En cas d’échec temporaire du réseau ou de GitHub : réessayer brièvement et vérifier la récupération du service.
- En cas d’absence d’authentification ou de permission d’écriture : conserver l’intégralité du travail en cours et demander à l’utilisateur de finaliser l’autorisation.
Utiliser gh pr create pour créer la PR :
- base :
main - head : nouvelle branche
- titre : message de commit
- corps : 2–3 points de résumé, aperçu des fichiers modifiés, résultats de validation et
🤖 Finale via git-coda
Si une PR existe déjà, la réutiliser sans en créer une nouvelle. Après la création réussie, afficher l’URL de la PR à l’utilisateur, puis continuer sans attendre de réponse.
Étape 5 : Attente CI et corrections
Utiliser les commandes disponibles du dépôt comme gh pr checks <pr-number> --watch pour attendre les vérifications obligatoires.
En cas d’échec des vérifications :
- Utiliser
gh pr checks,gh run view --log-failedetc. pour lire les tâches échouées et leurs logs. - Si possible, reproduire localement, puis corriger la cause racine selon la « Boucle de correction des échecs de validation ».
- Commiter la correction et pousser normalement, puis attendre à nouveau la CI.
- Répéter jusqu’à ce que toutes les vérifications obligatoires réussissent.
Si les vérifications sont en attente depuis longtemps, vérifier le workflow, la file d’attente de concurrence et l’état de GitHub ; si possible, relancer les tâches échouées automatiquement. Ne demander l’intervention de l’utilisateur que si une tâche doit être approuvée par une personne autorisée ou si un service externe est indisponible de manière persistante.
Étape 6 : Synchronisation du dernier main et Squash merge
Avant le merge, synchroniser à nouveau la branche principale :
git fetch origin main
git merge --no-edit origin/main
En cas de conflit, le résoudre selon le « Processus de gestion des conflits », relancer la validation locale, pousser et attendre la CI. Puis fusionner directement :
gh pr merge <pr-number> --squash --delete-branch
Si le merge échoue en raison d’une mise à jour de la base ou d’un conflit, recommencer la boucle : synchronisation, résolution, validation, push, attente CI, puis fusionner à nouveau. Si le dépôt prend en charge une file d’attente de merge, attendre dans la file jusqu’à confirmation que la PR a effectivement été fusionnée.
Ne pas contourner la protection de branche. Si des approbations, signatures ou permissions nécessaires manquent, il s’agit d’un blocage externe : afficher le message de retour précis de GitHub, expliquer les étapes déjà effectuées et la seule action que l’utilisateur doit accomplir.
Étape 7 : Retour sur main et confirmation du résultat
git checkout main
git pull --ff-only origin main
git status --short --branch
gh pr view <pr-number> --json state,mergedAt,mergeCommit,url
Confirmer que l’état de la PR est « merged », et afficher le hash final du commit de main. Si le main local contient des commits uniques préexistants qui empêchent un fast-forward, les conserver sans action destructive ; confirmer quand même que la PR distante a été fusionnée et expliquer clairement l’état local.
Afficher l’état final :
🚀 Ship terminé !
✓ Branche <branch-name> fusionnée dans main
✓ Validation locale et CI obligatoire réussies
✓ Actuellement sur main, synchronisé avec le dernier code (<commit-hash>)
✓ PR: <pr-url>
Principes de gestion des erreurs
- Avant chaque étape, expliquer brièvement ce qui est en cours.
- En cas d’échec d’une commande, diagnostiquer, corriger et réessayer, en visant toujours une fusion réussie.
- Ne pas utiliser force push,
reset --hardou d’autres méthodes destructives pour restaurer. - Résoudre activement les conflits, en protégeant à la fois les fonctionnalités en ligne les plus récentes et les objectifs fonctionnels actuels.
- Corriger activement les échecs de tests, lint, typecheck, build, hooks de commit et CI.
- Ne pas demander de confirmation pour le nom de branche, le message de commit, le titre de la PR, le corps de la PR ou la poursuite automatique.
- Ne pas considérer les échecs réparables, les besoins de débogage multiples ou la durée du processus comme des blocages.
- Ne s’interrompre que pour des conditions externes que l’environnement actuel ne peut vraiment pas résoudre ; conserver la branche, les commits et les logs pour pouvoir reprendre.
- En cas d’interruption, ne donner qu’une action claire, minimale et exécutable pour l’utilisateur, et permettre de reprendre à partir de la position actuelle.
Cas limites courants
| Situation | Traitement |
|---|---|
| Sur une branche non main avec uniquement des modifications de l’espace de travail | Stash → Nouvelle branche basée sur origin/main → Apply → Résoudre conflit |
| La branche actuelle a déjà des commits à publier | Conserver les commits, fusionner le dernier origin/main, continuer |
| Aucune modification non commitée | Vérifier les commits à publier par rapport à origin/main ; s’il n’y en a pas, s’arrêter |
| Nom de branche déjà existant | Générer automatiquement un suffixe unique ; si une branche distante existe pour la même fonctionnalité, la réutiliser et intégrer |
Conflit stash apply ou merge | Analyser l’intention fonctionnelle des deux côtés, intégrer l’implémentation, valider, continuer |
| Échec lint/test/typecheck/build | Corriger la cause racine et boucle de validation ; ne pas transmettre l’échec à l’utilisateur |
| Échec CI | Lire les logs, reproduire localement, corriger, pousser, attendre la prochaine CI |
| Mise à jour de main avant merge | Fusionner le dernier origin/main, résoudre les conflits, re-exécuter la boucle de validation |
gh non connecté | Demander d’exécuter gh auth login |
| Approbation humaine obligatoire ou absence de permission d’écriture | Conserver l’état, expliquer la seule action externe à effectuer par l’utilisateur |
Utilisateur spécifie --no-squash | Utiliser --merge |