Weiterführende Themen

Git kann noch wesentlich mehr, was aber den Rahmen dieser Schulung sprengen würde. Viele Probleme oder Wünsche lassen sich aufgrund der weiten Verbreitung der Software gut googlen (am besten auf englisch).

Ein paar Stichpunkte, die noch erwähnenswert sind:

Dateien zurücksetzen

git checkout -- <datei> kann verwendet werden, um Dateien auf ihren Commit-Zustand zurückzusetzen. Alle anderen Änderungen gehen dabei verloren.

Commits entfernen

git reset kann verwendet werden, um Commits rückgängig zu machen. Z. B. würde git reset HEAD~1 das Repository auf den Stand des vorletzen Commits zurücksetzen (HEAD ist der aktuelle, also letzte Commit, HEAD~1 der davor, HEAD~2 der davor, usw. Natürlich könnte stattdessen auch der Commit-Hash verwendet werden). Die so nicht mehr committeten Dateien und Änderungen sind danach wieder unstaged.

Feature-Branches pushen

Im Fall einer Übergabe einer Entwicklungsbranch an einen Kollegen kann diese auch auf den Server gepusht werden. Dafür muss nur ein Remote gesetzt werden, der Remote-Branch-Name sollte sprechend sein. Remote-Branches können nach Abarbeitung gelöscht werden: git push --delete <remote> <branch>.

Commits "squashen"

Mittels git rebase -i <commit> (--interactive) kann die Historie nachträglich geändert werden. Das geht natürlich nur konfliktfrei, wenn die Commits noch lokal (noch nie gepusht) sind, da sonst unsere Commit-Änderungen Auswirkungen auf die Repositories anderer Entwickler haben könnten. Unser Git-Server verbietet standardmäßig solche pushes.

Der interaktive Rebase erwartet einen Basis-Commit, alle Commits seit diesem können dann verändert werden. Dies geschieht in einer Textdatei, deren Format in Kommentaren in der Datei selbst erläutert wird. So lässt sich die Lesbarkeit der Historie weiter verbessern.

pick 1e6433e Change "Hello" to "Greetings"
pick a7d1320 Add first part of a feature
squash 688c44d Add test for first part of a feature
squash 95be132 Complete feature
# Rebase 68ed1a0..95be132 onto 95be132 (4 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

Git kennt keine Verzeichnisse

Git kümmert sich nur um die Verwaltung von Dateien, leere Verzeichnisse werden ignoriert. Wenn das Verzeichnis dennoch bei anderen Entwicklern automagisch vorhanden sein soll, ist der idiomatische Weg, dort eine leere Datei .keep zu committen:

$ touch foo/bar/.keep
$ git add foo/bar/.keep
$ git commit

Diffs können noch nützlicher werden

Z. B. mit dem Skript diff-so-fancy können Diffs noch lesbarer werden, in dem die einzelnen geänderten Zeichen einer Zeile marktiert werden.

Standard-Diff links, Diff-So-Fancy rechts