Git-Installation und -Konfiguration¶
Installation¶
Für ix-Distributionen sollte Git im Standard-Repository vorhanden sein.
Das Paket git-all stellt euch eine vollständige Umgebung für Git bereit. Dieses installiert ihr wie folgt:
$ sudo apt install git-all
Geht es ausschliesslich um Git, genügt das Paket namens git:
$ sudo apt install git
Mit der Bash-Autovervollständigung lässt sich Git auf der Kommandozeile einfacher bedienen. Das entsprechende Paket dazu heisst bash-completion und ihr installiert es wie folgt:
$ sudo apt install bash-completion
Es gibt verschiedene Möglichkeiten, Git auf einem Mac zu installieren. Am
einfachsten ist es vermutlich, die Xcode Command Line Tools zu installieren.
Hierfür müsst ihr nur git das erste Mal vom Terminal aufrufen:
$ git --version
git-completion könnt ihr mit Homebrew installieren:
Anschließend müsst ihr folgende Zeile in der Datei ~/.bash_profile hinzufügen:
[[ -r "$(brew --prefix)/etc/profile.d/bash_completion.sh" ]] && . "$(brew --prefix)/etc/profile.d/bash_completion.sh"
Ruft dazu https://git-scm.com/download/win auf und startet den passenden Download dazu.
Siehe auch
Konfiguration¶
Sichern der globalen Konfiguration in ~/.config/git/¶
Git nutzt verschiedene Ebenen von Konfigurationsdateien, die in der folgenden Reihenfolge ausgeführt werden:
systemgilt für alle User auf eurem Computer, aber es ist unwahrscheinlich, dass ihr dies jemals benutzen werdet.
globalgilt für alle Repositories eines einzelnen Users und wir werden uns das detaillierter anschauen.
localgilt für ein einzelnes Repository und ist nur für einige wenige Repository-spezifische Optionen.
Git such nach einer globalen Konfigurationsdatei an zwei verschiedenen Orten:
~/.config/git/config und ~/.gitconfig. Der erste Ort ist der
Standard für Konfigurationsdateien, der zweite ist der frühere Standard.
Bemerkung
Auf Linux-Maschinen kann ~/.config manchmal ein anderer Pfad sein,
abhängig von der Umgebungsvariable XDG_CONFIG_HOME. Dieses Verhalten ist
Teil der X Desktop Group (XDG) specification. Ihr
erhaltet den Pfad mit:
$ echo $XDG_CONFIG_HOME
Wenn dies nichts zurückgibt, wird Ihr System ~/.config verwenden,
andernfalls wird es den angezeigten Pfad verwenden. Der Einfachheit halber
werden wir uns von nun an nur noch auf ~/.config beziehen.
Siehe auch
Da ihr Optionen an mehreren Ebenen festlegen könnt, möchtet ihr vielleicht
nachvollziehen, woher Git einen bestimmten Wert liest. Mit git config --list
[1] könnt ihr alle überschriebenen Optionen und Werte auflisten. Dies könnt
ihr kombinieren mit --show-scope [2] um zu sehen, woher Git den Wert
bezieht:
$ git config --list --show-scope
system credential.helper=osxkeychain
global user.name=veit
global user.email=veit@cusy.io
…
Ihr könnt auch --show-origin [3] verwenden, um die Namen der
Konfigurationsdateien aufzulisten:
$ git config --list --show-origin
file:/opt/homebrew/etc/gitconfig credential.helper=osxkeychain
file:/Users/veit/.config/git/config user.name=veit
file:/Users/veit/.config/git/config user.email=veit@cusy.io
…
Bemerkung
Ein umfangreiches Beispiel einer Konfigurationsdatei findet ihr in meinem dotfiles-Repository: .gitconfig.
Migrieren von ~/.gitconfig zu ~/.config/git/config¶
Wenn ihr aktuell noch die alte Datei ~/.gitconfig verwendet, könnt ihr
die Datei mit wenigen Schritten in das ~/.config-Verzeichnis
verschieben:
Stellt sicher, dass das
~/.config-Verzeichnis existiert.Verschiebt eure bestehende Konfigurationsdate in dieses Verzeichnis:
$ mv ~/.gitconfig ~/.config/git/config
Überprüft, ob Git weiterhin eure Konfigurationsdatei liest, indem ihr
user.nameabfragt:$ git config --global user.name Veit Schiele
Möglicherweise solltet ihr auch noch andere Dateien verschieben, z.B.
~/.gitattributesund~/.gitignore. Ob diese Dateien vorhanden sind, könnt ihr überprüfen mit$ git config --global core.excludesFile ~/.gitignore $ git config --global core.attributesFile ~/.gitattributes
Dann müsst ihr die Dateien ebenfalls verschieben und die zugehörigen Konfigurationseinträge löschen:
$ mv ~/.gitignore_global ~/.config/git/ignore $ git config --global --unset core.excludesFile $ mv ~/.gitattributes ~/.config/git/attributes $ git config --global --unset core.attributesFile
Lesen und Schreiben der Konfigurationseinträge¶
Wie wir bereits oben gesehen haben, können Konfigurationseinträge gelesen werden mit git config, z.B.:
$ git config --global user.name
Veit Schiele
… und um den Eintrag zu ändern
$ git config --global user.name 'veit'
Ihr könnt die Konfigurationsdatei auch direkt ändern, indem ihr git config
zusammen mit der -e|--edit-Option aufruft:
$ git config --global -e
Dies öffnet die ~/.config/git/config-Datei in eurem Standardeditor.
Git speichert die Konfiguration in INI-Dateien.
Der Standardeditor für Git ist definiert in der GIT_EDITOR-Umgebungsvariable
oder in Git’s core.editor-Option oder in der VISUAL oder
EDITOR-Umgebungsvariable. Ihr könnt die Werte abfragen mit
$ echo $GIT_EDITOR
$ git config core.editor
$ echo $VISUAL
$ echo $EDITOR
Üblicherweise wollt ihr immer denselben Editor verwenden und daher sollte die
EDITOR-Umgebungsvariable gesetzt werden. Um dies zu tun, könnt ihr folgendes
in ~/.bash_profile oder ~/.zprofile eintragen:
export EDITOR='C:\Program Files (x86)\Microsoft VS Code\code.exe --wait'
Bemerkung
Auf macOS müsst ihr zunächst Visual Studio Code starten, dann die Befehlspalette mit ⌘+⇧-p öffnen und schließlich den Befehl Install ‚code‘ command in PATH ausführen.
oder
export EDITOR='vim'
Basiskonfiguration¶
Git Commits haben zwei Pflichtfelder, die sich auf die Person beziehen: den Namen der Person, die die Code-Änderungen vorgenommen hat und die Person, die den
Code ins Repository übertragen hat. In den meisten Workflows ist dies dieselbe
Person. Mit den Optionen user.name und user.email könnt ihr diese
Informationen für author und committer konfigurieren.
Tipp
Git-Hosts, wie GitHub oder GitLab, verknüpfen Commits mit eurem Profil über die E-Mail-Adresse. Wenn die konfigurierte E-Mail-Adresse nicht mit eurem Profil übereinstimmt, werden eure Commits nicht richtig zugewiesen. Dadurch können Teammitglieder schwerer bestimmen, dass der Commit von euch kommt. Daher solltet ihr den konfigurierten Namen und die E-Mail-Adresse stets überprüfen.
Alternative Konfigurationsdatei¶
Ihr könnt für bestimmte Arbeitsverzeichnisse andere Konfigurationsdateien verwenden, z.B. um zwischen privaten und beruflichen Projekten zu unterscheiden. Dazu könnt ihr eine lokale Konfiguration in eurem Repository verwenden oder aber Conditional Includes am Ende eurer globalen Konfiguration:
…
[includeIf "gitdir:~/private"]
path = ~/.config/git/config-private
Dieses Konstrukt sorgt dafür, dass Git zusätzliche Konfigurationen einbezieht
oder bestehende überschreibt, wenn ihr in ~/private arbeitet.
Erstellt dazu nun die Datei ~/.config/git/config-private und legt dort
eure alternative Konfiguration fest, z.B.:
[user]
email = kontakt@veit-schiele.de
[core]
sshCommand = ssh -i ~/.ssh/private_id_rsa
Siehe auch
Kolorieren¶
Standardmäßig nutzt Git die Fähigkeit eures Terminals, verschiedene Arten von
Text einzufärben und zu formatieren. Eine solche Kolorierung ermöglicht euch,
die Ausgabe schneller zu analysieren. Die Standardfarben sind jedoch suboptimal:
git status beispielsweise markiert geänderte Dateien in Rot, einer Farbe,
die im Allgemeinen mit Fehlern assoziiert wird; das Ändern von Dateien ist
jedoch kein Fehler, sondern völlig normal in jedem Git-Prozess. Ihr könnt die
Optionen color.* verwenden, um die Farben pro Befehl anzupassen. Ich
verwende die Farben des cheat sheet colours
schon seit langem:
[color "branch"]
current = yellow reverse
local = yellow
remote = green
[color "status"]
added = yellow
changed = green
untracked = cyan
Bemerkung
Später werden wir uns delta ansehen, ein Werkzeug zur besseren
Visualisierung von Unterschieden. Seine Kolorierung würde die Informationen
aus [colour "diff"] überschreiben, weshalb wir diesen Abschnitt nicht
hinzugefügt haben.
Befehle korrigieren¶
Wenn ihr bei der Eingabe eines Git-Befehls einen Fehler macht, werden standardmäßig ähnliche Befehle aufgelistet und das Programm beendet:
$ git comit -m ':wrench: Update git config'
git: 'comit' ist kein Git-Befehl. Siehe 'git --help'.
Der ähnlichste Befehl ist
commit
Ihr könnt Git aber auch mit git config --global help.autoCorrect immediate
[4] so konfigurieren, dass der erste Treffer automatisch ausgeführt wird:
$ git comit -m ':wrench: Update git config'
WARNUNG: Sie haben Git-Befehl 'comit' ausgeführt, welcher nicht existiert.
Setze fort unter der Annahme, dass Sie 'commit' meinten.
[main 48cafbf5f] :wrench: Update git config
Git korrigiert jedoch nur dann automatisch, wenn ein Befehl eine ausreichend große Übereinstimmung aufweist. Wenn es mehrere potenzielle Übereinstimmungen gibt, werden diese aufgelistet und die Korrektur wird abgebrochen:
$ git co -m ':wrench: Update git config'
git: 'co' is not a git command. See 'git --help'.
The most similar commands are
commit
clone
log
Wenn euch die automatische Korrektur eines Befehls zu viel ist, könnt ihr stattdessen den Prompt-Modus verwenden:
$ git config --global help.autoCorrect prompt
$ git comit -m ':wrench: Update git config'
WARNUNG: Sie haben Git-Befehl 'comit' ausgeführt, welcher nicht existiert.
Stattdessen 'commit' ausführen (y/N)? y
[main 48cafbf5f] :wrench: Update git config
Paginierung¶
Ihr könnt die Paginierung standardmäßig für einen Befehl aktivieren, indem ihr
die entsprechende Option setzt: pager.CMD = true, [5] zum Beispiel,
um den Git-Status auf Paginierung umzustellen:
$ git config --global pager.status true
Anmeldedaten verwalten¶
Seit der Git-Version 1.7.9 lassen sich die Zugangsdaten zu git-Repositories mit gitcredentials verwalten. Um diese zu nutzen, könnt ihr z.B. folgendes angeben:
$ git config --global credential.helper Cache
Hiermit wird euer Passwort für 15 Minuten im Cache-Speicher gehalten. Der Timeout kann ggf. erhöht werden, z.B. mit:
$ git config --global credential.helper 'cache --timeout=3600'
Unter Linux müsst ihr einen sog: Credential Store
auswählen. In den meisten Fällen werdet ihr euch für die Secret Service API
entscheiden, wie z.B. libsecret von Git, den ihr
auswählen könnt mit:
$ git config --global credential.credentialStore secretservice
Unter macOS lässt sich mit osxkeychain die Schlüsselbundverwaltung
(Keychain) nutzen um die Zugangsdaten zu speichern. osxkeychain setzt
Git in der Version 1.7.10 oder neuer voraus und kann im selben Verzeichnis
wie Git installiert werden mit:
$ git credential-osxkeychain
git: 'credential-osxkeychain' is not a git command. See 'git --help'.
$ curl -s -O http://github-media-downloads.s3.amazonaws.com/osx/git-credential-osxkeychain
$ chmod u+x git-credential-osxkeychain
$ sudo mv git-credential-osxkeychain /usr/bin/
Password:
git config --global credential.helper osxkeychain
Dies trägt folgendes in die ~/.gitconfig-Datei ein:
[credential]
helper = osxkeychain
Alternativ könnt ihr auch den Git Credential Manager installieren mit
brew install --cask git-credential-manager
Für Windows steht der Git Credential Manager (GCM) zur Verfügung. Er ist integriert in Git for Windows und wird standardmäßig mitinstalliert. Zusätzlich besteht jedoch auch ein eigenständiges Installationsprogramm in Releases.
GCM wird mit dem nachfolgenden Aufruf konfiguriert:
$ git credential-manager configure
Configuring component 'Git Credential Manager'...
Configuring component 'Azure Repos provider'...
Dies trägt den [credential]-Abschnitt in eure ~/.gitconfig-Datei
ein:
[credential]
helper =
helper = C:/Program\\ Files/Git/mingw64/bin/git-credential-manager.exe
Nun öffnet sich beim Clonen eines Repository ein Fenster des GCM und fordert euch zur Eingabe eurer Zugangsdaten auf.
Zudem wird die ~/.gitconfig-Datei ergänzt, z.B. um die folgenden beiden Zeilen:
[credential "https://ce.cusy.io"]
provider = generic
Die .gitignore-Datei¶
In der .gitignore-Datei eines Repository könnt ihr Dateien von der
Versionsverwaltung ausschließen. Eine typische .gitignore-Datei kann
z.B. so aussehen:
/logs/*
!logs/.gitkeep
/tmp
*.swp
Dabei verwendet Git Globbing-Muster, u.a.:
Muster |
Beispiel |
Erläuterung |
|---|---|---|
**/logs
|
|
Ihr könnt zwei Sternchen voranstellen um Verzeichnisse an einer beliebigen Stelle im Verzeichnisbaum zu finden. |
**/logs/instance.log
|
|
Ihr könnt zwei Sternchen voranstellen um Dateien anhand ihres Namens in einem übergeordneten Verzeichnis zu finden. |
*.log
|
|
Ein Sternchen ist ein Platzhalter für null oder mehr Zeichen. |
/logs
!/logs/.gitkeep
|
|
Ein vor ein Muster gestelltes Anführungszeichen ignoriert dieses. Wenn eine Datei mit einem Muster übereinstimmt, aber auch mit einem negierenden, das später definiert ist, wird sie nicht ignoriert. |
/instance.log
|
|
Mit dem vorangestellten Schrägstrich passt das Muster nur zu Dateien im Stammverzeichnis des Repository. |
instance.log
|
|
Üblicherweise passen die Muster zu Dateien in jedem Verzeichnis. |
instance?.log
|
|
Ein Fragezeichen passt genau zu einem Zeichen. |
instance[0-9].log
|
|
Eckige Klammern können verwendet werden um ein einzelnes Zeichen aus einem bestimmten Bereich zu finden. |
instance[01].log
|
|
Eckige Klammern passen auf ein einzelnes Zeichen aus einer bestimmten Menge. |
instance[!01].log
|
|
Ein Ausrufezeichen kann verwendet werden um ein beliebiges Zeichen aus einer angegebenen Menge zu finden. |
logs
|
|
Wenn kein Schrägstrich anhängt, passt das Muster sowohl auf Dateien als auch auf den Inhalt von Verzeichnissen mit diesem Namen. |
logs/
|
|
Das Anhängen eines Schrägstrichs zeigt an, dass das Muster ein Verzeichnis ist. Der gesamte Inhalt jedes Verzeichnisses im Repository, das diesem Namen entspricht – einschließlich all seiner Dateien und Unterverzeichnisse – wird ignoriert. |
var/**/instance.log
|
|
Zwei Sternchen passen zu null oder mehr Verzeichnissen. |
logs/instance*/error.log
|
|
Wildcards können auch in Verzeichnisnamen verwendet werden. |
logs/instance.log
|
|
Muster, die eine Datei in einem bestimmten Verzeichnis angeben, sind relativ zum Stammverzeichnis des Repository. |
Git-commit eines leeren Verzeichnisses¶
In obigem Beispiel seht ihr, dass mit /logs/* keine Inhalte des
logs-Verzeichnisses mit Git versioniert werden sollen, in der Folgezeile
jedoch eine Ausnahme definiert wird:
!logs/.gitkeep
Diese Angabe erlaubt, dass die Datei .gitkeep mit Git verwaltet werden
darf. Damit wird dann auch das logs-Verzeichnis in das Git-Repository
übernommen. Eine solche Hilfskonstruktion ist erforderlich, da leere
Verzeichnisse nicht mit Git verwaltet werden können.
Warnung
Diese Technik hat jedoch mehrere Nachteile:
Sowohl
.gitignorewie auchlog/.gitkeepmüssen bearbeitet werden.Beim Umbenennen des Verzeichnis kann leicht vergessen werden, auch die
.gitignore-Datei zu ändern..gitkeepist für Git eine ganz normale Datei; der Name legt jedoch nahe, dass die Datei von Git besonders behandelt würde.
Eine bessere Möglichkeit ist, in einem leeren Verzeichnis eine
.gitignore-Datei mit folgendem Inhalt zu erstellen:
# ignore everything except .gitignore
*
!.gitignore
Dies vermeidet die vorher genannten Probleme.
Dateien zentral mit excludesfile ausschließen¶
Ihr könnt jedoch auch zentral für alle Git-Repositories Dateien ausschließen.
Hierfür wird üblicherweise in der ~/.gitconfig-Datei folgendes
angegeben:
[core]
# Use custom `.gitignore`
excludesfile = ~/.gitignore
…
Bemerkung
Hilfreiche Vorlagen findet ihr in meinem dotfiles-Repository oder auf der Website gitignore.io.
Ignorieren einer Datei aus dem Repository¶
Wenn ihr eine Datei ignorieren wollt, die in der Vergangenheit bereits dem Repository hinzugefügt
wurde, müsst ihr die Datei aus eurem Repository löschen und dann eine
.gitignore-Regel für sie hinzufügen. Die Verwendung der Option --cached
bei git rm bedeutet, dass die Datei aus dem Repository gelöscht wird, aber
als ignorierte Datei in eurem Arbeitsverzeichnis verbleibt.
$ echo *.log >> .gitignore
$ git rm --cached *.log
rm 'instance.log'
$ git commit -m "Remove log files"
Bemerkung
Ihr könnt die Option --cached weglassen, wenn ihr die Datei sowohl aus
dem Repository als auch aus eurem lokalen Dateisystem löschen wollt.
Commit einer ignorierten Datei¶
Es ist möglich, den Commit einer ignorierten Datei an das Repository mit der
Option -f (oder --force) bei git add zu erzwingen:
$ cat data/.gitignore
*
$ git add -f data/iris.csv
$ git commit -m "Force add iris.csv"
Ihr könnt dies in Erwägung ziehen, wenn ihr ein allgemeines Muster (wie *)
definiert habt, aber eine bestimmte Datei übertragen wollt. Eine bessere Lösung
ist meist jedoch, eine Ausnahme von der allgemeinen Regel zu definieren:
$ echo '!iris.csv' >> data/.gitignore
$ cat data/.gitignore
*
!iris.csv
$ git add data/iris.csv
$ git commit -m "Add iris.csv"
Dieser Ansatz dürfte für euer Team offensichtlicher und weniger verwirrend sein.
Fehlersuche in .gitignore-Dateien¶
Bei komplizierten .gitignore-Mustern oder bei Mustern, die über mehrere
.gitignore-Dateien verteilt sind, kann es schwierig sein,
herauszufinden, ob oder warum eine bestimmte Datei ignoriert wird.
Mit dem Aufruf git status --ignored=matching [6] wird der Ausgabe ein
Abschnitt Ignorierte Dateien hinzugefügt, der zusätzlich alle von Git
ignorierten Dateien und Verzeichnisse beinhaltet:
$ git status --ignored=matching
Auf Branch main
Ignorierte Dateien:
(benutzen Sie "git add -f <Datei>...", um die Änderungen zum Commit vorzumerken)
.DS_Store
docs/.DS_Store
docs/_build/doctrees/
docs/_build/html/
docs/clean-prep/.ipynb_checkpoints/
…
nichts zu committen, Arbeitsverzeichnis unverändert
Ihr könnt den Befehl git check-ignore [7] mit der Option -v (Langform:
--verbose) verwenden, um festzustellen, welches Muster die Ursache für das
Ignorieren einer bestimmten Datei ist:
$ git check-ignore -v data/iris.csv
data/.gitignore:2:!iris.csv data/iris.csv
Obige Ausgabe besteht aus vier Feldern (Trennzeichen sind drei Doppelpunkte und ein Leerzeichen) und beinhaltet:
FILE_CONTAINING_THE_PATTERNden Namen der Datei, die das Muster enthält.
LINE_NUMBER_OF_THE_PATTERNdie Zeilennummer, in der in der Datei
FILE_CONTAINING_THE_PATTERNdas Muster gefunden wurde.PATTERNdas gefundene Muster.
FILE_NAMEden Namen der Datei inklusive Pfad, die Git ignoriert.
Ihr könnt mehrere Dateinamen an git check-ignore übergeben, wenn ihr
möchtet, und die Namen selbst müssen nicht einmal den Dateien entsprechen, die
in eurem Repository existieren.
Eine vollständige Liste aller ignorierten Dateien erhaltet ihr mit git
ls-files --ignored --exclude-standard --others [8]. Mit
--exclude-standard werden die Standard-ignore-Dateien gelesen und
mit --others werden die nicht-versionierten Dateien statt der versionierten
angezeigt:
$ git ls-files --ignored --exclude-standard --others
.DS_Store
_build/doctrees/clean-prep/bulwark.doctree
_build/doctrees/clean-prep/dask-pipeline.doctree
_build/doctrees/clean-prep/deduplicate.doctree
…
Gelegentlich möchtet ihr vielleicht die globale ~/.gitignore-Datei
umgehen um zu sehen, welche Dateien Git unabhängig von eurer Konfiguration immer
ignoriert. Ihr könnt dies tun, indem ihr zu einer anderen exclude-Option
wechselt, --exclude-per-directory, die nur die .gitignore-Dateien
des Repositorys verwendet:
$ git ls-files --ignored --exclude-per-directory=.gitignore --others
docs/_build/doctrees/clean-prep/bulwark.doctree
docs/_build/doctrees/clean-prep/dask-pipeline.doctree
docs/_build/doctrees/clean-prep/deduplicate.doctree
…
Beachtet, dass die Datei .DS_Store nicht mehr als ignoriert aufgeführt
wird.
Wenn ihr --others durch --cached ersetzt, listet git ls-files
Dateien auf, die ignoriert werden würden, es sei denn, sie wurden bereits
übertragen:
$ git ls-files --ignored --exclude-per-directory=.gitignore --cached
data/iris.csv
Möglicherweise habt ihr solche Dateien, weil jemand sie vor den relevanten
Mustern in einer .gitignore-Datei hinzugefügt hat, oder weil jemand sie
mit git add --force hinzugefügt hat. So oder so, wenn ihr die Datei nicht
mehr mit Git verwalten wollt, könnt ihr sie mit dem folgenden Einzeiler aus der
Git-Verwaltung nehmen, sie aber nicht löschen:
$ git ls-files --ignored --exclude-per-directory=.gitignore --cached | xargs -r git rm --cached
rm 'data/iris.csv'