Git: édition d'historique et changement d'auteur
Le problème
Le problème de base : j'ai une identité associée à un dépôt git via l'auteur des commits. Ce dépôt git doit devenir public, et je ne veux pas que cette identité apparaisse. Mais, je souhaite garder l'historique en terme de date.
J'en profite pour vérifier d'autres dépôt git et je me rends compte qu'un vieux dépôt, déjà public, contient des veilles identités dont… mon identité régalienne1. Ouch, pas bon ça. Heureusement, le dépôt est pas connu du tout et personne contribue dessus. Ça, ça va me sauver. Voir la suite.
La solution
La version courte : ré-écrire l'historique avec git-filter-repo
.
Git permet de ré-écrire l'historique. C'est parmi les éléments qui font que j'aime git. Il est conservateur par défaut, mais plein d'outils pour bidouiller si besoin.
Je fais une tangente ici : oui, ré-écrire l'historique, c'est « pas une bonne pratique », mais certaines de ces dites « bonnes pratiques » sont pas pensées en prenant en compte certains cas spécifique. Je pense notamment au cas de l'identité pré-transition pour une personne trans. Si on a contribué à un dépôt public avec notre ancienne identité, on est bloqué avec si on ne s'autorise pas à ré-écrire l'historique. Certaines personnes accepte simplement que cela fait partie de leur histoire et tant pi. D'autre ont pu se protéger pré-emptivement en utilisant jamais leur identité régalienne dans des dépôts publics. Et puis y'a les comme moi qui nuke le truc salement parce que. Cette tangente est là pour souligner que l'informatique, c'est un monde très normé encore aujourd'hui plein de présupposé complètement faux sur la donné utilisateur. Ça va du pas grave mais frustrant 2 au très emmerdant voir dangereux : que le numéro de sécurité sociale ne change pas, que la date de naissance ne change pas, que tout le monde à accès à un ordifone3. La liste n'est pas exhaustive, loin s'en faut.
Cette tangente me fait d'ailleurs penser à cet article lu récemment au sujet des licenses dites "libres" pleine d'angles morts : article d'Oniricope : pourquoi je publie sous une licence non libre ?. L'autaire y pointe des choses très importantes qui dépassent le seul sujet de la license, ou de l'informatique.
Les outils rejetés
Deux outils pourrait être utilisé : git-rebase
ou git-filter-branch
.
Concernant le premier, c'est vraiment pas pratique et fort bourrin. Aussi, cela ne permet pas de garder les dates des commits. Une commande que j'ai trouvé à plusieurs endroit pour faire ça vite et sale (à mon sens) :
git rebase -r --root --exec "git commit --amend --no-edit --reset-author"
Cette commande ré-écrit tout l'historique en modifiant l'auteur en utilisant la configuration de Git. La solution est donc de modifier la configuration de Git, soit globalement, soit du dépôt, et d'exécuter la commande. Bien-sûr c'est possible de la modifier pour ajuster un peu le comportement. Je rentre pas dans les détails parce que ce n'est pas la solution que j'ai retenue même si je l'ai essayée.
La documentation du second indique :
WARNING
git filter-branch has a plethora of pitfalls that can produce non-obvious manglings of
the intended history rewrite (and can leave you with little time to investigate such
problems since it has such abysmal performance). These safety and performance issues
cannot be backward compatibly fixed and as such, its use is not recommended. Please use
an alternative history filtering tool such as git filter-repo[1]. If you still need to
use git filter-branch, please carefully read the section called “SAFETY” (and the
section called “PERFORMANCE”) to learn about the land mines of filter-branch, and then
vigilantly avoid as many of the hazards listed there as reasonably possible.
Donc, faut pas l'utiliser et je vais voir du côté de ma solution : git-filter-repo
.
Où l'on règle le problème
Donc, git-filter-repo
est un outil écrit en Python fait spécifiquement pour être plusse performant que et ajouter des fonctionnalités à git-filter-branch
. Y'a pas mal de choses, j'vous laisse aller fouiller.
La commande qui m'intéresse, c'est --mailmap
qui permet de filter sur un email l'auteur d'un commit et le remplacer. Cela fonctionne via un fichier indicant les substitutions. Le format est détaillé sur cette page. Pour ma part, je mets ça dans un fichier appeler mailmap
qui contient :
Nouveau_Nom <nouveau_email@example.org> <ancien_email01@example.org>
Nouveau_Nom <nouveau_email@example.org> <ancien_email02@example.org>
Y'avait plusieurs identité à effacer, donc y'a plusieurs lignes.
Par sécurité, je suis partie d'un clone frais du dépôt après avoir push et sauvegardé tout ce qui avait besoin de l'être sur le clone actif de travail. Ensuite, depuis le dépôt clone, je lance :
git filter-repo --mailmap mailmap
Une vérification des logs m'indique que l'auteur est modifié. Je peux aussi constater en comparant les sorties avant et après de la commande git filter-repo --analyze
que les anciens commits n'existent plu. Car oui, les dates et heures sont conservées, mais le fonctionnement interne de Git fait que ce sont de nouveaux commit qui sont écrit puisque l'auteur fait parti du hash qui identifie un commit. Donc, le dépôt est propre et sans trace des anciens commits que je voulais voir disparaitre, tout en conservant un historique juste concernant les dates, heures et ordre des commits.
Il ne reste qu'une étape :
git push --force
L'historique ayant étant ré-écrit, il faut force push, pas le choix. Et c'est là que le fait d'être seul sur le dépôt me sauve.
- j'entends par « identité régalienne » l'identité d'une personne selon les institutions régissant son pays, c'est à dire selon l'État. ↩︎
- oui le '+' dans la partie locale d'une adresse mail est valide. ↩︎
- Terme pour désigner un ordinateur téléphone, tout le monde appel ça un smartphone mais je trouve la traduction fluide et intéressante. ↩︎