Entwicklung/Git: Unterschied zwischen den Versionen

Aus Opencaching-Wiki
Zur Navigation springen Zur Suche springen
KKeine Bearbeitungszusammenfassung
 
(17 dazwischenliegende Versionen von 7 Benutzern werden nicht angezeigt)
Zeile 4: Zeile 4:
Die Verwendung von Git setzt eine gewisse Lernkurve voraus. Diese Anleitung soll dir den Einstieg erleichtern und erklärt alles, was du für den Git-Einsatz bei Opencaching.de wissen musst (und Einiges mehr). Sie erklärt die Verwendung von Git anhand der Kommandozeilenversion, die für alle relevanten Betriebssysteme erhältlich ist. Daneben gibt es verschiedene komfortable Benutzeroberflächen. Gerne kannst du ein weiteres Kapitel für die von dir bevorzugte Git-UI hinzufügen!
Die Verwendung von Git setzt eine gewisse Lernkurve voraus. Diese Anleitung soll dir den Einstieg erleichtern und erklärt alles, was du für den Git-Einsatz bei Opencaching.de wissen musst (und Einiges mehr). Sie erklärt die Verwendung von Git anhand der Kommandozeilenversion, die für alle relevanten Betriebssysteme erhältlich ist. Daneben gibt es verschiedene komfortable Benutzeroberflächen. Gerne kannst du ein weiteres Kapitel für die von dir bevorzugte Git-UI hinzufügen!


Allgemeine Einführungen in Git findest du z.B. hier (Liste gerne ergänzen):  
Allgemeine Einführungen in Git findest du z.B. hier (Liste gerne ergänzen):
* http://gitref.org/index.html - eine leichtverständliche Einführung
* https://rogerdudler.github.io/git-guide/index.de.html - Der einfache Einstieg (deutsch)
* http://www.spheredev.org/wiki/Git_for_the_lazy - eine Kurzeinführung
* https://docs.github.com/de - eine leichtverständliche Einführung
* http://git-scm.com/documentation - offizielle Dokumentation
* https://www.stefanimhoff.de/git/ - Sammlung von einfachen und komplexeren Tutorials (englisch)
* https://git-scm.com/documentation - offizielle Dokumentation


== Installation ==
== Installation ==
Zeile 13: Zeile 14:
Git-Download
Git-Download


... für Windows: http://code.google.com/p/msysgit/downloads/list?q=full+installer+official+git<br>
* ... für Linux: <code>sudo apt install git</code>
... für Mac: http://code.google.com/p/git-osx-installer/
* ... für Mac: https://git-scm.com/download/mac
* ... für Windows: https://git-scm.com/download/win
 
Installation per Installationsprogramm und Standardeinstellungen. Zur Installation in der Entwickler-VM siehe [[Entwicklung/Entwicklersystem|Entwicklersystem]].
Installation per Installationsprogramm und Standardeinstellungen. Zur Installation in der Entwickler-VM siehe [[Entwicklung/Entwicklersystem|Entwicklersystem]].


Zeile 22: Zeile 25:
Diese Information wird später - für jeden einsehbar - zusammen mit jedem Codebeitrag (''commit'') von dir gespeichert. Verwende eine Emailadresse, die veröffentlicht werden darf, und ggf. einen Nickname. Diese Daten werden in der Datei <code>.gitconfig</code> in deinem Benutzerverzeichnis abgelegt.
Diese Information wird später - für jeden einsehbar - zusammen mit jedem Codebeitrag (''commit'') von dir gespeichert. Verwende eine Emailadresse, die veröffentlicht werden darf, und ggf. einen Nickname. Diese Daten werden in der Datei <code>.gitconfig</code> in deinem Benutzerverzeichnis abgelegt.


== Funktionsweise von Git und Einsatz bei OC.de ==
== Funktionsweise von Git und Einsatz bei Opencaching.de ==
   
   
Git arbeitet im Gegensatz zu Subversion ''dezentral''. Jeder Entwickler hat eine eigene Kopie - einen "Klon" - des Repositories, also der Datenbank in der sich alle Dateien des Projekts in allen Branches und Versionsständen befinden. Aus diesem Klon werden die Arbeitsdaten ausgecheckt, und Änderungen der Arbeitsdaten werden dort eingecheckt.
Git arbeitet im Gegensatz zu Subversion ''dezentral''. Jeder Entwickler hat eine eigene Kopie - einen "Klon" - des Repositories, also der Datenbank in der sich alle Dateien des Projekts in allen Branches und Versionsständen befinden. Aus diesem Klon werden die Arbeitsdaten ausgecheckt, und Änderungen der Arbeitsdaten werden dort eingecheckt.


Die Entwickler können in beliebigen Topologien organisiert werden und gleichen den Inhalt ihrer Repositories wechselseitig miteinander ab. Opencaching.de verwendet eine Art Sternstruktur, mit einem Haupt-Repository unter der Adresse  
Die Entwickler können in beliebigen Topologien organisiert werden und gleichen den Inhalt ihrer Repositories wechselseitig miteinander ab. Opencaching.de verwendet eine Art Sternstruktur, mit einem Haupt-Repository unter der Adresse  
* http://github.com/OpencachingDeutschland/oc-server3
* https://github.com/OpencachingDeutschland/oc-server3
   
   
Auf dieses Repo hat nur der Entwicklungsleiter Schreibzugriff; alle anderen können nur lesen. Um auch Daten hochladen zu können, besitzt jeder Entwickler bei Github.com eine eigene Kopie - einen "Fork" - des Haupt-Repositories, z.B.  
Auf dieses Repo haben nur der Code Maintainer und seine Vertreter Schreibzugriff; alle anderen können nur lesen. Um auch Daten hochladen zu können, besitzt jeder Entwickler bei GitHub.com eine eigene Kopie - einen "Fork" - des Haupt-Repositories, z.B.  
* http://github.com/flopp/oc-server3
* https://github.com/flopp/oc-server3
   
   
Dein erster Schritt als Opencaching-Entwickler ist das Anlegen deines Forks. Dazu legst du dir auf [http://github.com Github] einen kostenlosen Account an, gehst auf http://github.com/OpencachingDeutschland/oc-server3 und klickst oben rechts auf "Fork".
Dein erster Schritt als Opencaching-Entwickler ist das Anlegen deines Forks. Dazu legst du dir auf [https://github.com GitHub] einen kostenlosen Account an, gehst auf https://github.com/OpencachingDeutschland/oc-server3 und klickst oben rechts auf "Fork".


Der zweite Schritt ist, dir eine lokale Kopie - einen "Klon" - deines Forks anzulegen. Wie du das im OC.de-Entwicklersystem machst, ist im Artikel [[Entwicklung/Entwicklersystem|Entwicklersystem]] beschrieben. Hier machen wir es einfach mal testweise - du kannst so viele Klone anlegen wie du möchtest, den Github-Repositories ist das egal:
Der zweite Schritt ist, dir eine lokale Kopie - einen "Klon" - deines Forks anzulegen. Wie du das im OC.de-Entwicklersystem machst, ist im Artikel [[Entwicklung/Entwicklersystem|Entwicklersystem]] beschrieben. Hier machen wir es einfach mal testweise - du kannst so viele Klone anlegen wie du möchtest, den GitHub-Repositories ist das egal:
  git clone git://github.com/&lt;DeinBenutzername&gt;/oc-server3
  git clone git@github.com:&lt;DeinBenutzername&gt;/oc-server3


Nun wird bei dir ein Verzeichnis <code>oc-server3/.git</code> angelegt, das zunächst eine 1:1-Kopie deines Github-Forks ist (der zunächst eine 1:1-Kopie des Opencaching-Deutschland-Repos ist), und von dort der komplette aktuelle OC.de-Code in Unterverzeichnisse von <code>oc-server3</code> ausgecheckt. In <code>oc-server3</code> befinden sich also sowohl deine Arbeitsdaten als auch der lokale Repository-Klon. <code>oc-server3/.git/config</code> ist die Konfigurationsdatei des lokalen Repositories, die du aber nur selten von Hand bearbeiten wirst.
Nun wird bei dir ein Verzeichnis <code>oc-server3/.git</code> angelegt, das zunächst eine 1:1-Kopie deines GitHub-Forks ist (der zunächst eine 1:1-Kopie des Opencaching-Deutschland-Repos ist), und von dort der komplette aktuelle OC.de-Code in Unterverzeichnisse von <code>oc-server3</code> ausgecheckt. In <code>oc-server3</code> befinden sich also sowohl deine Arbeitsdaten als auch der lokale Repository-Klon. <code>oc-server3/.git/config</code> ist die Konfigurationsdatei des lokalen Repositories, die du aber nur selten von Hand bearbeiten wirst.


Dein Github-Fork heißt in deinem lokalen Repository ''origin''; über diesen Name kannst du mit verschiedenen Git-Kommandos darauf zugreifen. Um die Konfiguration abzuschließen, muss zusätzlich noch der ''upstream'' definiert werden - das Repository, aus dem du neue Daten abrufst. Dies ist nicht dein eigener Fork, sondern du beziehst die Daten direkt von OpencachingDeutschland:
Dein GitHub-Fork heißt in deinem lokalen Repository ''origin''; über diesen Name kannst du mit verschiedenen Git-Kommandos darauf zugreifen. Um die Konfiguration abzuschließen, muss zusätzlich noch der ''upstream'' definiert werden - das Repository, aus dem du neue Daten abrufst. Dies ist nicht dein eigener Fork, sondern du beziehst die Daten direkt von OpencachingDeutschland. Navigiere dazu ins Verzeichnis <code>oc-server3</code> und führe dann folgenden Befehl aus:
  git remote add upstream http://github.com/OpencachingDeutschland/oc-server3
 
  git remote add upstream git@github.com:OpencachingDeutschland/oc-server3


Mit <code>git remote -v</code> kannst du dir nun alle "remote"-Repositories anzeigen lassen, die in deinem Klon eingestellt sind.
Mit <code>git remote -v</code> kannst du dir nun alle "remote"-Repositories anzeigen lassen, die in deinem Klon eingestellt sind.
Zeile 48: Zeile 52:
Die folgende Grafik zeigt den Git-Datenfluss im Opencaching-Team am Beispiel von drei Entwicklern. Oben siehst du die "remote"-Repositories - das für alle Entwickler als "upstream" dienende Haupt-Repo und die drei "origin" genannten Forks -, und unten die drei lokalen Repositories und die Arbeitsdaten. Die grauen Pfeile zeigen, was du eben gemacht hast: 1. den Fork auf Github.com, und 2. das Erzeugen des lokalen Klons (nicht erschrecken lassen durch die vielen Details - das wird unten alles schrittweise erklärt):
Die folgende Grafik zeigt den Git-Datenfluss im Opencaching-Team am Beispiel von drei Entwicklern. Oben siehst du die "remote"-Repositories - das für alle Entwickler als "upstream" dienende Haupt-Repo und die drei "origin" genannten Forks -, und unten die drei lokalen Repositories und die Arbeitsdaten. Die grauen Pfeile zeigen, was du eben gemacht hast: 1. den Fork auf Github.com, und 2. das Erzeugen des lokalen Klons (nicht erschrecken lassen durch die vielen Details - das wird unten alles schrittweise erklärt):


''(TODO: Grafik defekt, muss neu hochgeladen werden)''
[[Datei:Git-Workflow.png|800px]]


Die schwarzen Pfeile zeigen, wie ''ab sofort'' die Daten fließen werden: In umgekehrter Richtung! Du beziehst Daten vom ''upstream'', schiebst deine eigenen Änderungen in deinen ''origin'', und von dort übernimmt der Entwicklungsleiter sie wiederum in den ''upstream''. Aus Sicht jedes Entwicklers fließen die Daten also zwischen drei Repositories im Kreis.
Die schwarzen Pfeile zeigen, wie ''ab sofort'' die Daten fließen werden: In umgekehrter Richtung! Du beziehst Daten vom ''upstream'', schiebst deine eigenen Änderungen in deinen ''origin'', und von dort übernimmt der Code Maintainer sie wiederum in den ''upstream''. Aus Sicht jedes Entwicklers fließen die Daten also zwischen drei Repositories im Kreis.


Links und in der Mitte ist der Standard-Git-Workflow zu sehen, rechts ein vereinfachter mit nur einem Branch.
Links und in der Mitte ist der Standard-Git-Workflow zu sehen, rechts ein vereinfachter mit nur einem Branch.
Zeile 56: Zeile 60:
== Daten bearbeiten und hochladen ==
== Daten bearbeiten und hochladen ==
   
   
Nach dem ersten Auschecken ist der ''master''-Branch aktiv. Dieser enthält den aktuellen Entwicklungsstand. Welcher Branch aktiv ist, siehst du mit
Nach dem ersten Auschecken ist der ''development''-Branch aktiv. Dieser enthält den aktuellen Entwicklungsstand. Welcher Branch aktiv ist, siehst du mit
  <code>git branch</code>
  git branch
Unser Standard-Workflow sieht vor, dass '''nie im Master gearbeitet wird'''. Stattdessen musst du dir - ausgehend von ''master'' - für jede Aufgabe einen Arbeitsbranch anlegen:
Unser Standard-Workflow sieht vor, dass '''nie im development gearbeitet wird'''. Stattdessen musst du dir - ausgehend von ''development'' - für jede Aufgabe einen Arbeitsbranch anlegen:
  <code>git checkout -b 1234-new-feature master</code>
  git checkout -b 1234-new-feature development
Die vorangestellte Nummer ist eine Ticketnummer aus der Todo-Liste. Wenn es keine passende gibt, lässt du sie weg. Verwende nach Möglichkeit englische Namen und Kommentare, denn das OC-Projekt ist international vernetzt. Nun kannst du mit <code>git branch</code> sehen, dass es in deinem lokalen Repo zwei Branches gibt, und der neu angelegte ist aktiv. Mit dem Kommando <code>git checkout Branchname</code> kannst du zwischen den Branches hin- und herwechseln; dabei wird jeweils der Code in den Arbeitsdaten entsprechend ausgetauscht.
Die vorangestellte Nummer ist eine Ticketnummer aus der Todo-Liste. Wenn es keine passende gibt, lässt du sie weg. Verwende nach Möglichkeit englische Namen und Kommentare, denn das OC-Projekt ist international vernetzt. Nun kannst du mit <code>git branch</code> sehen, dass es in deinem lokalen Repo zwei Branches gibt, und der neu angelegte ist aktiv. Mit dem Kommando <code>git checkout Branchname</code> kannst du zwischen den Branches hin- und herwechseln; dabei wird jeweils der Code in den Arbeitsdaten entsprechend ausgetauscht.


Beim Anlegen des Branches sind wir davon ausgegangen, das unmittelbar zuvor der Klon angelegt wurde und die lokale master-Kopie aktuell ist. Wenn Letzteres evtl. nicht der Fall ist, solltest du sie vor dem Anlegen des neuen Branches aktualisieren:
Beim Anlegen des Branches sind wir davon ausgegangen, das unmittelbar zuvor der Klon angelegt wurde und die lokale development-Kopie aktuell ist. Wenn Letzteres evtl. nicht der Fall ist, solltest du sie vor dem Anlegen des neuen Branches aktualisieren:
  git checkout master
  git checkout development
  git pull upstream
  git pull upstream
  git checkout -b 1234-new-feature [master]  
  git checkout -b 1234-new-feature [development]  


Nun ist es soweit: Du kannst deine ersten Änderungen am OC-Code vornehmen und hochladen! Zum Bearbeiten musst du einen UTF8-fähigen Editor verwenden. Dass er das ist, erkennst du an den zwei japanischen Sonderzeichen oben in jeder Quelltextdatei: Wenn dort zwei Fragezeichen, Klötzchen oder Ähnliches erscheinen, ist dein Editor falsch eingestellt oder ungeeignet. Zum Thema Editoren/IDEs siehe auch im Forum: "[http://forum.geocaching-network.com/index.php?topic=2150.0 Git-UI / PHP-IDE]"
Nun ist es soweit: Du kannst deine ersten Änderungen am OC-Code vornehmen und hochladen! Zum Bearbeiten musst du einen UTF8-fähigen Editor verwenden. Dass er das ist, erkennst du an den zwei japanischen Sonderzeichen oben in jeder Quelltextdatei: Wenn dort zwei Fragezeichen, Klötzchen oder Ähnliches erscheinen, ist dein Editor falsch eingestellt oder ungeeignet. Zum Thema Editoren/IDEs siehe auch im Forum: "[http://forum.opencaching.de/index.php?topic=2150.0 Git-UI / PHP-IDE]"


Wenn du die Änderungen vorgenommen hast, zeigt dir
Wenn du die Änderungen vorgenommen hast, zeigt dir
  <code>git status</code>
  git status
in roter Farbe an, welche Dateien geändert oder hinzugefügt wurden, und
in roter Farbe an, welche Dateien geändert oder hinzugefügt wurden, und
  <code>git diff</code>
  git diff
die Änderungen im Einzelnen. Falls dein Editor bzw. deine Eintwicklungsumgebung irgendwelche zusätzlichen Dateien angelegt hat, kannst du diese in <code>.git/info/exclude</code> eintragen, damit sie nicht ins Repository gelangen.
die Änderungen im Einzelnen. Falls dein Editor bzw. deine Entwicklungsumgebung irgendwelche zusätzlichen Dateien angelegt hat, kannst du diese in <code>.git/info/exclude</code> eintragen, damit sie nicht ins Repository gelangen.


Als nächstes musst du Git mitteilen, dass die Daten zum aktiven Branch hinzugefügt werden sollen; dies geschieht mit
Als nächstes musst du Git mitteilen, dass die Daten zum aktiven Branch hinzugefügt werden sollen; dies geschieht mit
  <code>git add .</code>
  git add .
für alle geänderten und neuen Dateien im aktuellen Verzeichnisbaum (falls du Branches gewechselt hast vergewissere dich evtl. mit <code>git branch</code>, dass du im richtigen bist!) Wahlweise kannst du einzelne Dateien per (Pfad+)Dateiname hinzufügen oder Wildcards verwenden. Dateien löschen kann man mit
für alle geänderten und neuen Dateien im aktuellen Verzeichnisbaum (falls du Branches gewechselt hast vergewissere dich evtl. mit <code>git branch</code>, dass du im richtigen bist!) Wahlweise kannst du einzelne Dateien per (Pfad+)Dateiname hinzufügen oder Wildcards verwenden. Dateien löschen kann man mit
  <code>git rm Dateiname</code>
  git rm Dateiname
Nun zeigt <code>git status</code> in grüner Farbe alle vorbereiteten Änderungen an, und mit
Nun zeigt <code>git status</code> in grüner Farbe alle vorbereiteten Änderungen an, und mit
  <code>git commit</code>
  git commit
checkst du sie in dein lokales Repository ein. Es öffent sich ein vi-Editor, in dem du einen Kommentar eingeben musst. Schreibe eine aussagekräftige, möglichst englische Zusammenfassung in die erste Zeile, und evtl. zusätzliche Erläuterungen in die weiteren Zeilen. Wenn es nur ein einzeiliger Kommentar sein soll, kannst du dir den Editor auch sparen und den Kommentar direkt angeben mit
checkst du sie in dein lokales Repository ein. Es öffent sich ein vi-Editor, in dem du einen Kommentar eingeben musst. Schreibe eine aussagekräftige, möglichst englische Zusammenfassung in die erste Zeile, und evtl. zusätzliche Erläuterungen in die weiteren Zeilen. Wenn es nur ein einzeiliger Kommentar sein soll, kannst du dir den Editor auch sparen und den Kommentar direkt angeben mit
  <code>git commit -m "Kommentar"</code>
  git commit -m "Kommentar"
Wenn keine neuen Dateien hinzugefügt, sondern nur vorhandene geändert werden sollen, kannst du auch das <code>add</code> mit einbauen, also alle geänderten Daten mit nur einem Befehl einchecken:
Wenn keine neuen Dateien hinzugefügt, sondern nur vorhandene geändert werden sollen, kannst du auch das <code>add</code> mit einbauen, also alle geänderten Daten mit nur einem Befehl einchecken:
  <code>git commit -am "Kommentar"</code>
  git commit -am "Kommentar"
Mit
Mit
  <code>git log</code>
  git log
siehst du nun, dass ein neuer ''commit'' in die Versionsgeschichte des aktiven Branches eingefügt wurde. Wahlweise kannst du auch mit <code>git log --stat</code> nochmals alle geänderten Dateien anzeigen lassen.
siehst du nun, dass ein neuer ''commit'' in die Versionsgeschichte des aktiven Branches eingefügt wurde. Wahlweise kannst du auch mit <code>git log --stat</code> nochmals alle geänderten Dateien anzeigen lassen.


Um den Commit mit einem Ticket in der [[Entwicklung/Todo-Liste|Redmine-Todo-Liste]] zu verknüpfen, kannst du im Kommentar das Stichwort "updates #nnn" einfügen, mit #nnn = Redmine-Ticketnummer. Der Commit erscheint dann innerhalb des Tickets, sobald er geprüft und in den ''master''-Branch übernommen wurde.
Um den Commit später mit einem Ticket in der [[Entwicklung/Todo-Liste|Jira]] zu verknüpfen, kannst du im Kommentar die Ticket Nummer (inklusive Projekt Kürzel) angeben. Aktuell übernimmt es das jedoch nur für Pull Requests. Dort sollte die Ticket Nummer am Anfang stehen.


==== Exkurs: commits ====
==== Exkurs: Commits ====
   
   
Commits sind das Hauptelement der Arbeit mit Git. Jeder Branch ist eine bestimmte Abfolge von Commits. Verschiedene Branches unterscheiden sich dadurch, welche Commits sie enthalten. Ein Commit ist ein Patch, der eine oder mehrere Dateien verändert, hinzufügt und/oder löscht. Jeder Commit hat einen eindeutigen Hashcode, der im Log angezeigt wird. Über diesen Code lassen sich Commits einzeln herauspicken, rückgängig machen, als Diff anzeigen etc. Dabei genügt die Angabe der ersten paar Zeichen, sofern sie eindeutig sind; üblich als Kurzform sind die ersten 7-10 Zeichen.
Commits sind das Hauptelement der Arbeit mit Git. Jeder Branch ist eine bestimmte Abfolge von Commits. Verschiedene Branches unterscheiden sich dadurch, welche Commits sie enthalten. Ein Commit ist ein Patch, der eine oder mehrere Dateien verändert, hinzufügt und/oder löscht. Jeder Commit hat einen eindeutigen Hashcode, der im Log angezeigt wird. Über diesen Code lassen sich Commits einzeln herauspicken, rückgängig machen, als Diff anzeigen etc. Dabei genügt die Angabe der ersten paar Zeichen, sofern sie eindeutig sind; üblich als Kurzform sind die ersten 7-10 Zeichen.


Der letzte (neueste) Commit des aktiven Branches hat auch den Name HEAD, der vorletzte HEAD~1, der drittletzte HEAD~2 etc. Mit
Der letzte (neueste) Commit des aktiven Branches hat auch den Name HEAD, der vorletzte HEAD~1, der drittletzte HEAD~2 etc. Mit
  <code>git diff HEAD~1</code>
  git diff HEAD~1
kannst du dir z.B. alle Änderungen zwischen aktuellem und vorletztem Codestand anzeigen lassen - also genau das, was du mit deinem letzten <code>commit</code> eingecheckt hast.
kannst du dir z.B. alle Änderungen zwischen aktuellem und vorletztem Codestand anzeigen lassen - also genau das, was du mit deinem letzten <code>commit</code> eingecheckt hast.


Zeile 105: Zeile 109:
Zunächst solltest du deine Daten nochmal auf den aktuellen Stand bringen. Damit ist sichergestellt, dass deine Änderungen mit dem aktuellsten OC-Code funktionieren:
Zunächst solltest du deine Daten nochmal auf den aktuellen Stand bringen. Damit ist sichergestellt, dass deine Änderungen mit dem aktuellsten OC-Code funktionieren:
  git fetch upstream
  git fetch upstream
  git rebase upstream/master
  git rebase upstream/development


Das erste Kommando aktualisiert deine lokale Kopie der Upstream-Branches (die du mit <code>git branch -r</code> auflisten kannst), bzw. legt diese erstmalig an. Das zweite übernimmt alle neuen ''commits'' aus dem Upstream - also dem OC-Hauptrepository - in deinen aktiven Branch, und zwar fügt es sie ''vor'' deine eigenen Änderungen ein! Deine Änderungen werden auf Basis des aktuellen OC-Codestandes neu aufgesetzt (re-based), d.h. sie werden als Patch auf diesen Codestand angewandt. Beide Kommandos lassen sich auch zu einem zusammenfassen:
Das erste Kommando aktualisiert deine lokale Kopie der Upstream-Branches (die du mit <code>git branch -r</code> auflisten kannst), bzw. legt diese erstmalig an. Das zweite übernimmt alle neuen ''commits'' aus dem Upstream - also dem OC-Hauptrepository - in deinen aktiven Branch, und zwar fügt es sie ''vor'' deine eigenen Änderungen ein! Deine Änderungen werden auf Basis des aktuellen OC-Codestandes neu aufgesetzt (re-based), d.h. sie werden als Patch auf diesen Codestand angewandt. Beide Kommandos lassen sich auch zu einem zusammenfassen:
  git pull --rebase upstream master
  git pull --rebase upstream development


'''Verwende niemals ein einfaches <code>git pull</code> (ohne <code>--rebase</code>) in einem Arbeitsbranch!''' Es würde die Versionsgeschichte unlesbar machen und das Zurückverfolgen von Codeänderungen verhindern.
'''Verwende niemals ein einfaches <code>git pull</code> (ohne <code>--rebase</code>) in einem Arbeitsbranch!''' Es würde die Versionsgeschichte unlesbar machen und das Zurückverfolgen von Codeänderungen verhindern.
Zeile 118: Zeile 122:
Nun kannst du deinen neuen Branch mit
Nun kannst du deinen neuen Branch mit
  <code>git push origin 1234-new-feature</code>  
  <code>git push origin 1234-new-feature</code>  
in deinen Fork hochladen. Wenn du auf [http://github.com/ http://github.com/<DeinUsername>/oc-server3] links die Branch-Dropdown-Box aufklappst, oder weiter rechts auf "branches" klickst, sollte dort der neue Branch auftauchen (manchmal mit etwas Verzögerung). Wenn du oben auf "Network" klickst, siehst du wie dein neuer Branch vom master abzweigt. Jeder Punkt in diesem Diagramm steht für einen ''commit''.
in deinen Fork hochladen. Wenn du auf [http://github.com/ http://github.com/<DeinUsername>/oc-server3] links die Branch-Dropdown-Box aufklappst, oder weiter rechts auf "branches" klickst, sollte dort der neue Branch auftauchen (manchmal mit etwas Verzögerung). Wenn du oben auf "Network" klickst, siehst du wie dein neuer Branch vom development abzweigt. Jeder Punkt in diesem Diagramm steht für einen ''commit''.


Wenn dein Branch fertig ist und in den master übernommen werden soll, wählst du ihn aus der Branches-Liste aus und klickst oben auf "Pull Request"; hier kannst du noch einen zusätzlichen Kommentar angeben. Der Entwicklungsleiter wird per E-Mail informiert und wird deinen Code prüfen und ggf. übernehmen.
Wenn dein Branch fertig ist und in den development übernommen werden soll, wählst du ihn aus der Branches-Liste aus und klickst oben auf "Pull Request"; hier kannst du noch einen zusätzlichen Kommentar angeben. Der Code Maintainer wird per E-Mail informiert und wird deinen Code prüfen und ggf. übernehmen.


In diesem Fall war es wahrscheinlich nur ein Test, daher kannst du den Branch nun mit
In diesem Fall war es wahrscheinlich nur ein Test, daher kannst du den Branch nun mit
  git push origin :1234-new-feature
  git push origin :1234-new-feature
wieder aus deinem Fork löschen. Wenn du ihn auch lokal wieder löschen willst, geht das mit
wieder aus deinem Fork löschen. Wenn du ihn auch lokal wieder löschen willst, geht das mit
  git checkout master
  git checkout development
  git branch -D 1234-new-feature  
  git branch -D 1234-new-feature  


Das große <code>-D</code> ermöglicht es, einen Branch zu verwerfen, der nicht weiterverwendet wurde. Wenn du stattdessen <code>-d</code> angibst, sind nur Branches löschbar die bereits in einen anderen Branch (z.B. den master) übernommen wurden, wo durch die Löschung also keine Daten verloren gehen können. '''Im Zweifelsfall verwende immer -d'''; dabei kann nichts versehentlich verloren gehen.
Das große <code>-D</code> ermöglicht es, einen Branch zu verwerfen, der nicht weiterverwendet wurde. Wenn du stattdessen <code>-d</code> angibst, sind nur Branches löschbar die bereits in einen anderen Branch (z.B. den development) übernommen wurden, wo durch die Löschung also keine Daten verloren gehen können. '''Im Zweifelsfall verwende immer -d'''; dabei kann nichts versehentlich verloren gehen.


==== Zusammenfassung des OC-Git-Standard-Workflow ====
==== Zusammenfassung des OC-Git-Standard-Workflow ====
   
   
Neuen Branch für eine neue Aufgabe anlegen:
* Neuen Branch für eine neue Aufgabe anlegen
 
*# <code>git checkout development</code>
1. <code>git checkout master</code><br/>
*# <code>git pull upstream</code>
2. <code>git pull upstream</code><br/>
*# <code>git checkout -b 1234-new-feature</code>
3. <code>git checkout -b 1234-new-feature</code>
*: ... oder die Arbeit an einem bereits bestehenden Branch mit <code>git checkout 1234-new-feature</code> fortsetzen
... oder die Arbeit an einem bereits bestehenden Branch mit <code>git checkout 1234-new-feature</code> fortsetzen
* Programmierzyklen
 
*# Code schreiben
Programmierzyklen:
*# mit <code>git status</code> / <code>git diff</code> lokale Änderungen kontrollieren
 
*# Änderung mit <code>git add</code> / <code>git commit</code> ins lokale Repo einchecken
4. Code schreiben<br />
*# mit <code>git pull --rebase upstream development</code> auf aktuellen OC-Code aufsetzen
5. mit <code>git status</code> / <code>git diff</code> lokale Änderungen kontrollieren<br />
*# weiter bei 1, wenn der Code noch nicht fertig ist
6. Änderung mit <code>git add</code> / <code>git commit</code> ins lokale Repo einchecken<br />
* Hochladen
7. mit <code>git pull --rebase upstream master</code> auf aktuellen OC-Code aufsetzen<br />
*# <code>git push origin 1234-neues-Feature</code>
8. weiter bei 4, wenn der Code noch nicht fertig ist
*# ''Branch 1234-neues-Feature'' auf GitHub aufrufen und Pull Request starten
 
* Nicht mehr benötigte Branches löschen
Hochladen:
*# lokal: <code>git checkout development</code> / <code>git branch -d 1234-neues-Feature</code>
 
*# auf dem Fork: <code>git push origin :1234-neues-Feature</code>
9. <code>git push origin 1234-neues-Feature</code></code><br />
10. ''Branch 1234-neues-Feature'' im Github aufrufen und Pull Request starten
 
Nicht mehr benötigte Branches löschen:
 
11. lokal: <code>git checkout master</code> / <code>git branch -d 1234-neues-Feature</code><br />
12. auf dem Fork: <code>git push origin :1234-neues-Feature</code>  


==== Commits zusammenfassen ====
==== Commits zusammenfassen ====
Zeile 168: Zeile 165:
   
   
Wenn du selbst gerade nichts programmieren willst, sondern dir einfach nur ein Update vom OC-Server holen und anschauen, machst du
Wenn du selbst gerade nichts programmieren willst, sondern dir einfach nur ein Update vom OC-Server holen und anschauen, machst du
  git checkout master
  git checkout development
  git pull upstream  
  git pull upstream  
Wenn du mehrere Branches mit eigenen Änderungen angelegt hast, und diese alle im Zusammenhang testen möchtest, kannst du dir dafür einen Testbranch anlegen:
Wenn du mehrere Branches mit eigenen Änderungen angelegt hast, und diese alle im Zusammenhang testen möchtest, kannst du dir dafür einen Testbranch anlegen:
  git checkout -b test master
  git checkout -b test development
  git merge 1234-new-feature
  git merge 1234-new-feature
  git merge 2345-my-bugfix
  git merge 2345-my-bugfix
Zeile 190: Zeile 187:
* <code>git revert commit-ID</code>
* <code>git revert commit-ID</code>
* <code>git push</code>
* <code>git push</code>
* evt. Pull-Request auf dem Github, wenn es bereits im Upstream angekommen war
* evt. Pull-Request auf dem GitHub, wenn es bereits im Upstream angekommen war
   
   
Den Kommentar des letzten, noch nicht "gepushten" Commit korrigieren:  
Den Kommentar des letzten, noch nicht "gepushten" Commit korrigieren:  
Zeile 198: Zeile 195:
   
   
Wenn du z.B. den Branch ''1234-new-feature'' von Entwickler ''heinz'' testen möchtest, kannst du ihn in einen Testbranch bei dir herunterladen. Zunächst musst du ''heinz''' Fork einmalig als weitere Upstream definieren:
Wenn du z.B. den Branch ''1234-new-feature'' von Entwickler ''heinz'' testen möchtest, kannst du ihn in einen Testbranch bei dir herunterladen. Zunächst musst du ''heinz''' Fork einmalig als weitere Upstream definieren:
  git remote add heinz http://github.com/heinz/oc-server3
  git remote add heinz git@github.com:heinz/oc-server3
Dann legst du bei dir einen Testbranch an, am besten auf Basis aktuellster Daten ...
Dann legst du bei dir einen Testbranch an, am besten auf Basis aktuellster Daten ...
  git checkout master
  git checkout development
  git pull upstream
  git pull upstream
  git checkout -b tolles-heinz-feature  
  git checkout -b tolles-heinz-feature  
Zeile 208: Zeile 205:
== Der stable-Branch ==
== Der stable-Branch ==
   
   
Neben dem Master gibt es im OC-Repository einen Branch "stable". Dieser enthält immer den gleichen Stand wie das Produktivsystem www.opencaching.de. Neue Features werden im Master entwickelt und getestet und später über den Stable-Branch freigegeben.
Neben dem development gibt es im OC-Repository einen Branch "stable". Dieser enthält immer den gleichen Stand wie das Produktivsystem www.opencaching.de. Neue Features werden im development entwickelt und getestet und später über den Stable-Branch freigegeben.


Mit dem Stable-Branch wirst du nur dann zu tun haben, wenn du einen "Hotfix" schreibst - eine dringende Korrektur, die sofort freigegeben werden soll. Diese setzt du auf dem Stable statt dem Master auf; der übrige Workflow ist der gleiche wie oben beschrieben.
Mit dem Stable-Branch wirst du nur dann zu tun haben, wenn du einen "Hotfix" schreibst - eine dringende Korrektur, die sofort freigegeben werden soll. Diese setzt du auf dem Stable statt dem development auf; der übrige Workflow ist der gleiche wie oben beschrieben.


== Vereinfachter Workflow ==
== Vereinfachter Workflow ==
   
   
Der oben beschriebene Workflow ist Pflicht für alle Entwickler, die Code zu OC.de beitragen. Wer nur hin und wieder mal eine Grafik oder einen Text beisteuert, kann ausnahmsweise auch ohne separate Branches arbeiten. In diesem Fall ist ein '''einfaches <code>git pull</code> im Master-Branch verboten'''! Stattdessen muss überall, wo oben <code>git pull upstream</code> steht, stattdessen
Der oben beschriebene Workflow ist Pflicht für alle Entwickler, die Code zu OC.de beitragen. Wer nur hin und wieder mal eine Grafik oder einen Text beisteuert, kann ausnahmsweise auch ohne separate Branches arbeiten. In diesem Fall ist ein '''einfaches <code>git pull</code> im development-Branch verboten'''! Stattdessen muss überall, wo oben <code>git pull upstream</code> steht, stattdessen
  <code>git pull --rebase upstream master</code>  
  <code>git pull --rebase upstream development</code>  
verwendet werden! Der vereinfachte Ablauf ist dann:
verwendet werden! Der vereinfachte Ablauf ist dann:


Zeile 221: Zeile 218:
2. mit <code>git status</code> / <code>git diff</code> lokale Änderungen kontrollieren<br>
2. mit <code>git status</code> / <code>git diff</code> lokale Änderungen kontrollieren<br>
3. Änderung mit <code>git add</code> / <code>git commit</code> ins lokale Repo einchecken<br>
3. Änderung mit <code>git add</code> / <code>git commit</code> ins lokale Repo einchecken<br>
4. mit <code>git pull --rebase upstream master</code> auf aktuellen OC-Code aufsetzen<br>
4. mit <code>git pull --rebase upstream development</code> auf aktuellen OC-Code aufsetzen<br>
5. weiter bei 1, wenn der Code noch nicht fertig ist<br>
5. weiter bei 1, wenn der Code noch nicht fertig ist<br>
6. git push origin<br>
6. <code>git push origin</code><br>
7. Pull-Request
7. Pull-Request


== Noch ein paar Gimmicks ==
== Noch ein paar Gimmicks ==
<code>git diff Branchname</code>  
 
zeigt alle Unterschiede zwischen dem aktuellen Branch und einem anderen an.
* <code>git branch -m 1234-neuestes-Feature</code> Benennt den derzeit aktiven Branch um in "1234-neuestes-Feature".
<code>git cherry-pick Commit-ID</code>  
* <code>git diff Branchname</code> zeigt alle Unterschiede zwischen dem aktuellen Branch und einem anderen an.
übernimmt einen bestimmten Commit (von wo auch immer) in den aktiven Branch.
* <code>git cherry-pick Commit-ID</code> übernimmt einen bestimmten Commit (von wo auch immer) in den aktiven Branch.
<code>git gc</code>  
* <code>git diff --name-only --diff-filter=U</code> zeigt eine Liste aller konfliktbehafteten Dateien nach einem Merge an
führt eine [http://de.wikipedia.org/wiki/Garbage_Collection Garbage Collection] durch und gibt Platz im lokalen Repository frei. Per <code>git reset --hard</code> oder <code>git branch -d</code> gelöschte Commits werden damit endgültig weggeworfen (vorher sind sie via <code>git reflog</code> noch wiederherstellbar).
* <code>git gc</code> führt eine [http://de.wikipedia.org/wiki/Garbage_Collection Garbage Collection] durch und gibt Platz im lokalen Repository frei. Per <code>git reset --hard</code> oder <code>git branch -d</code> gelöschte Commits werden damit endgültig weggeworfen (vorher sind sie via <code>git reflog</code> noch wiederherstellbar).
<code>git grep Suchbegriff</code>  
* <code>git grep Suchbegriff</code> durchsucht den Code des aktuellen Verzeichnisbaums; für zahlreiche Optionen siehe Git-Doku.
durchsucht den Code des aktuellen Verzeichnisbaums; für zahlreiche Optionen siehe Git-Doku.
* <code>git help Kommando</code> zeigt die Doku für ein Git-Kommando an.
<code>git help Kommando</code>  
zeigt die Doku für ein Git-Kommando an.


== Forenbeiträge zu Git ==
== Forenbeiträge zu Git ==
* [http://forum.geocaching-network.com/index.php?topic=2125.0 Git-Workflow]
* [http://forum.opencaching.de/index.php?topic=2125.0 Git-Workflow]


[[Kategorie:Entwicklung|Git]]
[[Kategorie:Entwicklung|Git]]

Aktuelle Version vom 6. Mai 2024, 16:15 Uhr

Versionsverwaltung der Entwicklungsdaten mit Git

Das Opencaching.de-Projekt verwendet Git zur Verwaltung von Quellcode, Dokumentationen etc. Git ist leistungsfähiger und komplexer als klassische Versionsverwaltungstools wie CVS und Subversion. Es kann wesentlich besser mit Branches umgehen, also verschiedenen Codeversionen eines Projekts -- "branches (in Git) are cheap and easy". So kann man zu Testzwecken, zum Programmieren einzelner Features etc. eigene Zweige anlegen, die dann später wieder in den Haupt-Code (den Master-Branch) einfließen oder wahlweise verworfen werden. Dieses Verzweigen und Wieder-Zusammenführen von Codeversionen ist erstaunlich einfach und zuverlässig. Richtig eingesetzt, erleichtert es das Projektmanagement.

Die Verwendung von Git setzt eine gewisse Lernkurve voraus. Diese Anleitung soll dir den Einstieg erleichtern und erklärt alles, was du für den Git-Einsatz bei Opencaching.de wissen musst (und Einiges mehr). Sie erklärt die Verwendung von Git anhand der Kommandozeilenversion, die für alle relevanten Betriebssysteme erhältlich ist. Daneben gibt es verschiedene komfortable Benutzeroberflächen. Gerne kannst du ein weiteres Kapitel für die von dir bevorzugte Git-UI hinzufügen!

Allgemeine Einführungen in Git findest du z.B. hier (Liste gerne ergänzen):

Installation

Git-Download

Installation per Installationsprogramm und Standardeinstellungen. Zur Installation in der Entwickler-VM siehe Entwicklersystem.

Nach der Installation von Git muss du einmalig deinen Name und eine Emailadresse eingeben:

git config --global user.name "Your Name Here"
git config --global user.email "your_email@youremail.com" 

Diese Information wird später - für jeden einsehbar - zusammen mit jedem Codebeitrag (commit) von dir gespeichert. Verwende eine Emailadresse, die veröffentlicht werden darf, und ggf. einen Nickname. Diese Daten werden in der Datei .gitconfig in deinem Benutzerverzeichnis abgelegt.

Funktionsweise von Git und Einsatz bei Opencaching.de

Git arbeitet im Gegensatz zu Subversion dezentral. Jeder Entwickler hat eine eigene Kopie - einen "Klon" - des Repositories, also der Datenbank in der sich alle Dateien des Projekts in allen Branches und Versionsständen befinden. Aus diesem Klon werden die Arbeitsdaten ausgecheckt, und Änderungen der Arbeitsdaten werden dort eingecheckt.

Die Entwickler können in beliebigen Topologien organisiert werden und gleichen den Inhalt ihrer Repositories wechselseitig miteinander ab. Opencaching.de verwendet eine Art Sternstruktur, mit einem Haupt-Repository unter der Adresse

Auf dieses Repo haben nur der Code Maintainer und seine Vertreter Schreibzugriff; alle anderen können nur lesen. Um auch Daten hochladen zu können, besitzt jeder Entwickler bei GitHub.com eine eigene Kopie - einen "Fork" - des Haupt-Repositories, z.B.

Dein erster Schritt als Opencaching-Entwickler ist das Anlegen deines Forks. Dazu legst du dir auf GitHub einen kostenlosen Account an, gehst auf https://github.com/OpencachingDeutschland/oc-server3 und klickst oben rechts auf "Fork".

Der zweite Schritt ist, dir eine lokale Kopie - einen "Klon" - deines Forks anzulegen. Wie du das im OC.de-Entwicklersystem machst, ist im Artikel Entwicklersystem beschrieben. Hier machen wir es einfach mal testweise - du kannst so viele Klone anlegen wie du möchtest, den GitHub-Repositories ist das egal:

git clone git@github.com:<DeinBenutzername>/oc-server3

Nun wird bei dir ein Verzeichnis oc-server3/.git angelegt, das zunächst eine 1:1-Kopie deines GitHub-Forks ist (der zunächst eine 1:1-Kopie des Opencaching-Deutschland-Repos ist), und von dort der komplette aktuelle OC.de-Code in Unterverzeichnisse von oc-server3 ausgecheckt. In oc-server3 befinden sich also sowohl deine Arbeitsdaten als auch der lokale Repository-Klon. oc-server3/.git/config ist die Konfigurationsdatei des lokalen Repositories, die du aber nur selten von Hand bearbeiten wirst.

Dein GitHub-Fork heißt in deinem lokalen Repository origin; über diesen Name kannst du mit verschiedenen Git-Kommandos darauf zugreifen. Um die Konfiguration abzuschließen, muss zusätzlich noch der upstream definiert werden - das Repository, aus dem du neue Daten abrufst. Dies ist nicht dein eigener Fork, sondern du beziehst die Daten direkt von OpencachingDeutschland. Navigiere dazu ins Verzeichnis oc-server3 und führe dann folgenden Befehl aus:

git remote add upstream git@github.com:OpencachingDeutschland/oc-server3

Mit git remote -v kannst du dir nun alle "remote"-Repositories anzeigen lassen, die in deinem Klon eingestellt sind.

Datenfluss

Die folgende Grafik zeigt den Git-Datenfluss im Opencaching-Team am Beispiel von drei Entwicklern. Oben siehst du die "remote"-Repositories - das für alle Entwickler als "upstream" dienende Haupt-Repo und die drei "origin" genannten Forks -, und unten die drei lokalen Repositories und die Arbeitsdaten. Die grauen Pfeile zeigen, was du eben gemacht hast: 1. den Fork auf Github.com, und 2. das Erzeugen des lokalen Klons (nicht erschrecken lassen durch die vielen Details - das wird unten alles schrittweise erklärt):

Die schwarzen Pfeile zeigen, wie ab sofort die Daten fließen werden: In umgekehrter Richtung! Du beziehst Daten vom upstream, schiebst deine eigenen Änderungen in deinen origin, und von dort übernimmt der Code Maintainer sie wiederum in den upstream. Aus Sicht jedes Entwicklers fließen die Daten also zwischen drei Repositories im Kreis.

Links und in der Mitte ist der Standard-Git-Workflow zu sehen, rechts ein vereinfachter mit nur einem Branch.

Daten bearbeiten und hochladen

Nach dem ersten Auschecken ist der development-Branch aktiv. Dieser enthält den aktuellen Entwicklungsstand. Welcher Branch aktiv ist, siehst du mit

git branch

Unser Standard-Workflow sieht vor, dass nie im development gearbeitet wird. Stattdessen musst du dir - ausgehend von development - für jede Aufgabe einen Arbeitsbranch anlegen:

git checkout -b 1234-new-feature development

Die vorangestellte Nummer ist eine Ticketnummer aus der Todo-Liste. Wenn es keine passende gibt, lässt du sie weg. Verwende nach Möglichkeit englische Namen und Kommentare, denn das OC-Projekt ist international vernetzt. Nun kannst du mit git branch sehen, dass es in deinem lokalen Repo zwei Branches gibt, und der neu angelegte ist aktiv. Mit dem Kommando git checkout Branchname kannst du zwischen den Branches hin- und herwechseln; dabei wird jeweils der Code in den Arbeitsdaten entsprechend ausgetauscht.

Beim Anlegen des Branches sind wir davon ausgegangen, das unmittelbar zuvor der Klon angelegt wurde und die lokale development-Kopie aktuell ist. Wenn Letzteres evtl. nicht der Fall ist, solltest du sie vor dem Anlegen des neuen Branches aktualisieren:

git checkout development
git pull upstream
git checkout -b 1234-new-feature [development] 

Nun ist es soweit: Du kannst deine ersten Änderungen am OC-Code vornehmen und hochladen! Zum Bearbeiten musst du einen UTF8-fähigen Editor verwenden. Dass er das ist, erkennst du an den zwei japanischen Sonderzeichen oben in jeder Quelltextdatei: Wenn dort zwei Fragezeichen, Klötzchen oder Ähnliches erscheinen, ist dein Editor falsch eingestellt oder ungeeignet. Zum Thema Editoren/IDEs siehe auch im Forum: "Git-UI / PHP-IDE"

Wenn du die Änderungen vorgenommen hast, zeigt dir

git status

in roter Farbe an, welche Dateien geändert oder hinzugefügt wurden, und

git diff

die Änderungen im Einzelnen. Falls dein Editor bzw. deine Entwicklungsumgebung irgendwelche zusätzlichen Dateien angelegt hat, kannst du diese in .git/info/exclude eintragen, damit sie nicht ins Repository gelangen.

Als nächstes musst du Git mitteilen, dass die Daten zum aktiven Branch hinzugefügt werden sollen; dies geschieht mit

git add .

für alle geänderten und neuen Dateien im aktuellen Verzeichnisbaum (falls du Branches gewechselt hast vergewissere dich evtl. mit git branch, dass du im richtigen bist!) Wahlweise kannst du einzelne Dateien per (Pfad+)Dateiname hinzufügen oder Wildcards verwenden. Dateien löschen kann man mit

git rm Dateiname

Nun zeigt git status in grüner Farbe alle vorbereiteten Änderungen an, und mit

git commit

checkst du sie in dein lokales Repository ein. Es öffent sich ein vi-Editor, in dem du einen Kommentar eingeben musst. Schreibe eine aussagekräftige, möglichst englische Zusammenfassung in die erste Zeile, und evtl. zusätzliche Erläuterungen in die weiteren Zeilen. Wenn es nur ein einzeiliger Kommentar sein soll, kannst du dir den Editor auch sparen und den Kommentar direkt angeben mit

git commit -m "Kommentar"

Wenn keine neuen Dateien hinzugefügt, sondern nur vorhandene geändert werden sollen, kannst du auch das add mit einbauen, also alle geänderten Daten mit nur einem Befehl einchecken:

git commit -am "Kommentar"

Mit

git log

siehst du nun, dass ein neuer commit in die Versionsgeschichte des aktiven Branches eingefügt wurde. Wahlweise kannst du auch mit git log --stat nochmals alle geänderten Dateien anzeigen lassen.

Um den Commit später mit einem Ticket in der Jira zu verknüpfen, kannst du im Kommentar die Ticket Nummer (inklusive Projekt Kürzel) angeben. Aktuell übernimmt es das jedoch nur für Pull Requests. Dort sollte die Ticket Nummer am Anfang stehen.

Exkurs: Commits

Commits sind das Hauptelement der Arbeit mit Git. Jeder Branch ist eine bestimmte Abfolge von Commits. Verschiedene Branches unterscheiden sich dadurch, welche Commits sie enthalten. Ein Commit ist ein Patch, der eine oder mehrere Dateien verändert, hinzufügt und/oder löscht. Jeder Commit hat einen eindeutigen Hashcode, der im Log angezeigt wird. Über diesen Code lassen sich Commits einzeln herauspicken, rückgängig machen, als Diff anzeigen etc. Dabei genügt die Angabe der ersten paar Zeichen, sofern sie eindeutig sind; üblich als Kurzform sind die ersten 7-10 Zeichen.

Der letzte (neueste) Commit des aktiven Branches hat auch den Name HEAD, der vorletzte HEAD~1, der drittletzte HEAD~2 etc. Mit

git diff HEAD~1

kannst du dir z.B. alle Änderungen zwischen aktuellem und vorletztem Codestand anzeigen lassen - also genau das, was du mit deinem letzten commit eingecheckt hast.

Rebase auf aktuellen Codestand

Grundsätzlich solltest du Daten erst dann hochladen, wenn sie verwendbar sind und in das Haupt-Repository oder an einen anderen Entwickler weitergegeben werden sollen. Unfertiges bleibt zunächst nur lokal bei dir liegen. Wir tun jetzt einfach mal so, als sei deine Codeänderung fertig (du kannst den Upload danach wieder löschen, wenn es nur ein Test war).

Zunächst solltest du deine Daten nochmal auf den aktuellen Stand bringen. Damit ist sichergestellt, dass deine Änderungen mit dem aktuellsten OC-Code funktionieren:

git fetch upstream
git rebase upstream/development 

Das erste Kommando aktualisiert deine lokale Kopie der Upstream-Branches (die du mit git branch -r auflisten kannst), bzw. legt diese erstmalig an. Das zweite übernimmt alle neuen commits aus dem Upstream - also dem OC-Hauptrepository - in deinen aktiven Branch, und zwar fügt es sie vor deine eigenen Änderungen ein! Deine Änderungen werden auf Basis des aktuellen OC-Codestandes neu aufgesetzt (re-based), d.h. sie werden als Patch auf diesen Codestand angewandt. Beide Kommandos lassen sich auch zu einem zusammenfassen:

git pull --rebase upstream development

Verwende niemals ein einfaches git pull (ohne --rebase) in einem Arbeitsbranch! Es würde die Versionsgeschichte unlesbar machen und das Zurückverfolgen von Codeänderungen verhindern.

Beim rebase können "Merge-Konflikte" enstehen, wenn deine Codeänderungen nicht automatisch auf dem aktuellen Codestand aufgesetzt werden können, z.B. weil es mehrere Änderungen in der gleichen Codezeile gab. Git zeigt dann eine Fehlermeldung an, und die Konflikte sind in im Quelltext markiert (suche nach "===="). Korrigiere den Code, markiere die geänderte Datei erneut mit git add zum Hinzufügen, und gib git rebase --continue ein, um das Rebase abzuschließen.

Daten hochladen

Nun kannst du deinen neuen Branch mit

git push origin 1234-new-feature 

in deinen Fork hochladen. Wenn du auf http://github.com/<DeinUsername>/oc-server3 links die Branch-Dropdown-Box aufklappst, oder weiter rechts auf "branches" klickst, sollte dort der neue Branch auftauchen (manchmal mit etwas Verzögerung). Wenn du oben auf "Network" klickst, siehst du wie dein neuer Branch vom development abzweigt. Jeder Punkt in diesem Diagramm steht für einen commit.

Wenn dein Branch fertig ist und in den development übernommen werden soll, wählst du ihn aus der Branches-Liste aus und klickst oben auf "Pull Request"; hier kannst du noch einen zusätzlichen Kommentar angeben. Der Code Maintainer wird per E-Mail informiert und wird deinen Code prüfen und ggf. übernehmen.

In diesem Fall war es wahrscheinlich nur ein Test, daher kannst du den Branch nun mit

git push origin :1234-new-feature

wieder aus deinem Fork löschen. Wenn du ihn auch lokal wieder löschen willst, geht das mit

git checkout development
git branch -D 1234-new-feature 

Das große -D ermöglicht es, einen Branch zu verwerfen, der nicht weiterverwendet wurde. Wenn du stattdessen -d angibst, sind nur Branches löschbar die bereits in einen anderen Branch (z.B. den development) übernommen wurden, wo durch die Löschung also keine Daten verloren gehen können. Im Zweifelsfall verwende immer -d; dabei kann nichts versehentlich verloren gehen.

Zusammenfassung des OC-Git-Standard-Workflow

  • Neuen Branch für eine neue Aufgabe anlegen
    1. git checkout development
    2. git pull upstream
    3. git checkout -b 1234-new-feature
    ... oder die Arbeit an einem bereits bestehenden Branch mit git checkout 1234-new-feature fortsetzen
  • Programmierzyklen
    1. Code schreiben
    2. mit git status / git diff lokale Änderungen kontrollieren
    3. Änderung mit git add / git commit ins lokale Repo einchecken
    4. mit git pull --rebase upstream development auf aktuellen OC-Code aufsetzen
    5. weiter bei 1, wenn der Code noch nicht fertig ist
  • Hochladen
    1. git push origin 1234-neues-Feature
    2. Branch 1234-neues-Feature auf GitHub aufrufen und Pull Request starten
  • Nicht mehr benötigte Branches löschen
    1. lokal: git checkout development / git branch -d 1234-neues-Feature
    2. auf dem Fork: git push origin :1234-neues-Feature

Commits zusammenfassen

Wenn in Schritt 4-8 mehrere Einzelcommits entstehen, kannst du sie vor dem Hochladen zur besseren Übersicht zu einem zusammenfassen. Prüfe mit git log nach, wieviele Commits zusammenzufassen sind - sie sollten noch nicht hochgeladen sein! - und gib ein:

git rebase -i HEAD~n

... wobei n die Zahl der Commits ist. Nun erscheint ein Editorfenster mit einem "pick" je Commit. Ersetze alle "picks" ab dem zweiten durch "squash" oder "s", was bedeutet, dass sie mit dem Commit davor zusammenzufassen sind. Nach dem Speichern erscheint ein zweiter Text im Editor, in dem du auch die Commit-Kommentare zusammenfassen kannst.

Wenn du dir ganz sicher bist, dass ein bereits hochgeladener Commit noch nicht weiterverwendet wurde - z.B. wenn du ihn eben erst hochgeladen und noch keinen Pull Request gemacht hast - kannst du ihn auch noch nachträglich mit neuen Commits zusammenfassen. Dies funktioniert wie oben beschrieben, allerdings musst du beim anschließenden push zusätzlich --force angeben, um den/die alten Commit(s) in deinem Fork zu überschreiben.

Aktuelle Daten holen; mehrere Änderungen testen

Wenn du selbst gerade nichts programmieren willst, sondern dir einfach nur ein Update vom OC-Server holen und anschauen, machst du

git checkout development
git pull upstream 

Wenn du mehrere Branches mit eigenen Änderungen angelegt hast, und diese alle im Zusammenhang testen möchtest, kannst du dir dafür einen Testbranch anlegen:

git checkout -b test development
git merge 1234-new-feature
git merge 2345-my-bugfix
... 

Änderungen verwerfen

  • alle geänderten Dateien: git reset --hard
  • alles geänderten Dateien im aktuellen Verzeichnisbaum: git checkout .
  • alle neuen, noch nicht hinzugefügten Dateien: git clean -f -d
  • nur eine bestimmte Datei: git checkout Dateiname

... die bereits "commitet", aber noch nicht "gepusht" sind:

  • git reset --hard HEAD~n

... wobei n die Zahl der zu verwerfenden Commits ist. Wenn die Änderungen bereits "gepusht" wurden:

  • mit git log die rückgängig zu machende Commit-ID raussuchen
  • git revert commit-ID
  • git push
  • evt. Pull-Request auf dem GitHub, wenn es bereits im Upstream angekommen war

Den Kommentar des letzten, noch nicht "gepushten" Commit korrigieren:

  • git commit --amend

Daten direkt von anderen Entwicklern holen

Wenn du z.B. den Branch 1234-new-feature von Entwickler heinz testen möchtest, kannst du ihn in einen Testbranch bei dir herunterladen. Zunächst musst du heinz' Fork einmalig als weitere Upstream definieren:

git remote add heinz git@github.com:heinz/oc-server3

Dann legst du bei dir einen Testbranch an, am besten auf Basis aktuellster Daten ...

git checkout development
git pull upstream
git checkout -b tolles-heinz-feature 

... und mergst seinen Feature-Branch in deinen Testbranch:

git pull heinz 1234-new-feature

Der stable-Branch

Neben dem development gibt es im OC-Repository einen Branch "stable". Dieser enthält immer den gleichen Stand wie das Produktivsystem www.opencaching.de. Neue Features werden im development entwickelt und getestet und später über den Stable-Branch freigegeben.

Mit dem Stable-Branch wirst du nur dann zu tun haben, wenn du einen "Hotfix" schreibst - eine dringende Korrektur, die sofort freigegeben werden soll. Diese setzt du auf dem Stable statt dem development auf; der übrige Workflow ist der gleiche wie oben beschrieben.

Vereinfachter Workflow

Der oben beschriebene Workflow ist Pflicht für alle Entwickler, die Code zu OC.de beitragen. Wer nur hin und wieder mal eine Grafik oder einen Text beisteuert, kann ausnahmsweise auch ohne separate Branches arbeiten. In diesem Fall ist ein einfaches git pull im development-Branch verboten! Stattdessen muss überall, wo oben git pull upstream steht, stattdessen

git pull --rebase upstream development 

verwendet werden! Der vereinfachte Ablauf ist dann:

1. Code schreiben
2. mit git status / git diff lokale Änderungen kontrollieren
3. Änderung mit git add / git commit ins lokale Repo einchecken
4. mit git pull --rebase upstream development auf aktuellen OC-Code aufsetzen
5. weiter bei 1, wenn der Code noch nicht fertig ist
6. git push origin
7. Pull-Request

Noch ein paar Gimmicks

  • git branch -m 1234-neuestes-Feature Benennt den derzeit aktiven Branch um in "1234-neuestes-Feature".
  • git diff Branchname zeigt alle Unterschiede zwischen dem aktuellen Branch und einem anderen an.
  • git cherry-pick Commit-ID übernimmt einen bestimmten Commit (von wo auch immer) in den aktiven Branch.
  • git diff --name-only --diff-filter=U zeigt eine Liste aller konfliktbehafteten Dateien nach einem Merge an
  • git gc führt eine Garbage Collection durch und gibt Platz im lokalen Repository frei. Per git reset --hard oder git branch -d gelöschte Commits werden damit endgültig weggeworfen (vorher sind sie via git reflog noch wiederherstellbar).
  • git grep Suchbegriff durchsucht den Code des aktuellen Verzeichnisbaums; für zahlreiche Optionen siehe Git-Doku.
  • git help Kommando zeigt die Doku für ein Git-Kommando an.

Forenbeiträge zu Git