Trier les PRs
Objectif
Transformer un backlog de PRs ouvertes en un ensemble de fusions livrées en une seule session ciblée. Produire un plan tracé et reprenable (<VERSION>_PR_TRIAGE.md), puis l'exécuter – rebaser si nécessaire, fusionner par lots isolés, appliquer les suivis post-fusion, et fermer les PRs remplacées ou partiellement applicables en créditant leurs auteurs.
Cette compétence s'utilise avec draft-release-notes et release-bump : trier d'abord, puis rédiger les notes de version sur la nouvelle branche principale, puis publier la release.
Quand l'utiliser
- Avant une release mineure ou majeure lorsque 10 PRs ou plus se sont accumulées
- Lorsque vous voulez débloquer les fusions sans perdre le fil de ce qui est livré
- Lorsque vous ne pouvez pas réviser chaque PR en profondeur personnellement, mais devez livrer rapidement le sous-ensemble critique
Prérequis
- CLI
ghauthentifiée sur le dépôt - Un worktree dédié à la révision des PR (éviter de contaminer
mainavec des extractions de branches de contributeurs) - Clarté sur la version cible – le document de tri est nommé d'après elle (ex.
0.4.0_PR_TRIAGE.md)
Workflow
1. Créer un worktree isolé pour la révision des PRs
git worktree list # vérifier d'abord les worktrees obsolètes
git worktree prune
git worktree add ../voicebox-pr-review -b pr-review-<VERSION> main
Gardez le worktree principal pour le travail de préparation de release (brouillons de changelog, suivis directs sur main). Gardez le worktree de révision pour les gh pr checkout – chaque extraction déplace HEAD vers une branche de contributeur, ce que vous ne voulez pas faire dans le worktree principal.
2. Rassembler les métadonnées pour chaque PR ouverte
gh pr list --state open --limit 50 --json \
number,title,author,isDraft,mergeable,mergeStateStatus,files,additions,deletions,reviewDecision,statusCheckRollup,maintainerCanModify \
--jq '.[] | {num: .number, title, author: .author.login, mergeable, state: .mergeStateStatus, canModify: .maintainerCanModify, changes: "+\(.additions)/-\(.deletions)", files: [.files[].path]}'
Pour chaque PR, vous voulez :
- La taille (
+additions/-deletions) - L'état de fusionnabilité (
CLEAN,UNSTABLE,DIRTY= conflits,UNKNOWN= GitHub calcule encore) - Si les modifications par le mainteneur sont autorisées sur la branche (nécessaire plus tard si vous rebasez pour l'auteur)
- Les chemins de fichiers modifiés (aide à repérer les chevauchements entre PRs)
UNKNOWN est fréquent juste après un push sur main – essayez simplement la fusion et voyez.
3. Classer en catégories
Triez chaque PR dans exactement une catégorie :
Catégorie 1 — Fusionner : petite, fusionnable, corrige un vrai bug, CI propre, faible coût de révision. Correctifs d'une ligne, assouplissements de dépendances, durcissement de sécurité ciblé. Ce sont les victoires faciles.
Catégorie 2 — Candidat, à réviser : taille moyenne (50-200 lignes), touche plus de surface, semble valable mais nécessite une lecture plus attentive. Nouvelles fonctionnalités utilisateur qui correspondent à la direction du produit.
Remplacé : le correctif ou la fonctionnalité est déjà couverte par quelque chose de fusionné. Fermez avec un commentaire pointant vers la PR remplaçante. Vérifiez attentivement – un « titre similaire » n'est pas une preuve ; comparez les diffs réels.
Reporter à la prochaine release : grandes fonctionnalités, conflits sales, PRs en brouillon, tout ce qui touche au pipeline de release d'une manière qui introduirait un risque. Ne fusionnez pas cela dans une session de vitesse – ils nécessitent une attention dédiée.
4. Rédiger le document de tri
Créez <VERSION>_PR_TRIAGE.md à la racine du worktree de révision des PRs. Structure :
# <Dépôt> <VERSION> — Tri des PRs
Document de travail pour suivre quelles PRs ouvertes sont livrées dans <VERSION>. Supprimer après la release.
Dernière mise à jour : <DATE>
## Progression
**Catégorie 1 : 0 / N fusionnées**
**Catégorie 2 : 0 / M traitées**
**Tri des remplacées : en attente**
---
## Fusionner pour <VERSION> — corrections de bugs critiques
| PR | Statut | Taille | Ce qu'elle corrige | Pourquoi indispensable |
|---|---|---|---|---|
| [#123](url) | [ ] | +5/-0 | ... | ... |
## Candidat sérieux — nécessite une révision rapide
| PR | Statut | Taille | Résumé |
|---|---|---|---|
## Fermer comme remplacée
| PR | Statut | Raison |
|---|---|---|
## Reporter à <VERSION_SUIVANTE>
- [#xxx](url) ... — raison
---
## Ordre d'attaque
1. Fermer les PRs remplacées (commentaires d'une ligne)
2. Fusionner la catégorie 1 par lots sans dépendances – vérifiez que les chemins de fichiers ne se chevauchent pas
3. Réviser les candidats de catégorie 2 individuellement
4. Relancer `draft-release-notes` pour récupérer tout
5. Lancer `release-bump`
L'en-tête Progression est la partie la plus importante – c'est votre tableau de bord et vous permet de reprendre proprement si la session est interrompue.
5. Exécuter la boucle — par PR
Pour chaque PR dans la liste des catégories 1 / 2 :
a. Extraire dans le worktree de révision :
cd ../voicebox-pr-review
git checkout pr-review-<VERSION> # réinitialiser à la base neutre
gh pr checkout <N>
b. Lire le vrai commit, pas main..HEAD :
git show HEAD # les modifications réelles de la PR
git show --stat HEAD # fichiers modifiés + nombre de lignes
Ne PAS réviser via git diff main..HEAD si la branche de la PR est plus ancienne que main. Ce diff inclut tous les commits qui ont atterri sur main après que la PR a été créée sous forme de lignes - (suppression). Une PR de 3 lignes peut ressembler à une annulation de 700 lignes. C'est la manière la plus simple de mal évaluer une PR.
c. Évaluer les préoccupations : exactitude, périmètre, interaction avec le travail déjà fusionné, compatibilité de version (par exemple, impossible d'utiliser une API qui nécessite une version de dépendance que nous ne pins pas encore).
d. Rebaser si la branche est en retard sur main :
git fetch origin main
git rebase origin/main
C'est essentiel avant une fusion squash. Le squash de GitHub calcule diff(tête-PR, base-de-fusion) – sur une branche obsolète, ce diff inclut l'annulation de tous les commits intermédiaires. Rebaser avance la base de fusion pour que le squash soit propre.
e. Si les modifications par le mainteneur sont autorisées, pousser le rebase vers le fork du contributeur :
git remote add <auteur> https://github.com/<auteur>/<dépôt>.git
git fetch <auteur> <branche> # obtenir d'abord sa référence
git push <auteur> HEAD:<branche> --force-with-lease
Cela maintient l'interface utilisateur GitHub PR synchronisée avec l'état rebasé et rend la fusion propre du côté GitHub.
f. Fusionner :
gh pr merge <N> --squash
g. Mettre à jour le document de tri – cocher la case à ✅ fusionné <sha> (utiliser le SHA court de gh pr view <N> --json mergeCommit --jq '.mergeCommit.oid[0:7]'). Mettre à jour l'en-tête Progression.
6. Traiter les petits correctifs par lots
Les PRs avec ≤5 lignes de changement, CI propre, chemins de fichiers ne se chevauchant pas, et intention évidemment correcte (par exemple assouplissement de dépendance d'une ligne, ajout de variable d'environnement, correction de chemin d'import) peuvent être fusionnées en une seule boucle sans la cérémonie de révision par PR :
for pr in 425 384 416 429; do
echo "=== Fusion de la PR $pr ==="
gh pr merge $pr --squash
done
Vérifiez ensuite que chacune a atterri proprement :
for pr in 425 384 416 429; do
gh pr view $pr --json state,mergeCommit --jq "{pr: $pr, state, sha: .mergeCommit.oid[0:7]}"
done
7. Suivis post-fusion
Parfois, une PR mérite d'être fusionnée malgré un problème mineur connu (par exemple, dictionnaire de types incomplet, nettoyage de sentinelle obsolète). Ne bloquez pas la fusion ; appliquez le suivi comme une branche normale + PR juste après :
cd <worktree-principal>
git pull --ff-only origin main
git checkout -b fix/<nom-court>
# éditer...
git commit -m "fix(<zone>): <résumé>"
git push -u origin fix/<nom-court>
gh pr create --title "..." --body "Suivi de #<N>. ..."
Enregistrez les deux SHA dans le document de tri (✅ fusionné <sha-PR> + suivi <PR>).
Exception directe vers main : uniquement sous une politique explicite et limitée (par exemple « session de vitesse release »). N'en faites pas la valeur par défaut.
8. Remplacée : fermer avec un commentaire créditant
gh pr close <N> --comment "Fermeture — remplacée par la fusion de #<M> qui a livré <brève description>. Merci !"
Vérifiez d'abord les diffs – un « titre similaire » ne suffit pas. Si la PR est partiellement remplacée (le diagnostic est correct mais seule la moitié des changements est encore nécessaire), appliquez partiellement à la place.
9. Motif d'application partielle
Lorsqu'une PR contient à la fois des changements précieux et douteux :
cd <worktree-principal>
git pull --ff-only origin main
# Cherry-picker des fichiers spécifiques depuis la branche de la PR
git checkout <sha-commit-PR> -- <fichier1> <fichier2>
# Réviser les modifications staging, ajuster si nécessaire
git diff --cached
# Appliquer des modifications chirurgicales aux fichiers que vous ne voulez pas remplacer en bloc
# (par exemple, le fichier de la PR est antérieur à un commit récent sur main que vous devez préserver)
# Commiter avec un crédit de l'auteur original
git commit -m "$(cat <<'EOF'
<objet>
<corps expliquant ce qui a été conservé vs abandonné>
Co-Authored-By: <auteur> <[email protected]>
EOF
)"
git push ... # branche + PR, sauf exception directe vers main
Puis fermez la PR avec un commentaire expliquant ce qui a été appliqué et ce qui a été abandonné, en référençant le SHA du commit.
10. Garder le document à jour
Chaque fusion, chaque fermeture, chaque suivi → mettez à jour <VERSION>_PR_TRIAGE.md. Le document est votre journal de session. Si vous êtes interrompu et reprenez demain, le document est la seule source de vérité pour « où en suis-je ? ».
11. Lorsque le tri est terminé
- Chaque PR dans le document a un statut terminal (✅ fusionné / ✅ fermé / reporté)
- L'en-tête Progression montre N/N pour chaque catégorie
- La prochaine compétence à exécuter est
draft-release-notes(pour régénérer[Unreleased]contre le nouveau main), puisrelease-bump
Vous pouvez supprimer le document de tri après la mise en ligne de la release, ou le conserver dans l'historique de version comme archive.
Pièges
main..HEADsur une branche obsolète ment. Il montre tout ce que main a gagné depuis la division de la branche comme des suppressions. Révissez toujours viagit show HEADpour le commit réel de la PR.- Fusion squash d'une branche non rebasée annule le travail intermédiaire. Le squash calcule
diff(tête-PR, base-de-fusion). Rebaser avance la base de fusion. mergeable=UNKNOWNest temporaire – GitHub recalcule après un push. Essayez simplement la fusion.- L'ordre des routes est important (FastAPI et similaires) :
DELETE /history/faileddoit être enregistré avantDELETE /history/{id}, sinon le chemin paramétré consommera"failed"comme ID. - Le
-weak_frameworkd'Apple écrase-frameworkpour le même framework, quel que soit l'ordre – utilisez-le viacargo:rustc-link-arg=-Wl,-weak_framework,Namelorsqu'une dépendance lie en dur quelque chose d'optionnel. - Les planchers de version de dépendance limitent ce que vous pouvez appliquer. Avant d'accepter un renommage d'argument comme
torch_dtype=→dtype=, vérifiez que le pin de version minimale le supporte. Parfois, la bonne décision est de cherry-picker la moitié de la PR. - Les types audio
!Sendcommecpal::Streamne peuvent pas traverser les pointsawaitouspawn_blocking. Parfois, une attente synchrone « pas idéale mais correcte » est la meilleure solution disponible ; signalez mais ne bloquez pas. - Les nightly builds de PyTorch ne sont pas publiables pour les releases – non déterministes, peuvent régresser entre les exécutions. Si une PR suggère de passer à nightly pour corriger un problème GPU, préférez
TORCH_CUDA_ARCH_LIST=...+PTXou attendez un support stable.
Référence des commandes canoniques
# Métadonnées des PRs en masse
gh pr list --state open --limit 50 --json number,title,author,mergeable,mergeStateStatus,additions,deletions,maintainerCanModify,files
# Vue détaillée d'une seule PR
gh pr view <N> --json body,author,headRefName,baseRefName,mergeable,maintainerCanModify,files,statusCheckRollup
# Le commit réel, pas le diff branche-vs-main
git show HEAD
git show --stat HEAD
gh pr diff <N>
# Rebaser la branche du contributeur sur le main actuel
git fetch origin main && git rebase origin/main
# Pousser le rebase vers le fork du contributeur (nécessite maintainerCanModify=true)
git remote add <auteur> https://github.com/<auteur>/<dépôt>.git
git fetch <auteur> <branche>
git push <auteur> HEAD:<branche> --force-with-lease
# Fusionner
gh pr merge <N> --squash
# Confirmer le SHA de fusion pour le document de tri
gh pr view <N> --json state,mergeCommit --jq '{state, sha: .mergeCommit.oid[0:7]}'
# Fermer une remplacée
gh pr close <N> --comment "Fermeture — remplacée par la fusion de #<M>. Merci !"
Notes
- Ne révisez jamais une branche obsolète via
main..HEAD. C'est la ligne la plus importante de cette compétence. - Le document de tri est l'état de la session. Perdez le document, perdez la session. Mettez-le à jour après chaque action.
- Créditez les contributeurs même sur les applications partielles. Utilisez les crédits
Co-Authored-By:et des commentaires de fermeture qui pointent vers le commit appliqué. - Ne laissez pas la perfection être l'ennemi de la livraison. Un correctif qui passe de « cassé » à « fonctionne avec un problème mineur connu » est une amélioration nette. Signalez le problème, créez un suivi, fusionnez le correctif.