Aus Linux-Magazin 04/2019

Tricks und Tipps rund um Git

© langstrup, 123RF

Wer bei Suse arbeitet, absolviert in der Regel eine tägliche Trainingseinheit mit Git. Dabei kristallisieren sich im Laufe der Zeit automatisch Best Practises heraus. Der Artikel zeigt einige Git-Kniffe der Profis.

“Du kennst da doch sicher einige Git-Profis”, fragte mich ein Linux-Magazin-Redakteur vor ein paar Tagen. Ich antwortete “Klar, ich frag mal bei uns auf der Research-Mailingliste nach. Die Kollegen arbeiten jeden Tag mit Git, da finden sich sicher gute Ideen und wertvolle Tipps.” Dass ich mit dieser Anfrage einen mehrtägigen Thread lostreten würde (Abbildung 1), hatte ich nicht erwartet.

Abbildung 1: Der Thread mit Git-Tipps auf der internen Suse-Mailingliste wuchs schnell an.

Abbildung 1: Der Thread mit Git-Tipps auf der internen Suse-Mailingliste wuchs schnell an.

Anzahl und Qualität der eingereichten Tipps zeigen, wie wichtig das Werkzeug zur Versionskontrolle für Entwickler bei Suse ist. Binnen weniger Stunden war klar, dass der Platz im Artikel nicht ausreichen wird, um alle Hacks darzustellen.

Wem die hier genannten Tipps und Tricks nicht genügen, findet online zahlreiche weitere: Die Links am Ende des Artikels versammeln exemplarisch einige davon, die sich gleichermaßen an Anfänger und Git-Kenner richten. So zählt [1] nützliche Git-Kommandos auf, kommen unter [2] “Pro-Tipps” aus den Reihen der Kollegen von Fedora und finden sich unter [3] so genannte Cheat Sheets mit den wichtigsten Git-Kommandos.

Auch das Dokumentationsteam nutzt Git täglich [4], mit »git-flow« als ausgefuchstem Workflow mit Branches inklusive gleichnamigen Werkzeugen [5]. Für die interne Dokumentation der Tipps und Tricks zur Versionsverwaltung dient dabei das Trello-Board aus Abbildung 2. Hier haben sich über die Jahre zahllose Kurzanleitungen angesammelt. Diese reichen vom Einstieg bis zu hochspezifischen Lösungen für die Bedürfnisse eines Dokumentations-Teams. Aus diesem Fundus stammen auch die ersten fünf Tipps – eingereicht vom technischen Redakteur Thomas Schraitle.

Abbildung 2: Das Dokumentationsteam von Suse verwendet Trellos Kanban-Boards für fast alle Aufgaben. Auch die besten Git-Tipps für neue Suse-Mitarbeiter sammeln die Doku-Spezialisten hier.

Abbildung 2: Das Dokumentationsteam von Suse verwendet Trellos Kanban-Boards für fast alle Aufgaben. Auch die besten Git-Tipps für neue Suse-Mitarbeiter sammeln die Doku-Spezialisten hier.

Tipp 1: Fehlersuche

Nicht nur für Git-Anfänger erweist sich die Grafik in Abbildung 3 als äußerst hilfreich: Sie zeigt ein zugegeben komplexes Baumdiagramm als Prozedur fürs Aufräumen nach der Arbeit an einem Projekt. Am Ende der Entscheidungsketten stehen meist simple Git-Kommandos, ein “Mulligan – Fang noch mal von vorne an” oder aber das beruhigende “Alles wird gut”. Mehr Informationen zu dem Thema gibt es unter [6] und [7].

Abbildung 3: Git Pretty liefert einen Entscheidungsbaum fürs Aufräumen im eigenen Git-Repository.

Abbildung 3: Git Pretty liefert einen Entscheidungsbaum fürs Aufräumen im eigenen Git-Repository.

Tipp 2: Interaktiv, bitte!

Es kommt immer wieder vor, dass der Anwender interaktiv entscheiden möchte, was für Code er genau hinzufügen und in seinem Projekt ergänzen möchte. Wem ein »git add« nicht reicht, der sollte sich »git add -i« (für »–interactive«) oder »git gui« ansehen. Letzteres öffnet eine Tcl-Tk-Benutzeroberfläche, über die der Entwickler neue Commits anlegt oder bestehende ändert. Git-Gui erzeugt auch neue Branches, es kommt mit Stages und Änderungen zurecht und bringt weitere Funktionen mit (siehe auch den Artikel zu Git-GUIs auf Seite 42).

Etwas schlanker präsentiert sich »git add -i« in Listing 1. Das zeigt drei noch nicht für ein Commit vorbereitete Änderungen in einer Datei namens »README.adoc«, wobei die Ausgabe einem »git status« ähnelt. Das »+3/-1« in Zeile 2 bedeutet: Programmierer haben drei Zeilen ergänzt und eine entfernt. Mit einem [P]+ und [Eingabe] startet der User das Patching, danach erwartet Git die Nummer eines auszuwählenden Files (hier die »1«) und zeigt sofort die Änderungen an.

Listing 1

git add -i

01          staged   unstaged  path
02 1:    unchanged      +3/-1  README.adoc
03
04 *** Commands ***
05 1: status  2: update  3: revert  4: add untracked
06 5: patch   6: diff    7: quit    8: help
07 What now>

Über [?]+ erhält der Anwender Hilfe. Normalerweise geht er jetzt eine Änderung nach der anderen durch und bestätigt sie mit [Y]+ oder lehnt sie mit [N]+ ab. Drückt er [D]+ gefolgt von der Nummer der zu bearbeitenden Datei, erscheint ein Diff. [Q] beendet den Viewer und bringt den Anwender zurück zur Shell, wo er wie gewohnt Code ergänzt. Weitere Hilfestellung im Detail bietet [8].

Tipp 3: Wer hat was committed?

Fast jeder kennt das Kommando »git blame«, schreibt Thomas, aber dass die Option »-L« einen Start- und einen Endwert akzeptiert, ist weniger bekannt: Damit lässt sich für einen definierten Abschnitt an Zeilen anzeigen, wer wann was geändert hat. Auch Github kennt diese Funktion: Die Schaltfläche »Blame« visualisiert die Ausgabe im Web und zeigt Autor, Commit-Nachricht, SHA-Summe sowie die geänderten Zeilen. Wer Emacs mag, findet die Blame-Funktion via »M-x git blame-mode«, wenn er die Erweiterung »git-mode« installiert.

Suse-Entwickler Benjamin Poirier hat sich dafür ein Vim-Kommando eingerichtet, das ihm die Geschichte des Codes in Git-Gui anzeigt, via »git gui blame« (Listing 2). Wer das will, ergänzt den Code aus dem Listing in seiner ».vimrc«-Datei und gibt in einer Git-Session in Vim »:GGBlame« ein (oder »GG« und [Tab]).

Listing 2

Vim-Kommando-Plugin für git blame gui

01 function LaunchGGBlame()
02         let cmd = printf("cd %s && git gui blame --line=%d %s &", expand("%:p:h::S"), line("."), expand("%:p::S"))
03         let output = system(cmd)
04         " if the background command fails, we won't know because of &
05         if v:shell_error != 0
06                 let msg = printf("Error running '%s': %s", cmd, output)
07                 echohl WarningMsg | echon msg | echohl None
08                 return
09         endif
10 endfunction
11 command GGBlame call LaunchGGBlame()

Tipp 4: Ignorieren!

Git kennt mindestens drei Konfigurationsdateien, in denen sich Dateien auflisten lassen, die Git ignorieren soll:

  • ».gitignore«: Hier ist richtig, wer in seinem aktuellen Repository für alle Anwender eine Ausschlussliste anlegen möchte.
  • ».git/info/exclude«: Die hier gelisteten Regeln für auszuschließende Dateien gelten nur für das einzelne Repository, sie betreffen niemanden sonst und nur den lokalen Rechner.
  • »~/.gitignore« verhält sich ähnlich wie ».git/info/exclude«, gilt aber für alle Repositories der lokalen Maschine.

Wer das Letztgenannte global einsetzen möchte, verwendet das Kommando:

git config --global core.excludesfile ~/.gitignore

Wer sich noch tiefgehender in Gitignore einarbeiten möchte, findet unter [9] weiterführende Informationen. Außerdem kommt an dieser Stelle womöglich auch ein Werkzeug von Suses Senior Engineer Adam Spiers gerade recht: Er hat »git check-ignore« [10] entwickelt. Das ist in Git integriert und prüft für Dateien und Pfadnamen, ob diese auf einer der lokalen Ignorier-Listen stehen oder nicht. Auf diese Weise vermeiden Entwickler bei der Arbeit mit fremden Repositorys Überraschungen.

Tipp 5: Nachträglich…

Einen weiteren Tipp von Thomas wenden Entwickler besser nicht auf öffentliche Commits an: Git erlaubt es, einen Commit nachträglich um ganze Dateien zu ergänzen. Wer also mit »git add« Dateien auf die Bühne geschickt und bereits über »git commit« in das Repository eingecheckt hat, dabei aber einige Dateien vergessen hat, bessert mit »git commit –amend« später nach.

Zunächst ruft der Entwicker einfach erneut »git add« auf und gibt in diesem Zug die vergessene Datei als Parameter an. Danach kommt das erwähnte »git commit –amend« ins Spiel, das die Commit-Nachricht des vorherigen Commits im Editor anzeigt. Wer will, ändert diese jetzt, ein Muss ist das aber nicht. Amend unterstützt übrigens auch »rm« fürs nachträgliche Entfernen weiterer Dateien. Mehr Infos dazu stehen im Wiki von Atlassian [11].

Tipp 6: Stapeln mit Stash

Wer kennt das nicht: Ein Entwickler arbeitet an einer wichtigen Sache. Der Chef kommt mit einer neuen, sehr wichtigen Aufgabe. Die hat plötzlich Priorität, die Arbeit an der alten Aufgabe soll er zu einem späteren Zeitpunkt fortsetzen. Zugleich soll der Entwickler den Code zur neuen Aufgabe aber vor dem der ursprünglichen einchecken.

Git kennt für solche Situationen ein Konzept namens Stashing: Dabei landen Änderungen, die der Entwickler noch nicht eingecheckt hat, auf Stapeln (Stashes). Die bearbeitet er dann später weiter.

»git status« zeigt zunächst die Liste der geänderten Dateien an, »git stash« schiebt diese Änderungen auf einen Stapel. Jetzt lässt sich vortrefflich an der neuen Aufgabe arbeiten. Nach getaner Arbeit ruft der Entwickler »git stash pop« auf, und schon kann er an der Stelle weiterarbeiten, die ihn vor der Unterbrechung beschäftigt hat. Git Stash lässt sich mehrfach verschachteln, deshalb existieren Kommandos wie:

  • »git stash list«: listet alle Stashes
  • »git stash drop«: entfernt dann den letzten Stapel
  • »git stash branch test«: erzeugt einen neuen Branch basierend auf dem Stash

Achtung: Stash arbeitet standardmäßig nur auf hinzugefügten Dateien. Wer auch nicht überwachte Dateien auf seinem Stapel haben möchte, muss diese mit »git add –all« und »git stash« explizit ergänzen. Mehr Infos dazu gibt es im Git-SCM [12].

Tipp 7: In Memoriam Mercurial

Open-Attic-Urgestein und -Entwickler Lenz Grimmer schrieb: “Unser Team ist an der Entwicklung der Ceph-Managementlösung Open Attic und ihrem Nachfolger, dem Ceph Dashboard beteiligt. Wir haben im April 2017 unser Open-Attic-Code-Repository von Mercurial zu Git migriert [13]. Als ehemalige Mercurial-Nutzer haben uns bei Git ein paar Kommandos gefehlt, die wir als Aliase in der »~/.gitconfig« nachgebaut haben” (Listing 3).

Listing 3

Nützliche Aliase für Mercurial-Umsteiger

01 [alias]
02   branches = !git branch --list
03   ci = commit
04   out = !git fetch && git log FETCH_HEAD..
05   outgoing = !git fetch && git log FETCH_HEAD..
06   in = !git fetch && git log ..FETCH_HEAD
07   incoming = !git fetch && git log ..FETCH_HEAD
08   tags = !git tag --list

Tipp 8: Großreinemachen

Stephan Müller hat die Funktion aus Listing 4 in seine »zshrc« eingebaut, um sich das Leben mit Git und Submodules einfacher zu machen. Aber Vorsicht, das räumt komplett und unwiederbringlich auf. Alle Untermodule sind nach diesem Kommando so frisch wie nach einem neuen Clone-Vorgang!

Listing 4

Aufräumen in den Untermodulen

01 gitCleanSubmodules(){
02   git submodule sync
03   git submodule update -f --recursive --remote
04   git submodule foreach --recursive git clean -xfd
05   git submodule foreach --recursive git reset --hard
06   git submodule update -f --recursive --init
07 }

Tipp 9: Git-Vimdiff

Von Matt Oliver stammt der Verweis auf »git-vimdiff« (Abbildung 4, [14]). Über das normale Vimdiff hinaus, das sich auch mit Git verbinden lässt, bietet Git-Vimdiff jede Datei in einem separaten Tab an. Durch die blättert der Vim-User bequem vor und zurück. “Ich verwende das so oft mittlerweile: Jedes Mal, wenn ich in Gerrit oder Github ein neues Patchset durchgehe, springe ich nur in den Branch und rufe »git vimdiff HEAD~« auf.” Dann könne er die Diffs der Reihe nach durchgehen und parallel dazu die Reviewer-Kommentare lesen.

Abbildung 4: Suse-Entwickler Matt Oliver nennt »git-vimdiff« "einen der produktivsten Git-Hacks, den ich regelmäßig verwende".

Abbildung 4: Suse-Entwickler Matt Oliver nennt »git-vimdiff« “einen der produktivsten Git-Hacks, den ich regelmäßig verwende”.

Tipp 10: Automatische Analyse

Unverschämte Werbung in eigener Sache macht Adam Spiers bei Git-Deps [15]: “Ich glaube, ich muss hier auf eines meiner Projekte verweisen…”. Sein Tool dient zur automatischen Analyse von Abhängigkeiten zwischen Commits in einem Git Repository. Dafür gibt es laut Spiers jede Menge Anwendungsfälle, beispielsweise:

  • das Porting zwischen Branches
  • eine Patch-Serie in unabhängige Teile aufzuspalten
  • die Zusammenarbeit in Entwicklerteams zu unterstützen
  • das automatische Integrieren von Fix-up-Commits

Das Tool hilft auch einfach beim Aufräumen der privaten Commit-Historie vor einer Veröffentlichung.

Tipp 11: Fixups und Rebases

Alvaro Saurin betont, wie wichtig das richtige Verständnis von »git commit –fixup=Commit« und seinem Pendant »git rebase –autosquash« sei. Im Beispiel ist der Entwickler an folgender Stelle:

Master -> Änderung 2 -> Änderung 1 -> Aktuelle Änderung

Im nächsten Schritt könnte er dann einen Fixup-Commit für »Änderung 2« veranlassen. Das passende Kommando dazu lautet »git commit –fixup=HEAD~1«. Das Ergebnis würde so aussehen:

Master -> Änderung 2 -> Änderung 1 -> Fixup-Commit-für-Änderung-2

Ein anschließendes »git rebase -i –autosquash« verschmilzt dann den Fixup automatisch mit der Änderung 2 (hier in zwei Schritten gezeigt):

Master -> Änderung 2 -> Fixup-für-Änderung-2 -> Änderung 1 Master -> Neue Änderung 2 -> Änderung 1

Diese Abfolge von Schritten ließe sich auch als ein Git-Alias definieren und in einem Schritt durchziehen. Wie das funktioniert, zeigt Entwickler Bernhard Wiedemann im folgenden Listing:

[alias]
    pushf = push --force-with-lease
    ri = rebase --interactive --autosquash

Und dieser ließe sich – wie Benjamin Zeller anmerkt – via Git-Konfiguration als Default aktivieren.

Auf den Alias hingegen verzichten kann, wer Adam Spiers Git-Fixup [17] verwendet. Der Entwickler ist überzeugt, das beschriebene Konzept sei eines der fundamentalsten in Git, die ein Entwickler verstehen sollte.

Es lasse sich zudem – wenig überraschend – auch in Emacs einbetten und mit nur drei Tasten aufrufen. Dabei öffnet [C]+ das Commit-Menü, [F]+ startet den Instant Fixup, woraufhin der Anwender auswählen darf, was er fixen möchte. Ein [.] veranlasst Emacs, den Fixup Commit zu erzeugen, wobei er automatisch alle noch nicht erfassten Änderungen durchläuft, das interaktive Rebasing vornimmt und am Ende sogar den Stash verlässt. Letzteres klappt über das weiter oben beschriebene »pop«-Kommando.

Tipp 12: In Farbe und bunt!

Ebenfalls von Bernhard Wiedemann stammt ein Tipp, der Farbe in Git bringt. Den folgenden, nicht wirklich hübschen Alias habe er nach eigener Aussage “irgendwo im Internet” gefunden:

lfi = log HEAD --graph --all --abbrev-commit --full-history --color --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s%Cgreen(%cr) %C(bold blue)<%an>%Creset' --date=relative

Er habe sich schnell an die Übersichtlichkeit einer farbigen Darstellung des Baumdiagramms in der History gewöhnt.

Schnelldurchlauf

Zum Abschuss folgen noch fünf wertvolle Tipps von einigen Experten im Schnelldurchlauf.

Webentwickler Thomas Hutterer benutzt mit »homegit« [17] einen Git-Alias zum Verwalten seiner Konfigurationsdateien (“Dotfiles”). Dieser kleine »GIT_WORK_TREE«-Kniff mache es ohne zusätzliche Software möglich, Dateien innerhalb des eigenen Homeverzeichnis zu verwalten und auf mehreren Rechnern zu benutzen. Thomas meint “damit fühlt man sich schnell überall wie zuhause”.

Von Martin Wilck stammen die Links für ein Rebase ohne den Verlust von Tags [18]. Zudem liefert der Kernelentwickler einen Link auf das Werkzeug Git-Related [19]. Mit dessen Hilfe spüren Git-Nutzer die Entwickler und Commits für ein Set von Änderungen auf. Das Tool durchläuft dabei die Git-Historie und führt für jede Änderung ein »git blame« aus.

Sergio Lindo schickte gleich eine ganze Liste Empfehlungen. Zu diesen gehört das Signieren von Commits (via »gpgSign = true« in der »[commit]«-Sektion der Datei ».gitconfig«). Das Alias »git lola« [20] erzeugt einen farbigen Graphen für alle Branches des Repositorys auf der Kommandozeile. »git rup« ist ein Alias für »git remote update –prune«. Es lädt die letzten Commits aller Branches aller Repository in den Remote-Ref-Branches herunter, pflegt sie aber nicht in den lokalen Branches ein. Das darf der Entwickler selbst tun, zum Beispiel mit »git-sync-fork.sh« [21]. »diff-highlight« [22] hebt hingegen Änderungen in Diffs farbig hervor.

Storage-Guru Lars Marowsky-Brée empfiehlt Vim-Fugitive [23]. Die Vim-Erweiterung macht typische Git-Kommandos wie »git status«, »git blame« und »git mv« für Vim-Anwender nutzbar.

Das letzte Wort gebührt aber Stephan “coolo” Kulow: Spaß muss es machen! Dafür empfiehlt er die Happy Git Commits [24]. (kki)

Infos

  1. Nützliche Git-Befehle: https://dzone.com/articles/useful-git-commands

  2. Git-Pro-Tipps der Fedora-Entwickler: http://www.linux.com/news/featured-blogs/200-libby-clark/825032-7-pro-tips-for-using-git-from-fedora-developers

  3. Cheat Sheets für Git: https://www.git-tower.com/blog/git-cheat-sheet/,https://services.github.com/on-demand/downloads/github-git-cheat-sheet.pdf

  4. Markus Feilner, “Verfassen in Massen”: Linux-Magazin 02/18: https://www.linux-magazin.de/ausgaben/2018/02/dokumentieren/

  5. »git-flow«: https://github.com/nvie/gitflow

  6. Dinge in Git zurücknehmen: http://www.git-scm.com/book/en/v2/Git-Basics-Undoing-Things

  7. Fehlerkorrektur in Git: http://blog.ctp.com/2013/11/21/git-recovering-from-mistakes/

  8. Interaktives Ergänzen in Git: http://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging,http://gitready.com/intermediate/2009/01/14/interactive-adding.html

  9. Ignorieren in Git: http://git-scm.com/docs/gitignore

  10. »git-check-ignore«: https://git-scm.com/docs/git-check-ignore

  11. Git-Historie umschreiben: https://www.atlassian.com/zh/git/tutorial/rewriting-git-history#!commit-amend

  12. Stashing in Git: http://git-scm.com/book/en/v1/Git-Tools-Stashing,http://git-scm.com/docs/git-stash

  13. Migration von Mercurial zu Git: https://www.openattic.org/posts/openattic-code-repository-migrated-to-git/

  14. »git-vimdiff«: https://github.com/frutiger/git-vimdiff

  15. Git-Deps: https://github.com/aspiers/git-deps

  16. Git-Fixup: https://github.com/aspiers/git-deps/blob/master/bin/git-fixup

  17. Homegit: https://github.com/thutterer/homegit

  18. Git-Rebase ohne die Tags zu verlieren: https://ownyourbits.com/2017/08/14/rebasing-in-git-without-losing-tags/

  19. »git-related«: https://github.com/felipec/git-related

  20. »git-lola«: http://blog.kfish.org/2010/04/git-lola.html

  21. »git-sync-fork.sh«: https://github.com/software-for-life/git-helper/blob/development/src/git-sync-fork.sh

  22. Diffs optimieren: https://github.com/git/git/tree/master/contrib/diff-highlight

  23. »vim-fugitive«: https://github.com/tpope/vim-fugitive

  24. Happy Git Commits: https://collectiveidea.com/blog/archives/2010/08/03/happy-git-commits

Der Autor

Markus Feilner arbeitet seit 1994 mit dem freien Betriebssystem als Autor, Trainer, Consultant und Journalist und leitet heute das Dokumentationsteam beim Linux-Distributor Suse in Nürnberg.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 5 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben