Git-Branch im Bash-Prompt anzeigen
Meine kleinen Coding-Projekte setze ich meistens, direkt auf der Kommandozeile, mit dem Editor vim
um. Ich arbeite eher selten in dem grafischen Editor VSCodium
und noch weniger in einer Entwicklungsumgebung (IDE) wie Eclipse, Netbeans oder IntelliJ. Gerade die grafischen Tools integrieren die Versionsverwaltung git sehr gut und man hat als Entwickler jederzeit den Einblick, wie es um die Versionierung steht. Auf der Kommandozeile sehe ich das nur, wenn ich die jeweiligen Befehle wie z. B. git branch
oder git log
eingebe.
Vor ein paar Wochen ist es dann zum wiederholten Mal passiert: Ich hatte im falschen Branch gearbeitet (genervter Blick).
Mein Gedanke: Das passiert mir nicht nochmal … ich will den jeweiligen Branch im Shell-Prompt sehen, sofern ich in einem git-Repo arbeite. Wie ich das umgesetzt hab, dokumentiere ich im folgenden Beitrag.
Mir ist bekannt dass es für meinen Bedarf schon komplett fertige Lösungen gibt. Mit Projekten wie https://ohmyposh.dev (Bash) oder https://ohmyz.sh/ (zsh) bekommt man schöne Prompts vor’s Auge gezaubert, die den jeweiligen Status im Branch anzeigen.
Diese Lösungen kommen für mich jedoch nicht in Frage, weil es entweder zu bunt oder zu überladen ist. Ich will einfach nur meinen Editor auf der Konsole bedienen und mit wenigen Zeilen Code einen kleinen Hinweis erhalten, auf welchem git Branch ich mich gerade befinde. Den Prompt auf meinen Clients hatte ich sowieso schon (in Anlehnung an den Bash-Prompt von Kali-Linux) angepasst. Daher dachte ich mir, diese kleine Optimierung kann nicht so schwer sein. Das Ergebnis soll dann wie folgt aussehen:
Die Konfiguration des Standard-Prompts (primary prompt) der bash erfolgt über die Variable PS1
die man entweder systemweit in der /etc/profile
hinterlegt oder User-spezifisch im Verzeichnis ~/.bashrc
. Da auf einem Multiuser-System, jeder User seinen eigenen Prompt generieren dürfen soll, wähle ich die Option mit der ~/.bashrc
.
Bei der Erstellung des Prompts können “special characters” verwendet werden (eben auch Variablen), die je nach Hostname, Username oder aktuellem Verzeichnis den Prompt generieren. Ein Debian-System (und viele andere Distros) hat initial folgenden Prompt:
Mein Test-Benutzer yoda auf der Maschine debvm befindet sich derzeit im Homeverzeichnis (~). Möchte man die Darstellung nun anpassen, hinterlegt man eine passende Zeichenkette in der Variable PS1
. Für Testzwecke kann das direkt auf der Kommandozeile eingegeben werden:
Möchte ich den Standard-Prompt nachbilden, können die eben genannten “special characters” (Begriff aus der Man-Page) genutzt werden. Eine erneute Zuweisung zur Variable PS1
sieht wie folgt aus:
PS1="\u@\h:\w\$ "
Geben wir das auf der Konsole ein, sieht das Ergebnis dem Standardprompt schon recht ähnlich:
Bedeutung der Variablen:
Zeichen | Bedeutung |
---|---|
\u | Username |
@ | Normales Zeichen, das im Prompt dargestellt wird |
\h | Hostname |
: | Normales Zeichen, das im Prompt dargestellt wird |
\w | Aktuelles Arbeitsverzeichnis |
\$ | Indikator für einen eingeschränkten User, der als Zeichen im Prompt dargestellt wird |
Die farbliche Gestaltung ist darüber hinaus etwas komplizierter. Farben werden mit einer Art Tag (ähnich HTML) eingeleitet. Der korrekte Begriff lautet “Escape-Sequenz”. \[\033
oder \[\e
leitet die Zeichenformatierung ein, gefolgt von einer Zeichenkette [<ZAHL>m\]
¸ die beispielsweise den Text oder den Hintergrund farbig darstellt.
Das kann ziemlich “frickelig” sein. Soll der komplette Prompt in grün erscheinen, kann das wie folgt umgesetzt werden:
Man kann erkennen, dass schon ein einfacher Prompt sehr schnell recht unübersichtlich werden kann. Letztendlich instruiert \[\e[32m\]
, dass alle nachfolgenden Zeichen in grüner Farbe dargestellt werden. Am Ende der Zeile sorgt die Sequenz \[\e[m\]
dafür, dass an dieser Stelle der Farbverlauf endet. Alles danach wird wieder wie gewohnt dargestellt.
Die Zeichenfolge 32m
steht dabei für grün. Weitere Farben sind möglich. Ich benötige später gelb (33m), grau (37m) und rot (31m). Nicht weil diese Farben besonders schön sind, sondern weil mir die farbig hinterlegten Bestandteile gut ins Auge fallen.
Eine etwas ausführlichere Erklärung zu den Farbcodes hab ich hier gefunden. Eine entsprechende Man-Page man console_codes
gibt es ebenfalls. Wer hier zusätzliche Unterstützung möchte, sucht sich im Netz einen Bash-Prompt-Generator. Die können häufig ebenfalls farbige Prompts generieren.
Mit den genannten Möglichkeiten, hatte meine Variable PS1
bisher folgenden Aufbau:
PS1="\n┌── \[\e[33m\]\A \[\e[m\]- \[\e[37m\]\u@\h\[\e[m\]: \[\e[33m\][ \w ]\[\e[m\]\n└─\$ "
Der Prompt stellt sich wie folgt dar:
Der Aufbau hat sich aus folgenden Gründen bewährt:
- Uhrzeit vorne: Manchmal führe ich ein Skript aus, das längere Zeit läuft. Da schau ich nicht zu und drehe Däumchen. Wenn das Skript fertig ist, sehe ich anhand des neuen Prompts, wie lange das Ding gelaufen ist.
- Angabe von Usernamen und Host (wie im Standard-Prompt)
- Arbeitsverzeichnis (wie im Standard-Prompt)
- Kommando-Eingabe in der zweiten Zeile: Der gesamte Pfad des aktuellen Arbeitsverzeichnisses kann sehr lang sein. Dann brechen die Befehle im Standardprompt hässlich um. Durch die Eingabe meines Kommandos in der zweiten Zeile umgehe ich das. Wie oben beschrieben: Das ist jetzt keine geniale Eigenleistung. Ich hatte das in der Distro Kali-Linux aufgeschnappt und empfand diese Darstellung praktisch.
Um meinem eigentlichen Ziel näher zu kommen, brauche ich eine Funktion in der Datei ~/.bashrc
. Diese soll prüfen ob ich in einem Branch bin:
function check_branch {
if git status > /dev/null 2>&1; then
branch="<<< $(printf '\uE0A0') $(git branch --show current) >>>"
else
branch=""
fi
}
Es wird in der Bedingungsprüfung der Befehl git status
ausgeführt, jedoch sämtliche Ausgaben nach /dev/null
geschoben. Das System registriert dabei jedoch, ob der Return-Wert des letzten Befehls 0 (=wahr) ist oder nicht. Ist das der Fall wird eine Zeichenkette gebaut die ein kleines Symbol \uE0A0
(dieser abzweigende Pfeil) und den aktuellen Branch zurück gibt. Andernfalls ist die Zeichenkette leer.
Bleibt die Frage, wann die Funktion aufgerufen wird? Im Prinzip möchte ich bei jedem Bestätigen mit der Eingabetaste checken, ob ich derzeit in einem git-Repo arbeite. Hierfür gibt es eine Variable PROMPT_COMMAND
. Deren Inhalt wird ausgeführt, bevor ein neuer Prompt in der Kommandozeile angezeigt wird. Daher erfolgt der Funktionsaufruf per Zuweisung an diese Variable:
PROMPT_COMMAND="check_branch"
Zuletzt muss noch der Variable PS1
die Prompt-Struktur in leicht abgewandelter Form (mit zusätzlicher Variable $branch
) zugewiesen werden:
PS1="\n┌── \[\e[33m\]\A \[\e[m\]- \[\e[37m\]\u@\h\[\e[m\]: \[\e[33m\][ \w ]\[\e[m\] \[\e[31m\]\$branch \[\e[m\]\n└─\$ "
Die drei Bausteine liegen hintereinander in der erwähnten ~/.bashrc
. Jedes Mal wenn ich nach einer Eingabe die Enter-Taste drücke, wird die Variable PROMPT_COMMAND
ausgelesen und die Funktion check_branch
aufgerufen, die mir eine Zeichenkette baut (entsprechender Branch oder leere Zeichenkette). Das Ergebnis sieht dann wie folgt aus:
Ich bin mit dem Ergebnis erstmal zufrieden. Klar … es können noch weitere nützliche Infos hinterlegt werden. Aber das reicht mir für’s Erste. Die Variable PROMPT_COMMAND
benötige ich noch für ein weiteres Szenario. Das beschreibe ich in einem folgenden Beitrag hier.
Ich hatte die Möglichkeit mit einem 32MB großen Fertig-Gericht (https://ohmyposh.dev/) oder mit 8 Zeilen Code mein Ziel zu erreichen. Der Zeitaufwand hier, ist eher in den Blog-Beitrag als in die reine Umsetzung geflossen. Hätte ich mich für ohmyposh entschieden, hätte ich wahrscheinlich meine Zeit mit der Auswahl von Themes und deren Anpassung verbraten (siehe: ohmyposh themes).