-
1. Erste Schritte
-
2. Git Grundlagen
-
3. Git Branching
- 3.1 Branches auf einen Blick
- 3.2 Einfaches Branching und Merging
- 3.3 Branch-Management
- 3.4 Branching-Workflows
- 3.5 Remote-Branches
- 3.6 Rebasing
- 3.7 Zusammenfassung
-
4. Git auf dem Server
- 4.1 Die Protokolle
- 4.2 Git auf einem Server einrichten
- 4.3 Erstellung eines SSH-Public-Keys
- 4.4 Einrichten des Servers
- 4.5 Git-Daemon
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Von Drittanbietern gehostete Optionen
- 4.10 Zusammenfassung
-
5. Verteiltes Git
-
6. GitHub
-
7. Git Tools
- 7.1 Revisions-Auswahl
- 7.2 Interaktives Stagen
- 7.3 Stashen und Bereinigen
- 7.4 Deine Arbeit signieren
- 7.5 Suchen
- 7.6 Den Verlauf umschreiben
- 7.7 Reset entzaubert
- 7.8 Fortgeschrittenes Merging
- 7.9 Rerere
- 7.10 Debuggen mit Git
- 7.11 Submodule
- 7.12 Bundling
- 7.13 Replace (Ersetzen)
- 7.14 Anmeldeinformationen speichern
- 7.15 Zusammenfassung
-
8. Git einrichten
- 8.1 Git Konfiguration
- 8.2 Git-Attribute
- 8.3 Git Hooks
- 8.4 Beispiel für Git-forcierte Regeln
- 8.5 Zusammenfassung
-
9. Git und andere VCS-Systeme
- 9.1 Git als Client
- 9.2 Migration zu Git
- 9.3 Zusammenfassung
-
10. Git Interna
-
A1. Anhang A: Git in anderen Umgebungen
- A1.1 Grafische Schnittstellen
- A1.2 Git in Visual Studio
- A1.3 Git in Visual Studio Code
- A1.4 Git in IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine
- A1.5 Git in Sublime Text
- A1.6 Git in Bash
- A1.7 Git in Zsh
- A1.8 Git in PowerShell
- A1.9 Zusammenfassung
-
A2. Anhang B: Git in deine Anwendungen einbetten
- A2.1 Die Git-Kommandozeile
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
A3. Anhang C: Git Kommandos
- A3.1 Setup und Konfiguration
- A3.2 Projekte importieren und erstellen
- A3.3 Einfache Snapshot-Funktionen
- A3.4 Branching und Merging
- A3.5 Projekte gemeinsam nutzen und aktualisieren
- A3.6 Kontrollieren und Vergleichen
- A3.7 Debugging
- A3.8 Patchen bzw. Fehlerkorrektur
- A3.9 E-mails
- A3.10 Externe Systeme
- A3.11 Administration
- A3.12 Basisbefehle
7.5 Git Tools - Suchen
Suchen
Bei fast jeder Codebasis musst du oft herausfinden, wo eine Funktion aufgerufen oder definiert wird, oder die Historie einer Methode anzeigen. Git bietet eine Reihe nützlicher Werkzeuge, um den Code und die in seiner Datenbank gespeicherten Commits schnell und einfach zu durchsuchen. Im Folgenden gehen wir ein paar davon durch.
Git Grep
Git wird mit einem Befehl namens grep
ausgeliefert, der es dir ermöglicht, auf einfache Weise einen beliebigen Verzeichnisbaum, das Arbeitsverzeichnis oder sogar die Staging-Area nach einer Zeichenkette (engl. string) oder einem regulären Ausdruck (engl. regular expression) zu durchsuchen.
Für die folgenden Beispiele werden wir den Quellcode von Git selbst durchsuchen.
Standardmäßig durchsucht git grep
die Dateien in deinem Arbeitsverzeichnis.
Als erste Variante kannst du eine der Optionen -n
oder --line-number
verwenden, um die Zeilennummern anzuzeigen, bei denen Git Übereinstimmungen gefunden hat:
$ git grep -n gmtime_r
compat/gmtime.c:3:#undef gmtime_r
compat/gmtime.c:8: return git_gmtime_r(timep, &result);
compat/gmtime.c:11:struct tm *git_gmtime_r(const time_t *timep, struct tm *result)
compat/gmtime.c:16: ret = gmtime_r(timep, result);
compat/mingw.c:826:struct tm *gmtime_r(const time_t *timep, struct tm *result)
compat/mingw.h:206:struct tm *gmtime_r(const time_t *timep, struct tm *result);
date.c:482: if (gmtime_r(&now, &now_tm))
date.c:545: if (gmtime_r(&time, tm)) {
date.c:758: /* gmtime_r() in match_digit() may have clobbered it */
git-compat-util.h:1138:struct tm *git_gmtime_r(const time_t *, struct tm *);
git-compat-util.h:1140:#define gmtime_r git_gmtime_r
Zusätzlich zur oben gezeigten einfachen Suche unterstützt git grep
eine Vielzahl weiterer interessanter Optionen.
Anstatt beispielsweise alle Übereinstimmungen anzuzeigen, kannst du die Ausgabe von git grep
mit der Option -c
oder --count
zusammenfassen. Git zeigt dir dann nur an, welche Dateien den Suchbegriff enthalten und wie viele Übereinstimmungen es in jeder Datei gibt:
$ git grep --count gmtime_r
compat/gmtime.c:4
compat/mingw.c:1
compat/mingw.h:1
date.c:3
git-compat-util.h:2
Wenn du dich für den Kontext eines Suchbegriffs interessieren, kannst du die umschließende Methode oder Funktion für jeden passenden Suchbegriff mit einer der Optionen -p
oder --show-function
anzeigen:
$ git grep -p gmtime_r *.c
date.c=static int match_multi_number(timestamp_t num, char c, const char *date,
date.c: if (gmtime_r(&now, &now_tm))
date.c=static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt)
date.c: if (gmtime_r(&time, tm)) {
date.c=int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset)
date.c: /* gmtime_r() in match_digit() may have clobbered it */
Wie du sehen kannst, wird die Routine gmtime_r
sowohl von den Funktionen match_multi_number
als auch match_digit
in der Datei date.c
aufgerufen (die dritte angezeigte Übereinstimmung stellt nur den String dar, der in einem Kommentar erscheint).
Du kannst mit --and
nach komplexen Kombinationen von Strings suchen, was sicherstellt, dass mehrere Übereinstimmungen in der gleichen Textzeile vorkommen müssen.
Suchen wir zum Beispiel nach Zeilen, die eine Konstante definieren (den Teilstring #define
enthalten), deren Name einen der Teilstrings LINK
oder BUF_MAX
enthält. Wir suchen hier in einer älteren Version der Git-Codebasis, die durch den Tag v1.8.0 repräsentiert wird (wir werden die Optionen --break
und --heading
hinzufügen, um die Ausgabe in ein besser lesbares Format aufzuteilen):
$ git grep --break --heading \
-n -e '#define' --and \( -e LINK -e BUF_MAX \) v1.8.0
v1.8.0:builtin/index-pack.c
62:#define FLAG_LINK (1u<<20)
v1.8.0:cache.h
73:#define S_IFGITLINK 0160000
74:#define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK)
v1.8.0:environment.c
54:#define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS
v1.8.0:strbuf.c
326:#define STRBUF_MAXLINK (2*PATH_MAX)
v1.8.0:symlinks.c
53:#define FL_SYMLINK (1 << 2)
v1.8.0:zlib.c
30:/* #define ZLIB_BUF_MAX ((uInt)-1) */
31:#define ZLIB_BUF_MAX ((uInt) 1024 * 1024 * 1024) /* 1GB */
Der Befehl git grep
hat einige Vorteile gegenüber normalen Suchbefehlen wie grep
und ack
.
Der erste Vorteil ist, dass es sehr schnell ist, der zweite, dass du jeden Baum in Git durchsuchen kannst, nicht nur das Arbeitsverzeichnis.
Wie wir im obigen Beispiel gesehen haben, haben wir nach Begriffen in einer älteren Version des Git-Quellcodes gesucht, nicht in der Version, die gerade ausgecheckt war.
Stichwortsuche in Git Log
Vielleicht suchst du nicht, wo ein Begriff existiert, sondern wann er existiert oder eingeführt wurde.
Der Befehl git log
verfügt über eine Reihe leistungsfähiger Werkzeuge, um bestimmte Commits anhand des Inhalts ihrer Nachrichten, oder sogar anhand des Inhalts des von ihnen eingeführten Diffs zu finden.
Wenn wir zum Beispiel herausfinden wollen, wann die Konstante ZLIB_BUF_MAX
ursprünglich eingeführt wurde, können wir die Option -S
(umgangssprachlich als Git „pickaxe“ Option bezeichnet) verwenden, um Git anzuweisen, uns nur die Commits anzuzeigen, in denen die Anzahl der Vorkommen dieses Strings geändert wurde.
$ git log -S ZLIB_BUF_MAX --oneline
e01503b zlib: allow feeding more than 4GB in one go
ef49a7a zlib: zlib can only process 4GB at a time
Wenn wir uns den Unterschied dieser Commits ansehen, können wir sehen, dass die Konstante in ef49a7a
eingeführt und in e01503b
geändert wurde.
Wenn du spezifischer sein willst, kannst du mit der Option -G
einen regulären Ausdruck für die Suche angeben.
Zeilen- und Funktionssuche in Git Log
Eine weitere ziemlich fortgeschrittene Logsuche, die wahnsinnig nützlich ist, ist die Suche nach dem Zeilen- und Funktionsverlauf.
Führe einfach git log
mit der Option -L
aus, und es wird dir die Historie einer Funktion oder Codezeile in deiner Codebasis anzeigen.
Wenn wir zum Beispiel jede Änderung an der Funktion git_deflate_bound
in der Datei zlib.c
sehen wollten, könnten wir git log -L :git_deflate_bound:zlib.c
ausführen.
Dies wird versuchen, die Grenzen dieser Funktion herauszufinden und dann die Historie durchzusehen und uns jede Änderung, die an der Funktion vorgenommen wurde, als eine Reihe von Patches bis zum Zeitpunkt der ersten Erstellung der Funktion zu zeigen.
$ git log -L :git_deflate_bound:zlib.c
commit ef49a7a0126d64359c974b4b3b71d7ad42ee3bca
Author: Junio C Hamano <gitster@pobox.com>
Date: Fri Jun 10 11:52:15 2011 -0700
zlib: zlib can only process 4GB at a time
diff --git a/zlib.c b/zlib.c
--- a/zlib.c
+++ b/zlib.c
@@ -85,5 +130,5 @@
-unsigned long git_deflate_bound(z_streamp strm, unsigned long size)
+unsigned long git_deflate_bound(git_zstream *strm, unsigned long size)
{
- return deflateBound(strm, size);
+ return deflateBound(&strm->z, size);
}
commit 225a6f1068f71723a910e8565db4e252b3ca21fa
Author: Junio C Hamano <gitster@pobox.com>
Date: Fri Jun 10 11:18:17 2011 -0700
zlib: wrap deflateBound() too
diff --git a/zlib.c b/zlib.c
--- a/zlib.c
+++ b/zlib.c
@@ -81,0 +85,5 @@
+unsigned long git_deflate_bound(z_streamp strm, unsigned long size)
+{
+ return deflateBound(strm, size);
+}
+
Wenn Git nicht herausfinden kann, wie man eine Funktion oder Methode in deiner Programmiersprache abgleicht, kannst du Git auch einen regulären Ausdruck (engl. regular expression oder regex) mitgeben.
Zum Beispiel hätte Folgendes das Gleiche getan wie das obige Beispiel: git log -L '/unsigned long git_deflate_bound/',/^}/:zlib.c
.
Du kannst Git auch einen Bereich von Zeilen oder eine einzelne Zeilennummer angeben und du erhältst die gleiche Art von Ausgabe.