Kapitel 1. Einführung in Git

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

Einfach ausgedrückt, ist Git ein Content Tracker. Damit hat Git die gleichen Prinzipien wie die meisten Systeme zur Versionskontrolle. Das Besondere an Git ist jedoch, dass es ein verteiltes Versionskontrollsystem ist, das sich von der Vielzahl der heute verfügbaren Tools abhebt. Das bedeutet, dass Git schnell und skalierbar ist, über eine umfangreiche Sammlung von Befehlen verfügt, die sowohl High-Level- als auch Low-Level-Operationen ermöglichen, und für lokale Operationen optimiert ist.

In diesem Kapitel lernst du die Grundprinzipien von Git, seine Eigenschaften und die grundlegenden git Befehle kennen und erhältst eine kurze Anleitung zum Erstellen und Hinzufügen von Änderungen zu einem Repository.

Wir empfehlen dir dringend, dir Zeit zu nehmen, um die wichtigen Konzepte zu verstehen, die hier erklärt werden. Diese Themen sind die Bausteine von Git und helfen dir, die mittleren und fortgeschrittenen Techniken für die Verwaltung eines Git-Repositorys im Rahmen deiner täglichen Arbeit zu verstehen. Diese grundlegenden Konzepte werden dir auch dabei helfen, dein Wissen zu erweitern, wenn wir das Innenleben von Git in den Kapiteln von Teil II, "Grundlagen von Git", Teil III, "Mittlere Fertigkeiten", und Teil IV, "Fortgeschrittene Fertigkeiten", aufschlüsseln.

Git Komponenten

Bevor wir in die Welt der git Befehle eintauchen, wollen wir einen Schritt zurücktreten und uns einen Überblick über die Komponenten verschaffen, aus denen das Git-Ökosystem besteht. Abbildung 1-1 zeigt, wie die Komponenten zusammenarbeiten.

Git-GUI-Tools dienen als Frontend für die Git-Befehlszeile, und einige Tools haben Erweiterungen, die sich in gängige Git-Hosting-Plattformen integrieren lassen. Die Git-Client-Tools arbeiten meist mit der lokalen Kopie deines Repositorys.

vcg3 0101
Abbildung 1-1. Überblick über die Git-Komponenten

Wenn du mit Git arbeitest, gehören zu einer typischen Einrichtung ein Git-Server und Git-Clients. Du kannst auch auf einen Server verzichten, aber das würde die Pflege und Verwaltung von Repositories beim Austausch von Revisionsänderungen in einer kollaborativen Umgebung komplizierter machen und die Konsistenz erschweren (wir werden in Kapitel 11 darauf zurückkommen). Der Git-Server und die Clients funktionieren wie folgt:

Git-Server

Ein Git-Server ermöglicht dir eine einfachere Zusammenarbeit weil er die Verfügbarkeit einer zentralen und zuverlässigen Quelle der Wahrheit für die Repositories, an denen du arbeitest, gewährleistet. Ein Git-Server ist auch der Ort, an dem deine entfernten Git-Repositories gespeichert werden; wie es üblich ist, verfügt das Repository über die aktuellste und stabilste Quelle deiner Projekte. Du hast die Möglichkeit, einen eigenen Git-Server zu installieren und zu konfigurieren, oder du kannst auf den Aufwand verzichten und deine Git-Repositorys auf zuverlässigen Hosting-Seiten von Drittanbietern wie GitHub, GitLab und Bitbucket hosten lassen.

Git Clients

Git-Clients interagieren mit deinen lokalen Repositories, . Du kannst mit Git-Clients über die Git-Befehlszeile oder die Git-GUI-Tools interagieren. Wenn du einen Git-Client installierst und konfigurierst, kannst du auf die entfernten Repositories zugreifen, an einer lokalen Kopie des Repositories arbeiten und Änderungen an den Git-Server übertragen. Wenn du Git noch nicht kennst, empfehlen wir dir, mit der Git-Befehlszeile zu beginnen. Mach dich mit den gängigen git Befehlen vertraut, die du für deine tägliche Arbeit benötigst, und gehe dann zu einem Git-GUI-Tool deiner Wahl über.

Der Grund für diesen Ansatz ist, dass Git GUI-Tools bis zu einem gewissen Grad dazu neigen, Terminologien bereitzustellen, die ein gewünschtes Ergebnis darstellen, das möglicherweise nicht Teil der Standardbefehle von Git ist. Ein Beispiel wäre ein Werkzeug mit einer Option namens sync, hinter der sich die Verkettung von zwei oder mehr git Befehlen verbirgt, um ein gewünschtes Ergebnis zu erzielen. Wenn du aus irgendeinem Grund den Unterbefehl sync in die Befehlszeile eingibst, könntest du diese verwirrende Ausgabe erhalten:

$ git sync

git: 'sync' is not a git command. See 'git --help'.

The most similar command is
       svn
Hinweis

git sync ist kein gültiger git Unterbefehl. Um sicherzustellen, dass deine lokale Arbeitskopie des Repositorys mit den Änderungen des entfernten Git-Repositorys synchronisiert ist, musst du eine Kombination dieser Befehle ausführen: git fetch, git merge, git pull, oder git push.

Es gibt eine Fülle von Tools, die dir zur Verfügung stehen. Einige Git-GUI-Tools sind ausgefallen und über ein Plug-in-Modell erweiterbar, das dir die Möglichkeit bietet, Funktionen von beliebten Git-Hosting-Sites von Drittanbietern einzubinden und zu nutzen. So bequem es auch sein mag, Git über ein GUI-Tool zu erlernen, werden wir uns bei den Beispielen und Code-Diskussionen auf das Git-Befehlszeilen-Tool konzentrieren, da dies ein gutes Grundwissen schafft, das zu Git-Geschicklichkeit führt.

Git Merkmale

Nachdem wir nun einen Überblick über die Git-Komponenten gegeben haben,, wollen wir uns nun mit den Eigenschaften von Git beschäftigen. Wenn du diese besonderen Eigenschaften von Git verstehst, kannst du mühelos von einer zentralen Versionskontrolle zu einer verteilten Versionskontrolle wechseln. Wir bezeichnen dies als "Denken in Git":

Git speichert Revisionsänderungen als Snapshots

Das erste Konzept, das du verlernen musst, ist die Art und Weise, wie Git mehrere Revisionen einer Datei speichert, an der du gerade arbeitest. Im Gegensatz zu anderen Versionskontrollsystemen zeichnet Git Änderungen nicht als eine Reihe von Änderungen auf, die auch als Deltas bezeichnet werden, sondern erstellt einen Schnappschuss der Änderungen, die zu einem bestimmten Zeitpunkt am Zustand deines Projektarchivs vorgenommen wurden. In der Git-Terminologie wird dies als Commit bezeichnet. Stell dir vor, du hältst einen Moment in der Zeit fest, wie bei einem Foto.

Git wird für die lokale Entwicklung verbessert

In Git arbeitest du an einer Kopie des Repositorys auf deinem lokalen Entwicklungsrechner. Dies wird als lokales Repository oder als Klon des entfernten Repositorys auf einem Git-Server bezeichnet. Dein lokales Repository enthält die Ressourcen und die Snapshots der Revisionsänderungen, die an diesen Ressourcen vorgenommen wurden, an einem Ort. Git nennt diese Sammlungen von verknüpften Snapshots Repository Commit History oder kurz Repo History. So kannst du auch in einer unverbundenen Umgebung arbeiten, da Git keine ständige Verbindung zum Git-Server benötigt, um deine Änderungen zu kontrollieren. So kannst du auch in verteilten Teams an großen, komplexen Projekten arbeiten, ohne dass die Effizienz und Leistung der Versionskontrolle darunter leidet.

Git ist endgültig

Definitiv bedeutet, dass die git Befehle explizit sind. Git wartet darauf, dass du Anweisungen gibst, was zu tun ist und wann es zu tun ist. Git synchronisiert zum Beispiel nicht automatisch Änderungen aus deinem lokalen Projektarchiv mit dem entfernten Projektarchiv und speichert auch nicht automatisch einen Schnappschuss einer Revision in deiner lokalen Projektarchiv-Historie. Jede Aktion erfordert einen expliziten Befehl oder eine Anweisung von dir, um Git mitzuteilen, was erforderlich ist, z. B. das Hinzufügen neuer Commits, das Korrigieren bestehender Commits, das Verschieben von Änderungen aus deinem lokalen Projektarchiv in das Remote-Repository und sogar das Abrufen neuer Änderungen aus dem Remote-Repository. Kurz gesagt, du musst deine Handlungen mit Bedacht ausführen. Dazu gehört auch, dass du Git mitteilst, welche Dateien du verfolgen willst, denn Git fügt nicht automatisch neue Dateien zur Versionskontrolle hinzu.

Git soll die nichtlineare Entwicklung unterstützen

Mit Git kannst du Ideen entwickeln und mit verschiedenen Implementierungen von Funktionen experimentieren, um praktikable Lösungen für dein Projekt zu finden, indem du parallel an der stabilen Hauptcodebasis deines Projekts arbeitest und dich verzweigst. Diese Methode, die als Verzweigung bezeichnet wird, ist eine weit verbreitete Praxis, die die Integrität der Hauptentwicklungslinie sicherstellt und versehentliche Änderungen verhindert, die sie zerstören könnten.

In Git gilt das Konzept der Verzweigung als leichtgewichtig und kostengünstig, weil ein Branch in Git nur ein Verweis auf den letzten Commit in einer Reihe von verknüpften Commits ist. Für jeden Zweig, den du erstellst, merkt sich Git die Reihe der Commits für diesen Zweig. Du kannst lokal zwischen den Zweigen wechseln. Git stellt dann den Zustand des Projekts auf den letzten Zeitpunkt zurück, als der Snapshot des angegebenen Zweigs erstellt wurde. Wenn du dich entscheidest, die Änderungen aus einem beliebigen Zweig in die Hauptentwicklungslinie einzubringen, kann Git diese Reihen von Commits mithilfe von Techniken zusammenführen, die wir in Kapitel 6 besprechen werden.

Tipp

Da Git viele Neuerungen bietet, solltest du bedenken, dass die Konzepte und Praktiken anderer Versionskontrollsysteme möglicherweise anders funktionieren oder in Git gar nicht anwendbar sind.

Die Git-Befehlszeile

Die Kommandozeilenschnittstelle von Git ist einfach zu bedienen. Sie ist so konzipiert, dass du die volle Kontrolle über dein Repository hast. Daher gibt es viele Möglichkeiten, das Gleiche zu tun. Indem wir uns auf die Befehle konzentrieren, die für deine tägliche Arbeit wichtig sind, können wir sie vereinfachen und tiefergehend lernen.

Für den Anfang tippen Sie einfach git version oder git --version auf ein, um festzustellen, ob dein Rechner bereits mit Git vorgeladen ist. Du solltest eine ähnliche Ausgabe wie die folgende sehen:

$ git --version
git version 2.37.0

Wenn du Git noch nicht auf deinem Rechner installiert hast, lies bitte in Anhang B nach, wie du Git entsprechend deiner Betriebssystemplattform installieren kannst, bevor du mit dem nächsten Abschnitt fortfährst.

Nach der Installation gibst du git ohne Argumente ein. Git listet dann seine Optionen und die gängigsten Unterbefehle auf:

   $ git

   usage: git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]
              [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
              [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]
              [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
              [--super-prefix=<path>] [--config-env=<name>=<envvar>]
              <command> [<args>]

   These are common Git commands used in various situations:

   start a working area (see also: git help tutorial)
      clone     Clone a repository into a new directory
      init      Create an empty Git repository or reinitialize an existing one

   work on the current change (see also: git help everyday)
      add       Add file contents to the index
      mv        Move or rename a file, a directory, or a symlink
      restore   Restore working tree files
      rm        Remove files from the working tree and from the index

   examine the history and state (see also: git help revisions)
      bisect    Use binary search to find the commit that introduced a bug
      diff      Show changes between commits, commit and working tree, etc
      grep      Print lines matching a pattern
      log       Show commit logs
      show      Show various types of objects
      status    Show the working tree status

   grow, mark and tweak your common history
      branch    List, create, or delete branches
      commit    Record changes to the repository
      merge     Join two or more development histories together
      rebase    Reapply commits on top of another base tip
      reset     Reset current HEAD to the specified state
      switch    Switch branches
      tag       Create, list, delete or verify a tag object signed with GPG

   collaborate (see also: git help workflows)
      fetch     Download objects and refs from another repository
      pull      Fetch from and integrate with another repository or a local branch
      push      Update remote refs along with associated objects

   'git help -a' and 'git help -g' list available subcommands and some((("git help command")))
   concept guides. See 'git help <command>' or 'git help <concept>'
   to read about a specific subcommand or concept.
   See 'git help git' for an overview of the system.
Tipp

Eine vollständige Liste der git Unterbefehle findest du, indem du git help --all.

Wie du aus dem Verwendungshinweis ersehen kannst, gilt eine kleine Handvoll von Optionen für git. Die meisten Optionen, die im Hinweis als [ARGS] angezeigt werden, gelten für bestimmte Unterbefehle.

Die Option --version wirkt sich zum Beispiel auf den Befehl git aus und erzeugt eine Versionsnummer:

   $ git --version
   git version 2.37.0

Im Gegensatz dazu ist --amend ein Beispiel für eine Option, die spezifisch für den git Unterbefehl commit ist:

   $ git commit --amend

Manche Aufrufe erfordern beide Formen von Optionen (hier dienen die zusätzlichen Leerzeichen in der Befehlszeile nur dazu, den Unterbefehl optisch vom Basisbefehl zu trennen und sind nicht erforderlich):

   $ git --git-dir=project.git    repack -d

Der Einfachheit halber ist die Dokumentation für jeden git Unterbefehl unter git help subcommand, git --help subcommand, git subcommand --help, oder verfügbar. man git-subcommand.

Hinweis

Die vollständige Git-Dokumentation ist online.

In der Vergangenheit wurde Git als eine Suite von vielen einfachen, eigenständigen Befehlen bereitgestellt, die nach der Unix-Philosophie entwickelt wurden: kleine, interoperable Tools zu bauen. Jeder Befehl trug einen Namen mit Bindestrich, z. B. git-commit und git-log. Moderne Git-Installationen unterstützenjedoch nicht mehr die Befehlsformen mit Bindestrich und verwenden stattdessen eine einzelne git ausführbare Datei mit einem Unterbefehl.

Die Befehle git verstehen sowohl "kurze" als auch "lange" Optionen. Der Befehl behandelt zum Beispiel die folgenden Beispiele gleichwertig: git commit

   $ git commit -m "Fix a typo."
   $ git commit --message="Fix a typo."

Die Kurzform, -m, verwendet einen Bindestrich, die Langform, --message, zwei. (Dies entspricht der GNU-Erweiterung für lange Optionen.) Einige Optionen gibt es nur in einer Form.

Tipp

Du kannst eine Commit-Zusammenfassung und eine detaillierte Nachricht für die Zusammenfassung erstellen, indem du die Option -m mehrfach verwendest:

   $ git commit -m "Summary" -m "Detail of Summary"

Schließlich kannst du Optionen von einer Liste von Argumenten durch einen einfachen Doppelstrich trennen. Verwende den Doppelstrich zum Beispiel, um den Steuerteil der Befehlszeile von einer Liste von Operanden, wie Dateinamen, zu unterscheiden:

   $ git diff -w main origin -- tools/Makefile

Möglicherweise musst du den doppelten Bindestrich verwenden, um Dateinamen zu trennen und explizit zu kennzeichnen, damit sie nicht mit einem anderen Teil des Befehls verwechselt werden. Wenn du zum Beispiel zufällig sowohl eine Datei als auch einen Tag mit dem Namen main.c hast, musst du bei deinen Operationen absichtlich vorgehen:

   # Checkout the tag named "main.c"
   $ git checkout main.c

   # Checkout the file named "main.c"
   $ git checkout -- main.c

Schnelle Einführung in die Verwendung von Git

Um Git in Aktion zu sehen, kannst du ein neues Repository erstellen, einige Inhalte hinzufügen und ein paar Revisionen verfolgen. Du kannst ein Repository auf zwei Arten erstellen: Entweder du erstellst ein Repository von Grund auf neu und füllst es mit Inhalten, oder du arbeitest mit einem bestehenden Repository, indem du es von einem entfernten Git-Server klonst.

Vorbereitungen für die Arbeit mit Git

Egal, ob du ein neues Repository erstellst oder mit einem bestehenden Repository arbeitest, es gibt einige grundlegende Konfigurationen, die du nach der Installation von Git auf deinem lokalen Entwicklungsrechner vornehmen musst. Das ist so, als würdest du bei einer neuen Kamera das richtige Datum, die richtige Zeitzone und die richtige Sprache einstellen, bevor du deinen ersten Schnappschuss machst.

Git verlangt mindestens deinen Namen und deine E-Mail-Adresse, bevor du deinen ersten Commit in deinem Repository machst. Die Identität, die du angibst, wird dann zusammen mit anderen Metadaten des Snapshots als Autor der Übertragung angezeigt. Du kannst deine Identität in einer Konfigurationsdatei speichern, indem du den Befehl git config verwendest:

   $ git config user.name "Jon Loeliger"
   $ git config user.email "jdl@example.com"

Wenn du dich entscheidest, deine Identität nicht in eine Konfigurationsdatei aufzunehmen, musst du deine Identität für jeden git commit Unterbefehl angeben, indem du das Argument --author am Ende des Befehls anhängst:

   $ git commit -m "log message" --author="Jon Loeliger <jdl@example.com>"

Denke daran, dass dies der harte Weg ist, der schnell mühsam werden kann.

Du kannst auch deine Identität angeben, indem du deinen Namen und deine E-Mail-Adresse in den Umgebungsvariablen GIT_AUTHOR_NAME und GIT_AUTHOR_EMAIL angibst. Wenn diese Variablen gesetzt sind, setzen sie alle Konfigurationseinstellungen außer Kraft. Bei Angaben, die in der Befehlszeile gemacht werden, setzt Git jedoch die in der Konfigurationsdatei und der Umgebungsvariablen angegebenen Werte außer Kraft.

Arbeiten mit einem lokalen Repository

Nachdem du deine Identität konfiguriert hast, bist du bereit, mit einem Repository zu arbeiten. Beginne damit, ein neues leeres Repository auf deinem lokalen Entwicklungsrechner anzulegen. Wir fangen ganz einfach an und arbeiten uns dann zu den Techniken für die Arbeit mit einem gemeinsamen Repository auf einem Git-Server vor.

Erstellen eines ersten Repositorys

Wir werden eine typische Situation nachstellen, indem wir ein Repository für deine persönliche Website erstellen. Nehmen wir an, du fängst bei Null an und fügst Inhalte für dein Projekt in das lokale Verzeichnis ~/my_website ein, das du in ein Git-Repository stellst.

Gib die folgenden Befehle ein, um das Verzeichnis zu erstellen und einige grundlegende Inhalte in einer Datei namens index.html abzulegen:

   $ mkdir ~/my_website
   $ cd ~/my_website
   $ echo 'My awesome website!' > index.html

Um ~/my_website in ein Git-Repository zu verwandeln, führe git init aus. Hier geben wir die Option -b gefolgt von einem Standardzweig namens main an:

   $ git init -b main

   Initialized empty Git repository in ../my_website/.git/

Wenn du es vorziehst, zuerst ein leeres Git-Repository zu initialisieren und ihm dann Dateien hinzuzufügen, kannst du dies mit den folgenden Befehlen tun:

   $ git init -b main ~/my_website

   Initialized empty Git repository in ../my_website/.git/

   $ cd ~/my_website
   $ echo 'My awesome website!' > index.html
Tipp

Du kannst ein komplett leeres Verzeichnis oder ein bestehendes Verzeichnis voller Dateien initialisieren. In beiden Fällen ist der Prozess der Umwandlung des Verzeichnisses in ein Git-Repository derselbe.

Der Befehl git init erstellt ein verstecktes Verzeichnis namens .git auf der Stammebene deines Projekts. Alle Revisionsinformationen sowie unterstützende Metadaten und Git-Erweiterungen werden in diesem versteckten .git-Ordner auf oberster Ebene gespeichert.

Git betrachtet ~/my_website als das Arbeitsverzeichnis. Dieses Verzeichnis enthält die aktuelle Version der Dateien für deine Website. Wenn du Änderungen an bestehenden Dateien vornimmst oder neue Dateien zu deinem Projekt hinzufügst, speichert Git diese Änderungen im versteckten Ordner .git.

Zu Lernzwecken verweisen wir auf zwei virtuelle Verzeichnisse , die wir Local History und Index nennen, um das Konzept der Initialisierung eines neuen Git-Repositorys zu veranschaulichen. Wir werden die Local History und den Index in den Kapiteln 4 bzw. 5 besprechen.

Abbildung 1-2 veranschaulicht, was wir gerade erklärt haben:

.
└── my_website
   ├── .git/
   │   └── Hidden git objects
   └── index.html
vcg3 0102
Abbildung 1-2. Ursprüngliches Repository

Die gestrichelten Linien, die den lokalen Verlauf und den Index umgeben, stellen die versteckten Verzeichnisse innerhalb des .git-Ordners dar.

Hinzufügen einer Datei zu deinem Repository

Bis zu diesem Punkt hast du nur ein neues Git-Repository erstellt. Mit anderen Worten: Dieses Git-Repository ist leer. Obwohl die Datei index.html im Verzeichnis ~/my_website existiert, ist dies für Git das Arbeitsverzeichnis, eine Art Notizblock oder Verzeichnis, in dem du häufig deine Dateien änderst.

Wenn du die Änderungen an den Dateien abgeschlossen hast und diese Änderungen im Git-Repository ablegen möchtest, musst du dies explizit mit dem git add file Befehl:

   $ git add index.html
Warnung

Obwohl du Git mit dem Befehl git add . alle Dateien im Verzeichnis und allen Unterverzeichnissen hinzufügen lassen kannst, wird dadurch alles in das Verzeichnis eingefügt, und wir raten dir, genau zu überlegen, was du in das Verzeichnis einfügen willst. Um solche Informationen zu vermeiden, kannst du die Datei .gitignore verwenden, die in Kapitel 5 behandelt wird.

Das Argument ., der einzelne Punkt oder Punkt in der Unix-Sprache, ist eine Kurzform für das aktuelle Verzeichnis.

Mit dem Befehl git add versteht Git, dass du beabsichtigst, die letzte Iteration der Änderung an index.html als Revision in das Repository aufzunehmen. Bislang hat Git die Datei jedoch nur bereitgestellt, ein Zwischenschritt, bevor ein Snapshot per Commit erstellt wird.

Git trennt die Schritte add und commit, um Unbeständigkeit zu vermeiden und gleichzeitig Flexibilität und Granularität bei der Erfassung von Änderungen zu bieten. Stell dir vor, wie störend, verwirrend und zeitaufwändig es wäre, das Repository jedes Mal zu aktualisieren, wenn du eine Datei hinzufügst, entfernst oder änderst. Stattdessen können mehrere provisorische und zusammenhängende Schritte, wie z. B. das Hinzufügen einer Datei, zusammengefasst werden, wodurch das Projektarchiv in einem stabilen, konsistenten Zustand bleibt. Diese Methode ermöglicht es uns auch, eine Erklärung dafür zu finden, warum wir den Code ändern. In Kapitel 4 werden wir uns mit diesem Konzept näher befassen.

Wir empfehlen dir, logische Änderungsstapel zu gruppieren, bevor du eine Übergabe machst. Dies wird als atomare Übergabe bezeichnet und hilft dir in Situationen, in denen du in späteren Kapiteln einige fortgeschrittene Git-Operationen durchführen musst.

Wenn du den Befehl git status ausführst, siehst du diesen Zwischenzustand von index.html:

   $ git status

   On branch main

   No commits yet

   Changes to be committed:
     (use "git rm --cached <file>..." to unstage)
	    new file:   index.html

Der Befehl meldet, dass die neue Datei index.html bei der nächsten Übertragung zum Repository hinzugefügt wird.

Nachdem du die Datei bereitgestellt hast, ist der nächste logische Schritt, die Datei an das Projektarchiv zu übergeben. Sobald du die Datei festschreibst, wird sie Teil des Repository-Commit-Verlaufs, den wir der Einfachheit halber als Repo-Verlauf bezeichnen. Jedes Mal, wenn du einen Commit durchführst, speichert Git verschiedene andere Metadaten mit, vor allem die Commit-Logmeldung und den Autor der Änderung.

Ein vollständig qualifizierter git commit Befehl sollte eine knappe und aussagekräftige Logmeldung in aktiver Sprache liefern, um die Änderung zu bezeichnen, die durch den Commit eingeführt wird. Das ist sehr hilfreich, wenn du die Repo-Historie durchforsten musst, um eine bestimmte Änderung aufzuspüren, oder wenn du die Änderungen eines Commits schnell identifizieren willst, ohne dich in die Details der Änderung vertiefen zu müssen. Dieses Thema wird in den Kapiteln 4 und 8 genauer behandelt.

Übertragen wir die index.html-Datei für deine Website:

   $ git commit -m "Initial contents of my_website"

   [main (root-commit) c149e12] initial contents of my_website
    1 file changed, 1 insertion(+)
    create mode 100644 index.html
Hinweis

Die Daten des Autors, der die Übertragung vornimmt, werden aus der Git-Konfiguration abgerufen, die wir zuvor eingerichtet haben.

Im Codebeispiel haben wir das Argument -m angegeben, um die Logmeldung direkt in der Befehlszeile eingeben zu können. Wenn du es vorziehst, eine detaillierte Logmeldung über eine interaktive Editor-Sitzung zu erstellen, kannst du das auch tun. Du musst Git so konfigurieren, dass dein Lieblingseditor während einer git commit gestartet wird (lass das Argument -m weg); wenn es nicht bereits gesetzt ist, kannst du die Umgebungsvariable $GIT_EDITOR wie folgt setzen:

   # In bash or zsh
   $ export GIT_EDITOR=vim

   # In tcsh
   $ setenv GIT_EDITOR emacs
Hinweis

Git beachtet den Standard-Texteditor, der in den Shell-Umgebungsvariablen VISUAL und EDITOR konfiguriert ist. Wenn keiner von beiden konfiguriert ist, wird der Editor vi verwendet.

Nachdem du die Datei index.html in das Repository übertragen hast, rufe git status auf, um den aktuellen Stand deines Repositorys zu erfahren. In unserem Beispiel sollte git status anzeigen, dass es keine ausstehenden Änderungen gibt, die übertragen werden müssen:

   $ git status

   On branch main
   nothing to commit, working tree clean

Git sagt dir auch, dass dein Arbeitsverzeichnis sauber ist. Das bedeutet, dass das Arbeitsverzeichnis keine neuen oder geänderten Dateien enthält, die sich von denen im Repository unterscheiden.

Abbildung 1-3 hilft dir, alle Schritte, die du gerade gelernt hast, zu visualisieren.

Der Unterschied zwischen git add und git commit ist so, als würdest du eine Gruppe von Schulkindern in einer bestimmten Reihenfolge organisieren, um das perfekte Klassenfoto zu bekommen: git add organisiert, während git commit den Schnappschuss macht.

vcg3 0103
Abbildung 1-3. Bereitstellen und Hinzufügen einer Datei zu einem Repository

Eine weitere Verpflichtung eingehen

Als Nächstes nehmen wir ein paar Änderungen an index.html vor und erstellen eine Repository-Historie innerhalb des Repositorys.

Wandle index.html in eine richtige HTML-Datei um und übertrage die Änderung in diese:

   $ cd ~/my_website

   # edit the index.html file.

   $ cat index.html
   <html>
   <body>
   My website is awesome!
   </body>
   </html>

   $ git commit index.html -m 'Convert to HTML'
   [main 521edbe] Convert to HTML
    1 file changed, 5 insertions(+), 1 deletion(-)

Wenn du bereits mit Git vertraut bist, fragst du dich vielleicht, warum wir den Schritt git add index.html übersprungen haben, bevor wir die Datei übertragen haben. Das liegt daran, dass der zu übertragende Inhalt in Git auf mehr als eine Weise angegeben werden kann.

Gib ein git commit --help um mehr über diese Optionen zu erfahren:

   $ git commit --help

   NAME
       git-commit - Record changes to the repository

   SYNOPSIS
       git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]
                  [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>)]
                  [-F <file> | -m <msg>] [--reset-author] [--allow-empty]
                  [--allow-empty-message] [--no-verify] [-e] [--author=<author>]
                  [--date=<date>] [--cleanup=<mode>] [--[no-]status]
                  [-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]
                  [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]
                  [--] [<pathspec>...]

   ...
Tipp

Ausführliche Erläuterungen zu den verschiedenen Commit-Methoden findest du auch auf den Handbuchseiten von git commit --help.

In unserem Beispiel haben wir uns entschieden, die Datei index.html mit einem zusätzlichen Argument, dem Schalter -m, zu übertragen, der eine Nachricht liefert, die die Änderungen in der Übertragung erklärt: 'Convert to HTML'. Abbildung 1-4 erklärt die Methode, die wir gerade besprochen haben.

vcg3 0104
Abbildung 1-4. Bereitstellen und Hinzufügen von Änderungen an einer verfolgten Datei in einem Repository

Beachte, dass unsere Verwendung von git commit index.html -m 'Convert to HTML' das Staging der Datei nicht überspringt; Git erledigt dies automatisch als Teil der Commit-Aktion.

Deine Commits ansehen

Jetzt, wo du mehr Commits in der Repository-Historie hast, kannst du sie auf verschiedene Arten untersuchen. Einige git Befehle zeigen die Reihenfolge der einzelnen Commits an, andere zeigen die Zusammenfassung eines einzelnen Commits und wieder andere zeigen die vollständigen Details jedes Commits, den du im Repository angibst.

Der Befehl git log liefert eine fortlaufende Historie der einzelnen Commits im Repository:

   $ git log

   commit 521edbe1dd2ec9c6f959c504d12615a751b5218f (HEAD -> main)
   Author: Jon Loeliger <jdl@example.com>
   Date:   Mon Jul 4 12:01:54 2022 +0200

        Convert to HTML

   commit c149e12e89a9c035b9240e057b592ebfc9c88ea4
   Author: Jon Loeliger <jdl@example.com>
   Date:   Mon Jul 4 11:58:36 2022 +0200

        Initial contents of my_website

In der vorangegangenen Ausgabe gibt der Befehl git log detaillierte Protokollinformationen für jeden Commit im Repository aus. Zu diesem Zeitpunkt hast du nur zwei Commits in deiner Repository-Historie, was das Lesen der Ausgabe erleichtert. Bei Repositories mit vielen Commit-Historien hilft dir diese Standardansicht möglicherweise nicht, eine lange Liste detaillierter Commit-Informationen leicht zu durchforsten; in solchen Situationen kannst du mit dem Schalter --oneline eine zusammengefasste Commit-ID-Nummer zusammen mit der Commit-Nachricht auflisten:

   $ git log --oneline

   521edbe (HEAD -> main) Convert to HTML
   c149e12 Initial contents of my_website

Die Commit-Log-Einträge werden in der Reihenfolge vom jüngsten zum ältesten Eintrag aufgelistet.1 (die Originaldatei). Jeder Eintrag enthält den Namen und die E-Mail-Adresse des Commit-Autors, das Datum des Commits, die Logmeldung für die Änderung und die interne Identifikationsnummer des Commits. Die Commit-ID-Nummer wird in "Inhaltsadressierbare Datenbank" erklärt. Wir werden Commits in Kapitel 4 ausführlicher besprechen.

Wenn du mehr Details zu einem bestimmten Commit sehen willst, benutze den Befehl git show mit einer Commit-ID-Nummer:

   $ git show c149e12e89a9c035b9240e057b592ebfc9c88ea4

   commit c149e12e89a9c035b9240e057b592ebfc9c88ea4
   Author: Jon Loeliger <jdl@example.com>
   Date:   Mon Jul 4 11:58:36 2022 +0200

   Initial contents of my_website

   diff --git a/index.html b/index.html
   new file mode 100644
   index 0000000..6331c71
   --- /dev/null
   +++ b/index.html
   @@ -0,0 +1 @@
   +My awesome website!
Tipp

Wenn du git show ohne eine explizite Commit-Nummer aufrufst, zeigt es einfach die Details des HEAD Commits an, in unserem Fall den jüngsten.

Der Befehl git log zeigt in den Commit-Logs an, wie die Änderungen für jeden Commit in die Repo-Historie aufgenommen werden. Wenn du knappe, einzeilige Zusammenfassungen für den aktuellen Entwicklungszweig sehen willst, ohne dem Befehl git log --oneline zusätzliche Filteroptionen zu geben, kannst du alternativ den Befehl git show-branch verwenden:

   $ git show-branch --more=10

   [main] Convert to HTML
   [main^] Initial contents of my_website

Die Phrase --more=10 zeigt bis zu 10 weitere Versionen an, aber bisher gibt es nur zwei und deshalb werden beide angezeigt. (Die Standardeinstellung würde in diesem Fall nur die jüngste Übertragung auflisten.) Der Name main ist der Standardzweigname.

In Kapitel 3 werden wir die Verzweigungen besprechen und den Befehl git show-branch genauer unter die Lupe nehmen.

Unterschiede bei der Übertragung anzeigen

Mit der Repo-Historie von kannst du jetzt die Unterschiede zwischen den beiden Revisionen von index.html sehen. Du musst dir die Commit-ID-Nummern merken und den Befehl git diff ausführen:

   $ git diff c149e12e89a9c035b9240e057b592ebfc9c88ea4 \
               521edbe1dd2ec9c6f959c504d12615a751b5218f

   diff --git a/index.html b/index.html
   index 6331c71..8cfcb90 100644
   --- a/index.html
   +++ b/index.html
   @@ -1 +1,5 @@
   -My awesome website!
   +<html>
   +<body>
    My website is awesome!
   +</body>
   +</html>

Die Ausgabe ähnelt der, die der Befehl git diff erzeugt. Gemäß der Konvention ist die erste Revisionsübergabe, 9da581d910c9c4ac93557ca4859e767f5caf5169, die frühere des Inhalts von index.html und die zweite Revisionsübergabe, ec232cddfb94e0dfd5b5855af8ded7f5eb5c90d6, der neueste Inhalt von index.html. Daher steht vor jeder Zeile mit neuem Inhalt ein Pluszeichen (+) nach dem Minuszeichen (), das für entfernten Inhalt steht.

Hinweis

Lass dich von den langen Hex-Zahlen nicht einschüchtern. Git bietet viele kürzere, einfachere Möglichkeiten, ähnliche Befehle auszuführen, sodass du große, komplizierte Commit-IDs vermeiden kannst. In der Regel reichen die ersten sieben Zeichen der Hexadezimalzahlen, wie im Beispiel git log --oneline gezeigt, aus. Wir gehen in "Inhaltsadressierbare Datenbank" näher darauf ein .

Entfernen und Umbenennen von Dateien in deinem Projektarchiv

Nachdem du nun gelernt hast, wie man Dateien zu einem Git-Repository hinzufügt, schauen wir uns nun an, wie man eine Datei aus einem Repository entfernt. Das Entfernen einer Datei aus einem Git-Repository erfolgt analog zum Hinzufügen einer Datei, allerdings mit dem Befehl git rm. Angenommen, du hast die Datei adverts.html im Inhalt deiner Website und möchtest sie entfernen. Das kannst du wie folgt tun:

   $ cd ~/my_website
   $ ls
   index.html  adverts.html

   $ git rm adverts.html
   rm  'adverts.html'

   $ git commit -m "Remove adverts html"
   [main 97ff70a] Remove adverts html
    1 file changed, 0 insertions(+), 0 deletions(-)
    delete mode 100644 adverts.html

Ähnlich wie bei einer Hinzufügung sind auch beim Löschen zwei Schritte erforderlich: Drücke deine Absicht, die Datei zu entfernen, mit git rm aus, das auch die Datei, die du entfernen willst, in Szene setzt. Realisiere die Änderung im Repository mit git commit.

Hinweis

Genau wie bei git add löschen wir bei git rm nicht direkt die Datei, sondern wir ändern, was verfolgt wird: das Löschen oder Hinzufügen einer Datei.

Du kannst eine Datei indirekt umbenennen, indem du eine Kombination aus den Befehlen git rm und git add verwendest, oder du kannst die Datei schneller und direkt mit dem Befehl git mv umbenennen. Hier ist ein Beispiel für Ersteres:

   $ mv foo.html bar.html
   $ git rm foo.html
   rm 'foo.html'

   $ git add bar.html

In dieser Reihenfolge musst du zu Beginn mv foo.html bar.html ausführen, um zu verhindern, dass git rm die Datei foo.html dauerhaft aus dem Dateisystem löscht.

Hier siehst du den gleichen Vorgang mit git mv:

   $ git mv foo.html bar.html

In beiden Fällen müssen die abgestuften Änderungen anschließend übertragen werden:

   $ git commit -m "Moved foo to bar"
   [main d1e37c8] Moved foo to bar
    1 file changed, 0 insertions(+), 0 deletions(-)
    rename foo.html => bar.html (100%)

Git geht mit Dateiverschiebungen anders um als die meisten ähnlichen Systeme und verwendet einen Mechanismus, der auf der Ähnlichkeit des Inhalts zwischen zwei Dateiversionen basiert. Die Einzelheiten dazu werden in Kapitel 5 beschrieben.

Arbeiten mit einem gemeinsamen Repository

Inzwischen hast du ein neues Repository initialisiert und Änderungen daran vorgenommen. Alle Änderungen sind nur auf deinem lokalen Entwicklungsrechner verfügbar. Das ist ein gutes Beispiel dafür, wie du ein Projekt verwalten kannst, das nur für dich zugänglich ist. Aber wie kannst du gemeinsam an einem Repository arbeiten, das auf einem Git-Server gehostet wird? Lasst uns besprechen, wie ihr das erreichen könnt.

Erstellen einer lokalen Kopie des Repositorys

Mit dem Befehl git clone kannst du eine vollständige Kopie oder einen Klon eines Repositorys erstellen. Auf diese Weise arbeitest du mit anderen Personen zusammen, nimmst Änderungen an denselben Dateien vor und bleibst mit den Änderungen anderer Versionen desselben Repositorys synchron.

Für dieses Tutorial fangen wir ganz einfach an, indem wir eine Kopie deines bestehenden Repositorys erstellen; dann können wir das gleiche Beispiel so darstellen, als ob es auf einem entfernten Git-Server läge:

   $ cd ~
   $ git clone my_website new_website

Obwohl diese beiden Git-Repositories jetzt genau die gleichen Objekte, Dateien und Verzeichnisse enthalten, gibt es einige feine Unterschiede. Du kannst diese Unterschiede mit Befehlen wie dem folgenden untersuchen:

   $ ls -lsa my_website new_website
   ...
   $ diff -r my_website new_website
   ...

Auf einem lokalen Dateisystem wie diesem ist die Verwendung von git clone, um eine Kopie eines Repositorys zu erstellen, ganz ähnlich wie die Verwendung von cp -a oder rsync. Wenn du dagegen dasselbe Repository von einem Git-Server klonen möchtest, würde die Syntax wie folgt lauten:

   $ cd ~

   $ git clone https://git-hosted-server.com/some-dir/my_website.git new_website
   Cloning into 'new_website'...
   remote: Enumerating objects: 2, done.
   remote: Counting objects: 100% (2/2), done.
   remote: Compressing objects: 100% (103/103), done.
   remote: Total 125 (delta 45), reused 65 (delta 18), pack-reused 0
   Receiving objects: 100% (125/125), 1.67 MiB | 4.03 MiB/s, done.
   Resolving deltas: 100% (45/45), done.

Sobald du ein Repository geklont hast, kannst du die geklonte Version ändern, neue Commits machen, die Logs und die Historie einsehen und so weiter. Es ist ein komplettes Repository mit einer vollständigen Historie. Erinnere dich daran, dass die Änderungen, die du am geklonten Projektarchiv vornimmst, nicht automatisch in die ursprüngliche Kopie des Projektarchivs übertragen werden.

Abbildung 1-5 veranschaulicht dieses Konzept.

vcg3 0105
Abbildung 1-5. Klonen eines gemeinsamen Repositorys

Lass dich von den Begriffen, die du in der Ausgabe siehst, nicht ablenken. Git unterstützt eine größere Anzahl von Repository-Quellen, einschließlich Netzwerknamen, um das zu klonende Repository zu benennen. Wir werden diese Formen und ihre Verwendung in Kapitel 11 erklären.

Konfigurationsdateien

Die Git-Konfigurationsdateien sind alle einfache Textdateien im Stil von .ini-Dateien. In den Konfigurationsdateien werden Präferenzen und Einstellungen gespeichert, die von mehreren git Befehlen verwendet werden. Einige der Einstellungen sind persönliche Vorlieben (z. B. soll color.pager verwendet werden?), andere sind wichtig, damit ein Repository richtig funktioniert (z. B. core repositoryformatversion), und wieder andere verändern das Verhalten der git Befehle ein wenig (z. B. gc.auto). Wie andere Tools auch, unterstützt Git eine Hierarchie von Konfigurationsdateien.

Hierarchie der Konfigurationsdateien

Abbildung 1-6 zeigt die Hierarchie der Git-Konfigurationsdateien in abnehmender Rangfolge:

.git/config

Repository-spezifische Konfigurationseinstellungen mit der Option --file oder standardmäßig manipuliert. Du kannst auch mit der Option --local in diese Datei schreiben. Diese Einstellungen haben den höchsten Vorrang.

~/.gitconfig

Benutzerspezifische Konfigurationseinstellungen, die mit der Option --global bearbeitet werden.

/etc/gitconfig

Systemweite Konfigurationseinstellungen kannst du mit der Option --system ändern, wenn du die richtigen Unix-Schreibrechte für die Datei gitconfig hast. Diese Einstellungen haben den geringsten Vorrang. Je nach deiner Installation kann sich die Datei mit den Systemeinstellungen an einer anderen Stelle befinden (vielleicht in /usr/local/etc gitconfig) oder ganz fehlen.

vcg3 0106
Abbildung 1-6. Hierarchie der Git-Konfigurationsdateien

Um zum Beispiel einen Autorennamen und eine E-Mail-Adresse zu speichern, die für alle deine Commits in allen Repositories verwendet wird, konfiguriere die Werte für user name und user.email in deiner Datei $HOME/.gitconfig mit git config --global:

   $ git config --global user.name "Jon Loeliger"
   $ git config --global user.email "jdl@example.com"

Wenn du einen repository-spezifischen Namen und eine E-Mail-Adresse festlegen musst, die eine --global -Einstellung überschreiben würden, lass einfach das --global -Flag weg oder benutze das --local -Flag, um explizit zu sein:

   $ git config user.name "Jon Loeliger"
   $ git config user.email "jdl@special-project.example.org"

Du kannst git config -l (oder die Langform --list) verwenden, um die Einstellungen aller Variablen aufzulisten, die sich in der gesamten Konfigurationsdatei befinden:

   # Make a brand-new, empty repository
   $ mkdir /tmp/new
   $ cd /tmp/new
   $ git init

   # Set some config values
   $ git config --global user.name "Jon Loeliger"
   $ git config --global user.email "jdl@example.com"
   $ git config user.email "jdl@special-project.example.org"

   $ git config -l
   user.name=Jon Loeliger
   user.email=jdl@example.com
   core.repositoryformatversion=0
   core.filemode=true
   core.bare=false
   core.logallrefupdates=true
   user.email=jdl@special-project.example.org
Tipp

Wenn du den Befehl git config -l angibst, kannst du mit den Optionen --show-scope und --show-origin die verschiedenen Quellen für die Konfigurationen ausgeben! Probiere das mit git config -l --show-scope --show-origin in deinem Terminal aus.

Da es sich bei den Konfigurationsdateien um einfache Textdateien handelt, kannst du ihren Inhalt mit cat ansehen und sie auch mit deinem bevorzugten Texteditor bearbeiten:

   # Look at just the repository-specific settings

   $ cat .git/config
   [core]
       repositoryformatversion = 0
       filemode = true
       bare = false
       logallrefupdates = true
ignorecase = true
	precomposeunicode = true

   [user]
       email = jdl@special-project.example.org
Hinweis

Der Inhalt der Konfigurationstextdatei kann sich je nach Betriebssystemleicht unterscheiden. Viele dieser Unterschiede ermöglichen unterschiedlicheEigenschaften des Dateisystems.

Wenn du eine Einstellung aus den Konfigurationsdateien entfernen musst, verwende die Option --unset zusammen mit dem Flag correct configuration files:

   $ git config --unset --global user.email

Git stellt dir viele Konfigurationsoptionen und Umgebungsvariablen zur Verfügung, die häufig für den gleichen Zweck existieren. Du kannst zum Beispiel einen Wert für den Editor festlegen, der beim Verfassen einer Commit-Logmeldung verwendet werden soll. Basierend auf der Konfiguration folgt der Aufruf diesen Schritten:

  1. GIT_EDITOR Umgebungsvariable

  2. core.editor Konfigurationsoption

  3. VISUAL Umgebungsvariable

  4. EDITOR Umgebungsvariable

  5. Der Befehl vi

Es gibt mehr als ein paar hundert Konfigurationsparameter. Wir werden dich nicht mit ihnen langweilen, sondern nach und nach auf wichtige Parameter hinweisen. Eine ausführlichere (aber immer noch unvollständige) Liste findest du auf der Handbuchseite git config.

Tipp

Eine vollständige Liste aller git Befehle findest du online.

Einen Alias konfigurieren

Git-Aliase ermöglichen es dir, häufige aber komplexe git Befehle, die du häufig eingibst, durch einfache und leicht zu erinnernde Aliase zu ersetzen. Das erspart dir die Mühe, dich an lange Befehle zu erinnern oder sie abzutippen, und es erspart dir den Frust über Tippfehler:

   $ git config --global alias.show-graph \
           'log --graph --abbrev-commit --pretty=oneline'

In diesem Beispiel haben wir den Alias show-graph erstellt und ihn in jedem Repository, das wir erstellen, verfügbar gemacht. Wenn wir den Befehl git show-graph verwenden, erhalten wir dieselbe Ausgabe, die wir erhalten haben, als wir den langen Befehl git log mit all diesen Optionen eingegeben haben.

Zusammenfassung

Auch nach allem, was du bisher gelernt hast, wirst du sicherlich viele unbeantwortete Fragen dazu haben, wie Git funktioniert. Wie speichert Git zum Beispiel jede Version einer Datei? Was macht eigentlich einen Commit aus? Woher kommen diese komischen Commit-Nummern? Warum der Name "main"? Und ist ein "Branch" das, was ich denke, dass er ist? Das sind gute Fragen. Was wir behandelt haben, gibt dir einen Einblick in die Vorgänge, die du in deinen Projekten häufig verwenden wirst. Die Antworten auf deine Fragen werden in Teil II im Detail erklärt.

Das nächste Kapitel definiert einige Begriffe, führt in einige Git-Konzepte ein und schafft eine Grundlage für die Lektionen im Rest des Buches.

1 Streng genommen sind sie nicht chronologisch geordnet, sondern eher eine topologische Sortierung der Commits.

Get Versionskontrolle mit Git, 3. Auflage now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.