Adjust `makeover` to handle newer AsciiDoc output.
[gitmagic.git] / de / secrets.txt
blob0c26226008cf37de787c7820b0352d34d3228330
1 == Aufgedeckte Geheimnisse ==
3 Wir werfen einen Blick unter die Motorhaube und erklären, wie Git seine
4 Wunder vollbringt. Ich werde nicht ins Detail gehen. Für tiefer gehende
5 Erklärungen verweise ich auf das
6 http://www.kernel.org/pub/software/scm/git/docs/user-manual.html[englischsprachige
7 Benutzerhandbuch].
9 === Unsichtbarkeit ===
11 Wie kann Git so unauffällig sein? Abgesehen von gelegentlichen 'Commits' und
12 'Merges' kannst Du arbeiten, als würde die Versionsverwaltung nicht
13 existieren. Das heißt, bis Du sie brauchst. Und das ist, wenn Du froh bist,
14 dass Git die ganze Zeit über Dich gewacht hat.
16 Andere Versionsverwaltungssysteme zwingen Dich ständig, Dich mit
17 Verwaltungskram und Bürokratie herumzuschlagen. Dateien können
18 schreibgeschützt sein, bis Du einem zentralen Server mitteilst, welche
19 Dateien Du gerne bearbeiten möchtest. Die einfachsten Befehle werden bis zum
20 Schneckentempo verlangsamt, wenn die Anzahl der Anwender steigt. Deine
21 Arbeit kommt zum Stillstand, wenn das Netzwerk oder der zentrale Server weg
22 sind.
24 Im Gegensatz dazu hält Git seinen Verlauf einfach im `.git` Verzeichnis von
25 Deinem Arbeitsverzeichnis. Das ist Deine eigene Kopie der
26 Versionsgeschichte, damit kannst Du so lange offline bleiben, bis Du mit
27 anderen kommunizieren willst. Du hast die absolute Kontrolle über das
28 Schicksal Deiner Dateien, denn Git kann jederzeit einfach einen gesicherten
29 Stand aus `.git` wiederherstellen.
31 === Integrität ===
33 Die meisten Leute verbinden mit Kryptographie die Geheimhaltung von
34 Informationen, aber ein genau so wichtiges Ziel ist es, Informationen zu
35 sichern. Die richtige Anwendung von kryptographischen Hash-Funktionen kann
36 einen versehentlichen oder bösartigen Datenverlust verhindern.
38 Einen SHA1-Hash-Wert kann man sich als eindeutige 160-Bit Identitätsnummer
39 für jegliche Zeichenkette vorstellen, welche Dir in Deinem ganzen Leben
40 begegnen wird. Sogar mehr als das: jegliche Zeichenfolge, die alle Menschen
41 über mehrere Generationen verwenden.
43 Ein SHA1-Hash-Wert selbst ist eine Zeichenfolge von Bytes. Wir können
44 SHA1-Hash-Werte aus Zeichenfolgen generieren, die selbst SHA1-Hash-Werte
45 enthalten. Diese einfache Beobachtung ist überraschend nützlich: suche nach
46 'hash chains'. Wir werden später sehen, wie Git diese nutzt um effizient die
47 Datenintegrität zu garantieren.
49 Kurz gesagt, Git hält Deine Daten in dem `.git/objects` Unterverzeichnis, wo
50 Du anstelle von normalen Dateinamen nur Identitätsnummern findest. Durch die
51 Verwendung von Identitätsnummern als Dateiname, zusammen mit ein paar
52 Sperrdateien und Zeitstempeltricks, macht Git aus einem einfachen
53 Dateisystem eine effiziente und robuste Datenbank.
55 === Intelligenz ===
57 Woher weiß Git, dass Du eine Datei umbenannt hast, obwohl Du es ihm niemals
58 explizit mitgeteilt hast? Sicher, Du hast vielleicht *git mv* benutzt, aber
59 das ist exakt das selbe wie *git rm* gefolgt von *git add*.
61 Git stöbert Umbenennungen und Kopien zwischen aufeinander folgenden
62 Versionen heuristisch auf. Vielmehr kann es sogar Codeblöcke erkennen, die
63 zwischen Dateien hin und her kopiert oder verschoben wurden! Jedoch kann es
64 nicht alle Fälle abdecken, aber es leistet ordentliche Arbeit und diese
65 Eigenschaft wird immer besser. Wenn es bei Dir nicht funktioniert, versuche
66 Optionen zur aufwendigeren Erkennung von Kopien oder erwäge einen Upgrade.
68 === Indizierung ===
70 Für jede überwachte Datei speichert Git Informationen wie deren Größe, ihren
71 Erstellzeitpunkt und den Zeitpunkt der letzten Bearbeitung in einer Datei
72 die wir als 'Index' kennen. Um zu ermitteln, ob eine Datei verändert wurde,
73 vergleicht Git den aktuellen Status mit dem im Index gespeicherten. Stimmen
74 diese Daten überein, kann Git das Lesen des Dateiinhalts überspringen.
76 Da das Abfragen des Dateistatus erheblich schneller ist als das Lesen der
77 Datei, kann Git, wenn Du nur ein paar Dateien verändert hast, seinen Status
78 im Nu aktualisieren.
80 Wir haben früher festgestellt, dass der Index ein Bereitstellungsraum
81 ist. Warum kann ein Haufen von Dateistatusinformationen ein
82 Bereitstellungsraum sein? Weil die 'add' Anweisung Dateien in die Git
83 Datenbank befördert und die Dateistatusinformationen aktualisiert, während
84 die 'commit' Anweisung, ohne Optionen, einen 'Commit' nur auf Basis der
85 Dateistatusinformationen erzeugt, weil die Dateien ja schon in der Datenbank
86 sind.
88 === Git's Wurzeln ===
90 Dieser http://lkml.org/lkml/2005/4/6/121['Linux Kernel Mailing List'
91 Beitrag] beschreibt die Kette von Ereignissen, die zu Git geführt haben. Der
92 ganze Beitrag ist eine faszinierende archäologische Seite für Git
93 Historiker.
95 === Die Objektdatenbank ===
97 Jegliche Versionen Deiner Daten wird in der Objektdatenbank gehalten, welche
98 im Unterverzeichnis `.git/objects` liegt; Die anderen Orte in `.git/`
99 enthalten weniger wichtige Daten: den Index, 'Branch' Namen, Bezeichner
100 ('tags'), Konfigurationsoptionen, Logdateien, die Position des aktuellen
101 'HEAD Commit' und so weiter. Die Objektdatenbank ist einfach aber trotzdem
102 elegant, und sie ist die Quelle von Git's Macht.
104 Jede Datei in `.git/objects` ist ein 'Objekt'. Es gibt drei Arten von
105 Objekten, die uns betreffen: 'Blob'-, 'Tree'- und 'Commit'-Objekte.
107 === Blobs ===
109 Zuerst ein Zaubertrick. Suche Dir irgendeinen Dateinamen aus. In
110 einem leeren Verzeichnis:
112  $ echo sweet > DEIN_DATEINAME
113  $ git init
114  $ git add .
115  $ find .git/objects -type f
117 Du wirst folgendes sehen:
118 +.git/objects/aa/823728ea7d592acc69b36875a482cdf3fd5c8d+.
120 Wie konnte ich das wissen, ohne den Dateiname zu kennen? Weil der
121 SHA1-Hash-Wert von:
123  "blob" SP "6" NUL "sweet" LF
125 aa823728ea7d592acc69b36875a482cdf3fd5c8d ist. Wobei SP ein Leerzeichen ist,
126 NUL ist ein Nullbyte und LF ist ein Zeilenumbruch. Das kannst Du durch die
127 Eingabe von
129   $ printf "blob 6\000sweet\n" | sha1sum
131 kontrollieren.
133 Git ist 'assoziativ': Dateien werden nicht nach Ihren Namen gespeichert,
134 sondern eher nach dem SHA1-Hash-Wert der Daten, welche sie enthalten, in
135 einer Datei, die wir als 'Blob'-Objekt bezeichnen. Wir können uns den
136 SHA1-Hash-Wert als eindeutige Identnummer des Dateiinhalts vorstellen, was
137 sinngemäß bedeutet, dass die Dateien über ihren Inhalt adressiert
138 werden. Das führende `blob 6` ist lediglich ein Vermerk, der sich aus dem
139 Objekttyp und seiner Länge in Bytes zusammensetzt; er vereinfacht die
140 interne Verwaltung.
142 So konnte ich einfach vorhersagen, was Du sehen wirst. Der Dateiname ist
143 irrelevant: nur der Dateiinhalt wird zum Erstellen des 'Blob'-Objekt
144 verwendet.
146 Du wirst Dich fragen, was mit identischen Dateien ist. Versuche Kopien
147 Deiner Datei hinzuzufügen, mit beliebigen Dateinamen. Der Inhalt von
148 +.git/objects+ bleibt der selbe, ganz egal wieviele Dateien Du
149 hinzufügst. Git speichert den Dateiinhalt nur ein einziges Mal.
151 Übrigens, die Dateien in +.git/objects+ sind mit zlib komprimiert, Du
152 solltest sie also nicht direkt anschauen. Filtere sie durch
153 http://www.zlib.net/zpipe.c[zpipe -d], oder gib ein:
155  $ git cat-file -p aa823728ea7d592acc69b36875a482cdf3fd5c8d
157 was Dir das Objekt im Klartext anzeigt.
159 === 'Trees' ===
161 Aber wo sind die Dateinamen? Sie müssen irgendwo gespeichert sein. Git kommt
162 beim 'Commit' dazu, sich um die Dateinamen zu kümmern:
164  $ git commit  # Schreibe eine Bemerkung.
165  $ find .git/objects -type f
167 Du solltest nun drei Objekte sehen. Dieses mal kann ich Dir nicht sagen, wie
168 die zwei neuen Dateien heißen, weil es zum Teil vom gewählten Dateiname
169 abhängt, den Du ausgesucht hast. Fahren wir fort mit der Annahme, Du hast
170 eine Datei ``rose'' genannt. Wenn nicht, kannst Du den Verlauf so
171 umschreiben, dass es so aussieht, als hättest Du es:
173  $ git filter-branch --tree-filter 'mv DEIN_DATEINAME rose'
174  $ find .git/objects -type f
176 Nun müsstest Du die Datei
177 +.git/objects/05/b217bb859794d08bb9e4f7f04cbda4b207fbe9+ sehen, denn das ist
178 der SHA1-Hash-Wert ihres Inhalts:
180  "tree" SP "32" NUL "100644 rose" NUL 0xaa823728ea7d592acc69b36875a482cdf3fd5c8d
182 Prüfe, ob diese Datei tatsächlich dem obigen Inhalt entspricht, durch
183 Eingabe von:
185  $ echo 05b217bb859794d08bb9e4f7f04cbda4b207fbe9 | git cat-file --batch
187 Mit zpipe ist es einfach, den SHA1-Hash-Wert zu prüfen:
189  $ zpipe -d < .git/objects/05/b217bb859794d08bb9e4f7f04cbda4b207fbe9 | sha1sum
191 Die SHA1-Hash-Wert Prüfung mit 'cat-file' ist etwas kniffliger, da dessen
192 Ausgabe mehr als die rohe unkomprimierte Objektdatei enthält.
194 Diese Datei ist ein 'Tree'-Objekt: eine Liste von Datensätzen, bestehend aus
195 dem Dateityp, dem Dateinamen und einem SHA1-Hash-Wert. In unserem Beispiel
196 ist der Dateityp 100644, was bedeutet, dass `rose` eine normale Datei ist,
197 und der SHA1-Hash-Wert entspricht dem 'Blob'-Objekt, welches den Inhalt von
198 `rose` enthält. Andere mögliche Dateitypen sind ausführbare Programmdateien,
199 symbolische Links oder Verzeichnisse. Im letzten Fall zeigt der
200 SHA1-Hash-Wert auf ein 'Tree'-Objekt.
202 Wenn Du 'filter-branch' aufrufst, bekommst Du alte Objekte, welche nicht
203 länger benötigt werden. Obwohl sie automatisch über Bord geworfen werden,
204 wenn ihre Gnadenfrist abgelaufen ist, wollen wir sie nun löschen, damit wir
205 unserem Beispiel besser folgen können.
207  $ rm -r .git/refs/original
208  $ git reflog expire --expire=now --all
209  $ git prune
211 Für reale Projekte solltest Du solche Anweisungen üblicherweise vermeiden,
212 da Du dadurch Datensicherungen zerstörst. Wenn Du ein sauberes 'Repository'
213 willst, ist es am besten, einen neuen Klon anzulegen. Sei auch vorsichtig,
214 wenn Du +.git+ direkt manipulierst: was, wenn zeitgleich ein Git Kommando
215 ausgeführt wird oder plötzlich der Strom ausfällt? Generell sollten
216 Referenzen mit *git update-ref -d* gelöscht werden, auch wenn es gewöhnlich
217 sicher ist +refs/original+ von Hand zu löschen.
219 === 'Commits' ===
221 Wir haben nun zwei von drei Objekten erklärt. Das dritte ist ein
222 'Commit'-Objekt. Sein Inhalt hängt von der 'Commit'-Beschreibung ab, wie
223 auch vom Zeitpunkt der Erstellung. Damit alles zu unserem Beispiel passt,
224 müssen wir ein wenig tricksen:
226  $ git commit --amend -m Shakespeare  # Ändere die Bemerkung.
227  $ git filter-branch --env-filter 'export
228      GIT_AUTHOR_DATE="Fri 13 Feb 2009 15:31:30 -0800"
229      GIT_AUTHOR_NAME="Alice"
230      GIT_AUTHOR_EMAIL="alice@example.com"
231      GIT_COMMITTER_DATE="Fri, 13 Feb 2009 15:31:30 -0800"
232      GIT_COMMITTER_NAME="Bob"
233      GIT_COMMITTER_EMAIL="bob@example.com"'  # Manipuliere Zeitstempel und Autor.
234  $ find .git/objects -type f
236 Du solltest nun +.git/objects/49/993fe130c4b3bf24857a15d7969c396b7bc187+
237 finden, was dem SHA1-Hash-Wert seines Inhalts entspricht:
239  "commit 158" NUL
240  "tree 05b217bb859794d08bb9e4f7f04cbda4b207fbe9" LF
241  "author Alice <alice@example.com> 1234567890 -0800" LF
242  "committer Bob <bob@example.com> 1234567890 -0800" LF
243  LF
244  "Shakespeare" LF
246 Wie vorhin kannst Du 'zpipe' oder 'cat-file' benutzen, um es für Dich zu
247 überprüfen.
249 Das ist der erste 'Commit' gewesen, deshalb gibt es keine
250 Eltern-'Commits'. Aber spätere 'Commits' werden immer mindestens eine Zeile
251 enthalten, die den Eltern-'Commit' identifiziert.
253 === Von Magie nicht zu unterscheiden ===
255 Git's Geheimnisse scheinen zu einfach. Es sieht so aus, als müsste man nur
256 ein paar Kommandozeilenskripte zusammenmixen, einen Schuß C-Code hinzufügen
257 und innerhalb ein paar Stunden ist man fertig: eine Mischung von
258 grundlegenden Dateisystemoperationen und SHA1-Hash-Berechnungen, garniert
259 mit Sperrdateien und Synchronisation für Stabilität. Tatsächlich beschreibt
260 dies die früheste Version von Git. Nichtsdestotrotz, abgesehen von
261 geschickten Verpackungstricks, um Speicherplatz zu sparen, und geschickten
262 Indizierungstricks, um Zeit zu sparen, wissen wir nun, wie Git gewandt ein
263 Dateisystem in eine Datenbank verwandelt, das perfekt für eine
264 Versionsverwaltung geeignet ist.
266 Angenommen, wenn irgendeine Datei in der Objektdatenbank durch einen
267 Laufwerksfehler zerstört wird, dann wird sein SHA1-Hash-Wert nicht mehr mit
268 seinem Inhalt übereinstimmen und uns sagen, wo das Problem liegt. Durch
269 Bilden von SHA1-Hash-Werten aus den SHA1-Hash-Werten anderer Objekte,
270 erreichen wir Integrität auf allen Ebenen. 'Commits' sind elementar, das
271 heißt, ein 'Commit' kann niemals nur Teile einer Änderung speichern: wir
272 können den SHA1-Hash-Wert eines 'Commits' erst dann berechnen und speichern,
273 nachdem wir bereits alle relevanten 'Tree'-Objekte, 'Blob'-Objekte und
274 Eltern-'Commits' gespeichert haben. Die Objektdatenbank ist immun gegen
275 unerwartete Unterbrechungen wie zum Beispiel einen Stromausfall.
277 Wir können sogar den hinterhältigsten Gegnern widerstehen. Stell Dir vor,
278 jemand will den Inhalt einer Datei ändern, die in einer älteren Version
279 eines Projekt liegt. Um die Objektdatenbank intakt aussehen zu lassen,
280 müssten sie außerdem den SHA1-Hash-Wert des korrespondierenden 'Blob'-Objekt
281 ändern, da die Datei nun eine geänderte Zeichenfolge enthält. Das heißt
282 auch, dass sie jeden SHA1-Hash-Wert der 'Tree'-Objekte ändern müssen, welche
283 dieses Objekt referenzieren und demzufolge alle SHA1-Hash-Werte der
284 'Commit'-Objekte, welche diese 'Tree'-Objekte beinhalten, zusätzlich zu
285 allen Abkömmlingen dieses 'Commits'. Das bedeutet auch, dass sich der
286 SHA1-Hash-Wert des offiziellen HEAD von dem des manipulierten 'Repository'
287 unterscheidet. Folgen wir dem Pfad der differierenden SHA1-Hash-Werte,
288 finden wir die verstümmelte Datei, wie auch den 'Commit', in dem sie
289 erstmals auftauchte.
291 Kurz gesagt, so lange die 20 Byte, welche den SHA1-Hash-Wert des letzen
292 'Commit' repräsentieren sicher sind, ist es unmöglich ein Git 'Repository'
293 zu fälschen.
295 Was ist mit Git's berühmten Fähigkeiten? 'Branching'? 'Merging'? 'Tags'? Nur
296 Kleinigkeiten. Der aktuelle HEAD wird in der Datei +.git/HEAD+ gehalten,
297 welche den SHA1-Hash-Wert eines 'Commit'-Objekts enthält. Der SHA1-Hash-Wert
298 wird während eines 'Commit' aktualisiert, genauso bei vielen anderen
299 Anweisungen. 'Branches' sind fast das selbe: sie sind Dateien in
300 +.git/refs/heads+. 'Tags' ebenso: sie stehen in +.git/refs/tags+ aber sie
301 werden durch einen Satz anderer Anweisungen aktualisiert.