Le prompt Bash qui change la vie avec Git
Par Christophe Porteneuve • Publié le 14 juillet 2010 • 2 min

Lors de l’atelier de samedi je vous ai promis un prompt Bash qui déboîte quand on fait du Git.

Celui-ci repose sur une série de fonctions Bash dont la plus “high-level” est appelée à chaque prompt. Elle permet de voir immédiatement :

  • Dans quelle branche on est
  • Si on a des modifs en working tree
  • Si on a des modifs en stage
  • Si on a des fichiers untracked
  • Si on a du stash

Toutes choses fort utiles au moment de faire son commit, histoire de ne rien oublier…

Cet article est obsolète ; vous trouverez une version plus à jour et plus utile dans l’article plus récent « Un prompt Git qui déchire ».

Voici le code source avec quelques commentaires. Vous pouvez aussi aller piocher le Gist directement.

# Scavenged from Git 1.6.5.x contrib/completion/git_completion.bash
# __git_ps1 accepts 0 or 1 arguments (i.e., format string)
# returns text to add to bash PS1 prompt (includes branch name)
__gitdir ()
{
if [ -z "${1-}" ]; then
if [ -n "${__git_dir-}" ]; then
echo "$__git_dir"
elif [ -d .git ]; then
echo .git
else
git rev-parse --git-dir 2>/dev/null
fi
elif [ -d "$1/.git" ]; then
echo "$1/.git"
else
echo "$1"
fi
}
__git_ps1 ()
{
local g="$(__gitdir)"
if [ -n "$g" ]; then
local r
local b
if [ -f "$g/rebase-merge/interactive" ]; then
r="|REBASE-i"
b="$(cat "$g/rebase-merge/head-name")"
elif [ -d "$g/rebase-merge" ]; then
r="|REBASE-m"
b="$(cat "$g/rebase-merge/head-name")"
else
if [ -d "$g/rebase-apply" ]; then
if [ -f "$g/rebase-apply/rebasing" ]; then
r="|REBASE"
elif [ -f "$g/rebase-apply/applying" ]; then
r="|AM"
else
r="|AM/REBASE"
fi
elif [ -f "$g/MERGE_HEAD" ]; then
r="|MERGING"
elif [ -f "$g/BISECT_LOG" ]; then
r="|BISECTING"
fi

b="$(git symbolic-ref HEAD 2>/dev/null)" || {

b="$(
case "${GIT_PS1_DESCRIBE_STYLE-}" in
(contains)
git describe --contains HEAD ;;
(branch)
git describe --contains --all HEAD ;;
(describe)
git describe HEAD ;;
(* | default)
git describe --exact-match HEAD ;;
esac 2>/dev/null)
"
||

b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
b="unknown"
b="($b)"
}
fi

local w
local i
local s
local u
local c

if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
c="BARE:"
else
b="GIT_DIR!"
fi
elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then
if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then
git diff --no-ext-diff --ignore-submodules \
--quiet --exit-code || w="*"
if git rev-parse --quiet --verify HEAD >/dev/null; then
git diff-index --cached --quiet \
--ignore-submodules HEAD -- || i="+"
else
i="#"
fi
fi
fi
if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then
git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$"
fi

if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then
if [ -n "$(git ls-files --others --exclude-standard)" ]; then
u="%"
fi
fi
fi

if [ -n "${1-}" ]; then
printf "$1" "$c${b##refs/heads/}$w$i$s$u$r"
else
printf " (%s)" "$c${b##refs/heads/}$w$i$s$u$r"
fi
fi
}

export GIT_PS1_SHOWDIRTYSTATE=1 GIT_PS1_SHOWUNTRACKEDFILES=1 GIT_PS1_SHOWSTASHSTATE=1

# Basique…
# export PS1='\u@\h:\W$(__git_ps1) \$ '
# Avec plein de couleurs…
export PS1='\[\033[0;37m\]\u@\h:\[\033[0;33m\]\W\[\033[0m\]\[\033[1;32m\]$(__git_ps1)\[\033[0m\] \$ '

Notez les variables qui configurent ce qui est affiché :

  • GIT_PS1_SHOWDIRTYSTATE fait remonter les modifs en working tree (symbole *) et en stage (symbole +)
  • GIT_PS1_SHOWUNTRACKED_FILES fait remonter les fichiers non présents dans l’index (non pris en compte jusqu’à ajout explicite) (symbole %)
  • GIT_PS1_SHOWSTASHSTATE indique qu’on a des trucs dans le stash (symbole $)

Ça ralentit un tout petit peu le premier prompt de votre session dans un dépôt non trivial, le temps pour les commandes Git internes de construire les caches d’accès à l’index et à l’historique… Ensuite c’est instantané.

Je ne pourrais pas vivre sans !

Enjoy!

Découvrez nos cours vidéo ! 🖥

Nos cours vidéo sont un complément idéal et bon marché à nos articles techniques et formations présentielles. Autour de Git, de JavaScript et d’autres sujets, retrouvez des contenus de très grande qualité à des prix abordables, spécialement conçus pour lever vos plus gros points de blocage.