Je reste toujours fasciné par le nombre incroyable de petits détails qui nous simplifient le quotidien mais qu'on ne perçois que le jour où on ne les as plus.
Informatiquement parlant, ça m'est arrivé récemment avec ma gestion de Git.
Jusque-là, que ce soit dans mon IDE ou dans un terminal Git Bash sous Windows, le nom de la branche sur laquelle je travaille était visible. Comme j'interviens sur plusieurs projets, ça me permet de me situer. Par exemple, quand je reviens sur un projet, est-ce que je travaillais sur quelque chose (branche de type feature) ou étais-je sur une base fraîche (branche main) ?
Quelque chose de tout bête mais qui me sert drôlement. Pareil pour l'autocomplétion Git sous Git Bash : je commence à taper le nom de la branche, un coup de tabulation et bim, autocomplétion, inutile de taper tout le nom de la branche.
C'est tellement naturel que je ne m'en rends pas compte.
Et puis j'ai dû intervenir sur un projet qui nécessitait de fonctionner sous WSL (et pas possible d'utiliser mon IDE habituel). Et j'ai été perdu. Non pas que je ne connaisse les commandes git mais ne pas avoir dans le terminal le nom de la branche qui s'affiche quand j'arrive dans un répertoire versionné, ça me gêne.
Je suis obligé de réfléchir à ce qui était un automatisme. Est-ce que je suis bien dans un répertoire versionné sous Git ? Puis faire un git branch ou un git status pour me repérer.
Au bout de deux jours, le bon gros techos en moi s'est mis à hurler. Et sachant pertinemment que c'était techniquement possible, je me suis mis en quête de configuration.
Afficher la branche courante dans le shell
Le premier élément que je souhaitais ajouter était le nom de la branche courante dans le récapitulatif du prompt, à la manière de Git Bash. C'est à dire le nom utilisateur, le nom de la machine et le path dans lequel on se trouve.
Précision : je parle ici de configuration qui vont s'appliquer à des machines Debian (et dérivées comme Ubuntu) et un shell bash (Bourne-Again Shell), je n'ai pas testé sous d'autres environnements et d'autres formes de shell.
Pour modifier l'invite de commande, il faut mettre à jour la variable $PS1 qui contrôle ce qui est affiché avant chaque commande. Pour ceux qui veulent en savoir plus, je vous renvoie vers cette page wiki Arch Linux très bien faite (pas trouvé en version debian) : https://wiki.archlinux.org/title/Bash/Prompt_customization.
Mais que mettre dedans ? Je suis tombé sur différentes méthodes de création de fonctions bash qui permettent de le faire (un bon condensé est disponible ici : https://askubuntu.com/questions/730754/how-do-i-show-the-git-branch-with-colours-in-bash-prompt). Il y a de tout, ça fonctionne mais je cherchais une solution un peu "officielle" quand même.
Finalement, la solution était sous mon nez, dans la documentation Git : https://git-scm.com/book/en/v2/Appendix-A:-Git-in-Other-Environments-Git-in-Bash.
Un ensemble de scripts bash ont été développé pour permettre exactement ce que je souhaite faire : autocomplétion et affichage du nom de la branche dans le terminal. C'est versionné avec le code source de git par ici : https://github.com/git/git/tree/master/contrib/completion
Le fichier qui va nous intéresser est git-prompt.sh (la documentation d'usage est dans les commentaires du fichier).
Basiquement, il met à disposition une fonction __git_ps1 qui va nous retourner le nom de la branche active pour un répertoire git ainsi que d'autres informations utiles comme :
- est-ce que des fichiers nouveau non versionnés sont présents ?
- est-ce que des fichiers versionnés ont été modifiés ?
- quel est l'état de ma branche par rapport à la remote ?
- etc.
Donc plutôt intéressant.
Autre fait intéressant : selon la distribution et la version de git installée, les fichiers vont carrément être présent sur votre machine et le actif dans le bash. Pour le savoir, dans le terminal, appelez la fonction avec un echo devrait vous apporter la réponse
$ echo $(__git_ps1)
<nom de branche ou ligne vide>
$
Si rien ne s'affiche (vous n'êtes pas dans un répertoire versionné par git) ou si un nom de branche s'affiche, c'est bon, la fonction est accessible. Si une erreur vous indique -bash : __git_ps1; command not found, vous êtes bon pour faire une installation manuelle.
Il est possible que le fichier git-prompt.sh soit présent sur votre poste, auquel cas un petit find vous permettra de le trouver.
Sinon, la solution la plus simple à mon sens est de télécharger le fichier depuis le repo Git et de le stocker dans votre home (personnellement, je l'ai mis dans ~/.config/git/, libre à vous de vous organiser comme vous voulez). Il est trouvable ici : https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh
Il faudra ensuite l'importer dans votre fichier .bashrc (rappel : le fichier est à la racine du répertoire home) :
PATH_GIT_PROMPT="$HOME/.config/git/git-prompt.sh" #Le chemin d'accès au fichier
if [ -f "$PATH_GIT_PROMPT" ]; then # On vérifie que le fichier existe bien, pour éviter les erreurs d'import
#Execution du script bash permettant d'accéder à __git_ps1
. "$PATH_GIT_PROMPT"
fi
Après fermeture/relance de votre terminal, la commande echo $(__git_ps1) ne devrait plus retourner d'erreur.
Ensuite, intéressons-nous à la configuration de la variable $PS1. Sous Debian/Ubuntu, j'ai toujours trouvé dans le .bashrc le code de configuration de cette variable, de cette forme-là :
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi
L'idée, c'est de reprendre le même et d'ajouter à la fin l'appel à git_ps1, comme décrit dans les commentaires du fichier. Le prompt évolue donc comme suit (attention, l'import de la fonction doit être réalisé avant ce code) :
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]$(__git_ps1 "%s")\$ '
else
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w$(git_ps1 "%s")\$ '
fi
Fermez et rouvrez votre terminal et aller dans un répertoire versionné sous git : le nom de branche devrait s'afficher !
Au passage, je suis un poil bourin sur le $PS1 car je l'écrase complètement, sans tenir compte d'autres scripts qui pourraient le mettre à jour. Cela fonctionne chez moi mais si vous avez des données en plus, il faudra gérer différemment.
Mais on peut aller encore plus loin grâce à de la configuration de variable d'environnements, gérées par le script. Le principe est simple : soit la variable existe et le script ajoute des informations, soit la variable n'existe pas et l'information n'est pas présentée. Je vous renvoie vers les commentaires du fichier pour le détail complet.
À titre personnel, j'ai mis à jour les variables suivantes, libre à vous de choisir ce qui vous convient le mieux :
GIT_PS1_SHOWUNTRACKEDFILES=1 #Ajoutera un % pour indiquer des fichiers nouveaux non versionnés/non ignorés. Utile pour éviter d'oublier des fichiers
GIT_PS1_SHOWCOLORHINTS=1 #Affichage en couleur, parce que plus joli
GIT_PS1_SHOWDIRTYSTATE=1 #Affichera une étoile et un + pour indiquer la présence de fichiers unstages/staged (et donc qu'il y a des modifications à commiter)
GIT_PS1_SHOWCONFLICTSTATE="yes" #Affichera |CONFLICT s'il y a des conflits de merge en cours. Pratique quand on décide de faire une ause avant de s'y mettre et qu'on oublie ;)
Et voilà !
La complétion avec git
Je suis du genre à faire des noms de branche à rallonge, pour bien me rappeler ce que je traite (une branche fix-config par exemple, j'oublie vite ce que j'essayais de modifier dans la configuration). Sans autocomplétion, ça devient vite long de taper des noms de branche long.
Mais là encore, les petits scripts mis à disposition dans le repo git nous seront utiles. Cette fois, on va s'intéresser à git-completion.bash qui va rajouter des routines permettant l'autocomplétion https://github.com/git/git/blob/master/contrib/completion/git-completion.bash.
Si le la fonction __git_ps1 était innaccessible, il y a des chances que ça sera de même pour ce fichier. Il est peut-être lui aussi déjà sur vore poste mais là encore je ne me suis pas trop pris la tête, je l'ai rajouté dans mon répertoire ~/.config/git/.
Ensuite, on peut modifier notre .bashrc pour ajouter l'import :
PATH_GIT_COMPLETION="$HOME/.config/git/git-completion.bash" #Le chemin d'accès au fichier
if [ -f "$PATH_GIT_COMPLETION" ]; then # On vérifie que le fichier existe bien pour éviter de générer des erreurs
source "$PATH_GIT_COMPLETION" # on ajoute à la liste des routines pour l'autocomplétion
fi
On relance le terminal et si on commence à taper git che depuis un répertoire versionné et qu'on appuie sur Tabulation, on devrait voir une liste de commande disponible (checkout, cherry, cherry-pick). Si on continue git chec et qu'on appuie sur tabulation, c'est auto-complété en git checkout .
Une petite tabulation plus loin affiche les noms de branche, tags et pointeurs disponibles. Commencer à taper le nom de la branche autocomplete, c'est cool.
Là encore, il y a quelques variables à mettre à jour pour modifier le comportement. Je vous renvois vers le fichier directement, la configuration par défaut me convient pour ma part. Le projet contient aussi des fichiers .tsch et .zsh, je suppose que ça s'applique à ces deux shells.
Dernière étape : on documente tout ça pour la prochaine fois et on est bon (article de blog fait, ça peut servir à quelqu'un d'autre) ! Libre à vous ensuite de modifier un peu ça (saut à la ligne, ajout d'émoji si votre terminal le gère, etc.)
La configuration finale
En supposant les fichiers git-prompt.sh et git-completion.bash dans un dossier ~/.config/git/, le morceau de bash à ajouter au .bashrc est le suivant :
###########################################
# Affichage des noms de branche dans le prompt bash
###########################################
PATH_GIT_PROMPT="$HOME/.config/git/git-prompt.sh" #Le chemin d'accès au fichier
if [ -f "$PATH_GIT_PROMPT" ]; then # On vérifie que le fichier existe bien, pour éviter les erreurs d'import
#Execution du script bash permettant d'accéder à __git_ps1
. "$PATH_GIT_PROMPT"
GIT_PS1_SHOWUNTRACKEDFILES=1 #Ajoutera un % pour indiquer des fichiers nouveaux non versionnés/non ignorés. Utile pour éviter d'oublier des fichiers
GIT_PS1_SHOWCOLORHINTS=1 #Affichage en couleur, parce que plus joli
GIT_PS1_SHOWDIRTYSTATE=1 #Affichera une étoile et un + pour indiquer la présence de fichiers unstages/staged (et donc qu'il y a des modifications à commiter)
GIT_PS1_SHOWCONFLICTSTATE="yes" #Affichera |CONFLICT s'il y a des conflits de merge en cours. Pratique quand on décide de faire une ause avant de s'y mettre et qu'on oublie ;)
# Mise à jour du prompt
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]$(__git_ps1 "%s")\$ '
else
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w$(git_ps1 "%s")\$ '
fi
fi
###########################################
# Autocomplétion git sous bash
###########################################
PATH_GIT_COMPLETION="$HOME/.config/git/git-completion.bash" #Le chemin d'accès au fichier
if [ -f "$PATH_GIT_COMPLETION" ]; then # On vérifie que le fichier existe bien pour éviter de générer des erreurs
source "$PATH_GIT_COMPLETION" # on ajoute à la liste des routines pour l'autocomplétion
fi