Réécrire son historique Git (et vite)

24 février 2022

En faisant le ménage dans mes repositories sur GitHub, je suis retombé sur de vieux projets, parfois antiques. Ne nous étendons pas sur la honte que l’on peut ressentir en jetant un œil sur du code écrit il y a presque 10 ans, c’est forcément très moche…​

Mais un élément a capté mon attention : de très nombreux commits ne sont pas associés à mon pseudo ou ne présentent pas ma photo de profil. Étrange, puisque les plus récents semblent correspondre à mon pseudo et affichent ma photo.

Qu’est-ce qui a changé entre temps ?

La réponse est venue assez vite : j’ai souvent changé d’adresse mail au cours des années (école, premier emploi, nouvelle adresse personnelle et ainsi de suite). Alors, je sais que l’on peut modifier l’auteur d’un commit, son pseudo ou son adresse mail. Mais sur des centaines de commits parmi des dizaines de repositories, comment dire …​ la vie est trop courte ?

En fait, tout est une question d’outillage.

À la main ... c'est long
À la main ... c'est long
Avec les bons outils ... c'est mieux
Avec les bons outils ... c'est mieux

Le bon outil, je l’ai trouvé sur StackOverflow (à noter que l’on retrouve cette réponse sur plusieurs dizaines de posts). Tout réside dans la commande filter-branch qui est capable de parcourir tous les commits du projet et de leur appliquer des modifications.

Vous sentez le potentiel ? Oui, il y a de quoi détruire votre historique, donc on y va doucement hein !

Dans mon cas, je devais modifier les commits écrits avec une certaine adresse mail et y faire figurer mon unique adresse actuelle ainsi que mon pseudo pour tout harmoniser. La ligne de commande ressemble donc à cela :

git filter-branch -f --env-filter '

  OLD_EMAIL="old.email@example.com"
  CORRECT_NAME="New Name"
  CORRECT_EMAIL="new.email@example.com"

  if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
  then
    export GIT_COMMITTER_NAME="$CORRECT_NAME"
    export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
  fi

  if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
  then
    export GIT_AUTHOR_NAME="$CORRECT_NAME"
    export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
  fi
  ' --tag-name-filter cat -- --branches --tags

Une fois ces modifications faites en local, encore faut-il les envoyer sur le répertoire distant :

  git push -f --tags origin HEAD:main

Et nettoyer les références locales :

  git update-ref -d refs/original/refs/heads/main

On observe alors que l’historique affiche bien les commits comme étant les nôtres :

Extrait d'un vieux projet en Java 7
Extrait d'un vieux projet en Java 7

Et ce qui ne fait pas de mal à l’égo : soudainement on a plus de commits comptabilisés par GitHub sur sa page de profil ! 😉