1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
|
== Multiplayer Git ==
Anfangs benutzte ich Git bei einem privaten Projekt, bei dem ich der einzige
Entwickler war. Unter den Befehlen im Zusammenhang mit Git's verteilter Art,
brauchte ich nur *pull* und *clone*, damit konnte ich das selbe Projekt an
unterschiedlichen Orten halten.
Später wollte ich meinen Code mit Git veröffentlichen und Änderungen von
Mitstreitern einbinden. Ich musste lernen, wie man Projekte verwaltet, an
denen mehrere Entwickler aus aller Welt beteiligt waren. Glücklicherweise
ist das Git's Stärke und wohl auch seine Daseinsberechtigung.
=== Wer bin ich? ===
Jeder 'Commit' enthält Name und eMail-Adresse des Autors, welche mit *git
log* angezeigt werden. Standardmäßig nutzt Git Systemeinstellungen, um diese
Felder auszufüllen. Um diese Angaben explizit zu setzen, gib ein:
$ git config --global user.name "Max Mustermann"
$ git config --global user.email maxmustermann@beispiel.de
Lasse den -global Schalter weg, um diese Einstellungen für das aktuelle
'Repository' zu setzen.
=== Git über SSH, HTTP ===
Angenommen, Du hast einen SSH-Zugang zu einem Webserver, aber Git ist nicht
installiert. Wenn auch nicht so effizient wie mit dem systemeigenen
Protokoll, kann Git über HTTP kommunizieren.
Lade Git herunter, compiliere und installiere es unter Deinem Benutzerkonto
und erstellen ein 'Repository' in Deinem Webverzeichnis:
$ GIT_DIR=proj.git git init
$ cd proj.git
$ git --bare update-server-info
$ cp hooks/post-update.sample hooks/post-update
Bei älteren Git Versionen funktioniert der 'copy'-Befehl nicht, stattdessen
gib ein:
$ chmod a+x hooks/post-update
Nun kannst Du Deine letzten Änderungen über SSH von jedem 'Clone' aus
veröffentlichen.
$ git push web.server:/pfad/zu/proj.git master
und jedermann kann Dein Projekt abrufen mit:
$ git clone http://web.server/proj.git
=== Git über alles ===
Willst Du 'Repositories' ohne Server synchronisieren oder gar ohne
Netzwerkverbindung? Musst Du während eines Notfalls improvisieren? Wir haben
gesehen, dass man mit <<makinghistory, *git fast-export* und *git
fast-import* 'Repositories' in eine einzige Datei konvertieren kann und
zurück>>. Wir können solche Dateien hin und her schicken, um Git
'Repositories' über jedes beliebige Medium zu transportieren, aber ein
effizienteres Werkzeug ist *git bundle*.
Der Absender erstellt ein 'Bundle':
$ git bundle create einedatei HEAD
und transportiert das 'Bundle' +einedatei+ irgendwie zum anderen
Beteiligten: per eMail, USB-Stick, einen *xxd* Hexdump und einen OCR
Scanner, Morsecode über Telefon, Rauchzeichen usw. Der Empfänger holt sich
die 'Commits' aus dem 'Bundle' durch Eingabe von:
$ git pull einedatei
Der Empfänger kann das sogar mit einem leeren 'Repository' tun. Trotz seiner
Größe, +einedatei+ enthält das komplette original Git 'Repository'.
In größeren Projekten vermeidest Du Datenmüll, indem Du nur Änderungen
'bundlest', die in den anderen 'Repositories' fehlen. Zum Beispiel, nehmen
wir an, der 'Commit' ``1b6d...'' ist der aktuellste, den beide Parteien
haben:
$ git bundle create einedatei HEAD ^1b6d
Macht man das regelmäßig, kann man leicht vergessen, welcher 'Commit'
zuletzt gesendet wurde. Die Hilfeseiten schlagen vor, 'Tags' zu benutzen, um
dieses Problem zu lösen. Das heißt, nachdem Du ein 'Bundle' gesendet hast,
gib ein:
$ git tag -f letztesbundle HEAD
und erstelle neue Aktualisierungsbundles mit:
$ git bundle create neuesbundle HEAD ^letztesbundle
=== Patches: Das globale Zahlungsmittel ===
'Patches' sind die Klartextdarstellung Deiner Änderungen, die von Computern
und Menschen gleichermaßen einfach verstanden werden. Dies verleiht ihnen
eine universelle Anziehungskraft. Du kannst einen 'Patch' Entwicklern
schicken, ganz egal, was für ein Versionsverwaltungssystem sie
benutzen. Solange Deine Mitstreiter ihre eMails lesen können, können sie
auch Deine Änderungen sehen. Auch auf Deiner Seite ist alles was Du brauchst
ein eMail-Konto: es gibt keine Notwendigkeit ein Online Git 'Repository'
aufzusetzen.
Erinnere Dich an das erste Kapitel:
$ git diff 1b6d > mein.patch
gibt einen 'Patch' aus, der zur Diskussion einfach in eine eMail eingefügt
werden kann. In einem Git 'Repository' gib ein:
$ git apply < mein.patch
um den 'Patch' anzuwenden.
In einer offizielleren Umgebung, wenn Autorennamen und eventuell Signaturen
aufgezeichnet werden sollen, erstelle die entsprechenden 'Patches' nach
einem bestimmten Punkt durch Eingabe von:
$ git format-patch 1b6d
Die resultierenden Dateien können an *git-send-email* übergeben werden oder
von Hand verschickt werden. Du kannst auch eine Gruppe von 'Commits'
angeben:
$ git format-patch 1b6d..HEAD^^
Auf der Empfängerseite speichere die eMail in eine Datei, dann gib ein:
$ git am < email.txt
Das wendet den eingegangenen 'Patch' an und erzeugt einen 'Commit',
inklusive der Informationen wie z.B. den Autor.
Mit einer Webmail Anwendung musst Du eventuell ein Button anklicken, um die
eMail in ihrem rohen Originalformat anzuzeigen, bevor Du den 'Patch' in eine
Datei sicherst.
Es gibt geringfügige Unterschiede bei mbox-basierten eMail Anwendungen, aber
wenn Du eine davon benutzt, gehörst Du vermutlich zu der Gruppe Personen,
die damit einfach umgehen können, ohne Anleitungen zu lesen.!
=== Entschuldigung, wir sind umgezogen. ===
Nach dem 'Clonen' eines 'Repositories', wird *git push* oder *git pull*
automatisch auf die original URL zugreifen. Wie macht Git das? Das Geheimnis
liegt in der Konfiguration, die beim 'Clonen' erzeugt wurde. Lasst uns einen
Blick riskieren:
$ git config --list
Die +remote.origin.url+ Option kontrolliert die Quell-URL; ``origin'' ist
der Spitzname, der dem Quell-'Repository' gegeben wurde. Wie mit der
``master'' 'Branch' Konvention können wir diesen Spitznamen ändern oder
löschen, aber es gibt für gewöhnlich keinen Grund, dies zu tun.
Wenn das original 'Repository' verschoben wird, können wir die URL
aktualisieren mit:
$ git config remote.origin.url git://neue.url/proj.git
Die +branch.master.merge+ Option definiert den Standard-Remote-'Branch' bei
einem *git pull*. Während des ursprünglichen 'Clonen' wird sie auf den
aktuellen 'Branch' des Quell-'Repository' gesetzt, so dass selbst dann, wenn
der 'HEAD' des Quell-'Repository' inzwischen auf einen anderen 'Branch'
gewechselt hat, ein späterer 'pull' treu dem original 'Branch' folgen wird.
Diese Option gilt nur für das 'Repository', von dem als erstes 'gecloned'
wurde, was in der Option +branch.master.remote+ hinterlegt ist. Bei einem
'pull' aus anderen 'Repositories' müssen wir explizit angeben, welchen
'Branch' wir wollen:
$ git pull git://beispiel.com/anderes.git master
Das obige erklärt, warum einige von unseren früheren 'push' und 'pull'
Beispielen keine Argumente hatten.
=== Entfernte 'Branches' ===
Wenn Du ein 'Repository' 'clonst', 'clonst' Du auch alle seine
'Branches'. Das hast Du vielleicht noch nicht bemerkt, denn Git versteckt
diese: Du musst speziell danach fragen. Das verhindert, dass 'Branches' vom
entfernten 'Repository' Deine lokalen 'Branches' stören, und es macht Git
einfacher für Anfänger.
Zeige die entfernten 'Branches' an mit:
$ git branch -r
Du solltes etwas sehen wie:
origin/HEAD
origin/master
origin/experimentell
Diese Liste zeigt die 'Branches' und den HEAD des entfernten 'Repository',
welche auch in regulären Git Anweisungen verwendet werden können. Zum
Beispiel, angenommen Du hast viele 'Commits' gemacht und möchtest einen
Vergleich zur letzten abgeholten Version machen. Du kannst die Logs nach dem
entsprechenden SHA1 Hashwert durchsuchen, aber es ist viel einfacher,
folgendes einzugeben:
$ git diff origin/HEAD
Oder Du kannst schauen, was auf dem 'Branch' ``experimentell'' los war:
$ git log origin/experimentell
=== Mehrere 'Remotes' ===
Angenommen, zwei andere Entwickler arbeiten an Deinem Projekt, und wir wollen
beide im Auge behalten. Wir können mehr als ein 'Repository' gleichzeitig
beobachten mit:
$ git remote add other git://example.com/some_repo.git
$ git pull other some_branch
Nun haben wir einen 'Branch' vom zweiten 'Repository' eingebunden und wir
haben einfachen Zugriff auf alle 'Branches' von allen 'Repositories':
$ git diff origin/experimentell^ other/some_branch~5
Aber was, wenn wir nur deren Änderungen vergleichen wollen, ohne unsere
eigene Arbeit zu beeinflussen? Mit anderen Worten, wir wollen ihre
'Branches' untersuchen, ohne dass deren Änderungen in unser
Arbeitsverzeichnis einfließen. Anstatt 'pull' benutzt Du dann:
$ git fetch # Fetch vom origin, der Standard.
$ git fetch other # Fetch vom zweiten Programmierer.
Dies holt lediglich die Chroniken. Obwohl das Arbeitsverzeichnis unverändert
bleibt, können wir nun jeden 'Branch' aus jedem 'Repository' in einer Git
Anweisung referenzieren, da wir eine lokale Kopie besitzen.
Erinnere Dich, dass ein 'Pull' hinter den Kulissen einfach ein *fetch*
gefolgt von einem *merge* ist. Normalerweise machen wir einen *pull*, weil
wir die letzten 'Commits' abrufen und einbinden wollen. Die beschriebene
Situation ist eine erwähnenswerte Ausnahme.
Siehe *git help remote*, um zu sehen, wie man Remote-'Repositories' entfernt,
bestimmte 'Branches' ignoriert und mehr.
=== Meine Einstellungen ===
Für meine Projekte bevorzuge ich es, wenn Unterstützer 'Repositories'
vorbereiten, von denen ich 'pullen' kann. Verschiedene Git Hosting Anbieter
lassen Dich mit einem Klick deine eigene 'Fork' eines Projekts hosten.
Nachdem ich einen Zweig abgerufen habe, benutze ich Git Anweisungen, um durch
die Änderungen zu navigieren und zu untersuchen, die idealerweise gut
organisiert und dokumentiert sind. Ich 'merge' meine eigenen Änderungen und
führe eventuell weitere Änderungen durch. Wenn ich zufrieden bin, 'pushe'
ich in das zentrale 'Repository'.
Obwohl ich nur unregelmäßig Beiträge erhalte, glaube ich, dass diese Methode
sich auszahlt. Siehe
http://torvalds-family.blogspot.com/2009/06/happiness-is-warm-scm.html[diesen
Blog Beitrag von Linus Torvalds (englisch)].
In der Git Welt zu bleiben, ist etwas bequemer als 'Patch'-Dateien, denn es
erspart mir, sie in Git 'Commits' zu konvertieren. Außerdem kümmert sich Git
um die Details wie Autorname und eMail-Adresse, genauso wie um Datum und
Uhrzeit und es fordert den Autor zum Beschreiben seiner eigenen Änderungen
auf.
|