Core Forking - best practice

Aus Contao Community Documentation


Core Forking - best practice

Dieses Tutorial beschreibt, wie man einen eigenen Fork von Contao mit git anlegt und beschreibt in einem good practice Szenario wie man eigene Features entwickelt, diese als Pull Requests dem Entwicklerteam übergibt und sein eigenes Repsitory auf dem aktuellen Stand hält.

Dieses Szenario ist nicht nur für den Contao Core geeignet, sondern kann auch auf andere Projekte, die auf github gehostet werden übernommen werden.


Hinweis.png Hinweis: Es gibt viele verschiedene git Clients, die aber alle etwas anders arbeiten. Da hier nicht auf alle Eigenarten der jeweiligen GUIs eingegangen werden kann, werden alle Beispiele mit dem Originalprogramm git auf der Konsole ausgeführt und gezeigt!


Voraussetzungen

git Kentnisse

git ist ein verteiltes Source Code Management System. Wer mit git noch nicht vertraut ist, dem sei das Buch Pro Git, welches Online, gedruckt und auch als eBook erhältlich ist ans Herz gelegt. Es gibt noch andere gute Bücher, z.B. Git. Verteilte Versionsverwaltung für Code und Dokumente die git ausführlich und praktisch erklären.

Achtung.png Achtung: Einsteigern sei gesagt, das git in vielen Punkten anders zu Handhaben ist, als das zentral organisierte Subversion (svn). Umsteigern wird dringend empfohlen, sich zuerst mit git auseinander zu setzen.


github Account

github ist einer der größten freien Anbieter für git Repositories auf dem Markt. Ähnlich wie Sourceforge. github wird bereits von vielen großen Unternehmen und Projekten genutzt, z.B. facebook, Twitter, redhat, Apache, eclipse, jquery, mootools und vielen mehr. So ist auch Contao seit dem Contao Camp 2011 auf github zu finden. Für dieses Tutorial wird ein Account auf github benötigt.

Contao Core forken

Der persönliche Fork

Zuerst muss ein persönlicher Fork erstellt werden. Ein Fork ist eine Kopie des Repositories, im eigenen Account. Auf dem Fork kann man beliebig arbeiten, man hat alle Commits die bis zu dem Zeitpunkt gemacht wurden zur Verfügung und kann mit diesen Arbeiten wie es einem beliebt. Um einen persönlichen Fork zu erstellen, muss zuerst das Contao Repository auf github aufgerufen werden. Anschließen reicht ein klick auf den Button Fork um einen persönlichen Fork zu erstellen. Nachdem der Vorgang abgeschlossen ist, wird man direkt auf seinen persönlichen Fork weitergeleitet.

Fork erstellen

Den persönlichen Fork richtig benennen

Standardmäßig wird der Fork unter dem Namen core erstellt. core kann vieles bedeuten, daher empfiehlt es sich, das Repository sinnvoll umzubenennen. Z.B. in contao-core. Dazu muss zuerst auf den Button Admin geklickt werden, im darauffolgenden Formular lässt sich der Name des Repositories ändern.

URL zum persönlichen Fork

Den persönlichen Fork klonen

Als nächstes muss der eigene Fork geklont werden, dazu wird die URL von dem persönlichen Fork benötigt.

URL zum persönlichen Fork
$ git clone git@github.com:tristanlins/contao-core.git
Cloning into contao-core...
remote: Counting objects: 27464, done.
remote: Compressing objects: 100% (6952/6952), done.
remote: Total 27464 (delta 20159), reused 27310 (delta 20025)
Receiving objects: 100% (27464/27464), 17.49 MiB | 152 KiB/s, done.
Resolving deltas: 100% (20159/20159), done.

Den Fork aktuell halten

Der Fork ist eine Kopie von dem Zeitpunkt, als dieser erstellt wurde. Neue Änderungen die im Originalrepository durchgeführt werden, kommen nicht automatisch in das eigene Repository. Will man immer auf dem aktuellen Stand bleiben, muss man ein bisschen selbst Hand anlegen.

Zuerst muss ein Remote zum Originalrepository hinzugefügt werden, dies geschieht mit git remote add <name> <url>, es empfiehlt sich als Remote Name contao zu nehmen. Als URL nehmen wir die öffentliche git URL zum Contao Core Repository https://github.com/contao/core.git.

$ cd contao-core
contao-core/ $ git remote add contao https://github.com/contao/core.git

Anschließend rufen wir die Informationen aus dem Repository ab, so dass diese lokal zur Verfügung stehen.

contao-core/ $ git fetch contao
remote: Counting objects: 2624, done.
remote: Compressing objects: 100% (936/936), done.
remote: Total 1917 (delta 1552), reused 1303 (delta 973)
Receiving objects: 100% (1917/1917), 555.81 KiB | 234 KiB/s, done.
Resolving deltas: 100% (1552/1552), completed with 329 local objects.
From https://github.com/contao/core
 * [new branch]      2.11.x     -> contao/2.11.x
 * [new branch]      3.0.x      -> contao/3.0.x
 * [new branch]      master     -> contao/master
 * [new tag]         2.11.RC1   -> 2.11.RC1
 * [new tag]         2.11.RC2   -> 2.11.RC2

Ein Blick auf alle verfügbaren Branches zeigt, dass jetzt nicht nur die lokalen und die aus dem persönlichen Fork (origin), sondern auch die Branches aus dem Contao Core Repository (contao) zur Verfügung stehen.

contao-core/ $ git branch -a
* master
  remotes/contao/2.11.x
  remotes/contao/3.0.x
  remotes/contao/master
  remotes/origin/2.11.x
  remotes/origin/HEAD -> origin/master
  remotes/origin/browserversions
  remotes/origin/database_result_issues
  remotes/origin/dcasaveperformance
  remotes/origin/gitignore
  remotes/origin/master

Während die remotes/origin/* Branches die Branches in dem persönlichen Fork darstellen (man sieht das bereits ein paar zusätzliche angelegt wurden), stellen die remotes/contao/* Branche die aus dem Contao Core Repository dar.

Lokale Branches aktualisieren

Wir gehen von folgender Situation aus, wir haben vor längerer Zeit einen persönlichen Fork erstellt und einen Commit gemacht. Am Contao Core wurde mittlerweile weiter entwickelt und wir wollen die persönlichen Änderungen auf den neuen Stand aufsetzen. Eine Möglichkeit wäre es, den neuen Stand aus dem Core Repository neu zu branchen und die Änderungen manuell einzuspielen. Mit git geht es auch automatisch und zwar mit git rebase.

Zuerst einmal die Ausgangssituation.

* 76b0bab (tag: 2.10.4, contao/master) Version 2.10.4
* 18bc510 Set all files to CHMOD 644
* dcab24e Correctly handle HTML comments in inline JavaScripts (#3696)
* a9199e5 Get the next auto increment ID when importing a theme so deleted themes can be restored (#3604)
| * a18c378 (HEAD, master) Make some changes on an old state.
|/  
* baaa762 (origin/master, origin/HEAD) Correctly handle HTML comments in inline JavaScripts (#3696)
* 328ed4a Correctly update the cache after a new template has been created (#3676)
* 3a2aefe Do not block resources required by the Google website preview in the robots.txt file (#3688)
...

Der Commit a18c378 stammt von einem alten Commit baaa762 ab. Im contao Repository gibt es aber bereits 4 neue Commits a9199e5, dcab24e, 18bc510 und 76b0bab.


Merge bietet sich in diesem Fall nicht an, da ein Merge die Versionsgeschichte verfälschen würde.

*   6c2bda5 (HEAD, master) Merge remote-tracking branch 'contao/master'
|\
| * 76b0bab (tag: 2.10.4, contao/master) Version 2.10.4
| * 18bc510 Set all files to CHMOD 644
| * dcab24e Correctly handle HTML comments in inline JavaScripts (#3696)
| * a9199e5 Get the next auto increment ID when importing a theme so deleted themes can be restored (#3604)
* | a18c378 (HEAD, master) Make some changes on an old state.
|/
* baaa762 (origin/master, origin/HEAD) Correctly handle HTML comments in inline JavaScripts (#3696)
* 328ed4a Correctly update the cache after a new template has been created (#3676)
* 3a2aefe Do not block resources required by the Google website preview in the robots.txt file (#3688)
...

Was ist falsch? Die Weiterentwicklung von Contao würde durch einen Merge als Abspaltung der Geschichte erkannt. Was aus Sicht des Fork auch korrekt ist, da die Weitereintwicklung ja in einem anderen Repository statt findet. Wir wollen jedoch nicht die Weiterentwicklung in unseren Fork integrieren, sondern wir wollen unseren Fork auf den neuen Stand aufbauen. Unser Ziel ist ganz einfach, unsere Änderungen, Commit a18c378 soll als direkten Vorgänger den letzten Commit 76b0bab erhalten, so das die Linearität erhalten bleibt.

Das Ziel sollte also so aussehen.

* ....... (HEAD, master) Make some changes on an old state.
* 76b0bab (tag: 2.10.4, contao/master) Version 2.10.4
* 18bc510 Set all files to CHMOD 644
* dcab24e Correctly handle HTML comments in inline JavaScripts (#3696)
* a9199e5 Get the next auto increment ID when importing a theme so deleted themes can be restored (#3604)
* baaa762 (origin/master, origin/HEAD) Correctly handle HTML comments in inline JavaScripts (#3696)
* 328ed4a Correctly update the cache after a new template has been created (#3676)
* 3a2aefe Do not block resources required by the Google website preview in the robots.txt file (#3688)
...

Dies können wir mit git rebase erreichen. Rebase ist ein komplexes Thema, es liefert ähnliche Ergebnisse wie ein Merge, jedoch greift Rebase stark auf die Versionsgeschichte ein. Rebase mit all seinen Möglichkeiten kann hier nicht erklärt werden, daher soll hier lediglich das einfache Rebase gezeigt werden, da es das ist, was wir brauchen.

Um unser Ziel zu erreichen, reicht ein git rebase contao/master. Das bedeutet so viel wie: Baue mir alle Änderungen meines lokalen Branch (master) auf den Branch contao/master auf. Rebase sucht dafür den nächsten Gemeinsamen Vorgänger, in unserem Fall der Commit baaa762. Nimmt alle Änderungen die seither in unserem lokalen Branch passiert sind, in unserem Fall nur der Commit a18c378 und baut diese auf den Stand von contao/master, also den Commit 76b0bab neu auf. Git baut dabei jeden Commit einzeln auf die neue Basis auf. Sollten dabei Konflikte auftreten, meldet git detailliert was zu tun ist.

$ git rebase contao/master
First, rewinding head to replay your work on top of it...
Applying: Make some changes on an old state.

Danach sieht unsere Versionsgeschichte so aus, wie wir sie haben wollten.

* a93f652 (HEAD, master) Make some changes on an old state.
* 76b0bab (tag: 2.10.4, contao/master) Version 2.10.4
* 18bc510 Set all files to CHMOD 644
* dcab24e Correctly handle HTML comments in inline JavaScripts (#3696)
* a9199e5 Get the next auto increment ID when importing a theme so deleted themes can be restored (#3604)
* baaa762 (origin/master, origin/HEAD) Correctly handle HTML comments in inline JavaScripts (#3696)
* 328ed4a Correctly update the cache after a new template has been created (#3676)
* 3a2aefe Do not block resources required by the Google website preview in the robots.txt file (#3688)
...

Die lokalen Commits bekommen dabei neue Ids, da sich ihr direkter Vorgänger geändert hat und damit auch das Commit Objekt. Aus unserem Commit a18c378 ist also der Commit a93f652 geworden, der jetzt auf den aktuellen Stand von Contao aufbaut.

Neue Features entwickeln

Der neue Fork besteht standardmäßig aus den gleichen Branches wie das Contao Repository. Um im persönlichen Fork den Überblick nicht zu verlieren, vor allem wenn man mehrere Features parallel entwickeln will, sollte jedes Feature in einem eigenen Branch entwickelt werden. Ein neuer Feature-Branch sollte immer auf einen Branch aus contao/* aufgebaut werden. Dadurch wird das Feature immer auf dem aktuellen Stand entwickelt und kann so von den Contao Entwicklern automatisiert in den Core überführt werden.

Zuerst muss man wissen, für welche Version will man das Feature entwickeln? Für Contao 2.10.5, Contao 2.11 oder sogar schon Contao 3? Diese Frage sollte wenn möglich vorher beantwortet werden, da es einem einige Arbeit ersparen kann. Wir gehen davon aus, dass das neue Feature für Contao 2.11 entwickelt werden soll, das entspricht dem Branch 2.11.x.

Hinweis.png Hinweis: Mit git branch -a können sich immer alle verfügbaren Branches angezeigt werden.


# zuerst aktualisieren wir den lokalen Bestand
contao-core/ $ git fetch --all
Fetching origin
Fetching contao
# jetzt lassen wir uns alle verfügbaren Branches anzeigen
contao-core/ $ git branch -a
* master
  remotes/contao/2.11.x
  remotes/contao/3.0.x
  remotes/contao/master
  remotes/origin/2.11.x
  remotes/origin/HEAD -> origin/master
  remotes/origin/browserversions
  remotes/origin/database_result_issues
  remotes/origin/dcasaveperformance
  remotes/origin/gitignore
  remotes/origin/master
# danach erstellen wir einen neuen Branch, auf Basis von origin/master
contao-core/ $ git branch myfeature origin/master
Branch myfeature set up to track remote branch master from origin.
# und wechseln auf den neuen Branch
contao-core/ $ git checkout myfeature 
Switched to branch 'myfeature'

In dem neuen Branch kann nun das neue Feature entwickelt werden. Wenn alles fertig ist, pushen wir den neuen Branch in unseren Fork.

contao-core/ $ git push -u origin myfeature 
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 325 bytes, done.
Total 3 (delta 2), reused 0 (delta 0)
To git@github.com:tristanlins/contao-core.git
 * [new branch]      myfeature -> myfeature
Branch myfeature set up to track remote branch myfeature from origin.

Nach dem alles zu github übertragen wurde, ist der neue Branch im Interface verfügbar.

Der branch myfeature auf github

Einen Pull Request erstellen

Ein Pull Request ist einfach gesagt ein Ticket im Tracker, bei dem auch die Änderungen übermittelt werden. Die Entwickler können über die Änderungen diskutieren, den Pull Request nochmal nachbessern und letztendlich mit ein paar Klicks in das Contao Repository automatisch überführen.

Um einen Pull Request zu erzeugen reicht es, im Interface von github beim persönlichen Fork auf den Button Pull Request zu klicken.

Einen Pull Request erzeugen

Wichtig ist, dass man genau ausgewählt hat, für welchen Branch im Core Repository der Pull Request bestimmt ist und welchen eigenen Branch man pullen möchte. Die Auswahl der Commit Range erhält man, wenn man auf den Button Change Commits klickt.

Die richtige Auswahl von Ziel und Quelle

Zum Schluss beschreibt man noch, möglichst ausführlich und nachvollziehbar was die Änderungen bewirken und warum sie gemacht wurden. Mit einem Klick auf Send pull request schickt man den Pull Request an die Contao Core Entwickler.

Tips und Troubleshooting

UNIX/DOS Dateiformat automatisch korrigieren

Contao benutzt für alle Dateien das UNIX Format (\n), wenn man Contao unter Windows klont, kann es vorkommen, dass nach dem Klonen ganz viele Änderungen im Repository gemeldet werden, weil die Dateien alle in das DOS Format (\r\n) konvertiert wurden. GIT versucht einfach, das Dateiformat der aktuellen Platform zu bestimmen und konvertiert Dateien dann automatisch um. Wer am Contao Core mitentwicklen will, sollte jedoch alle Dateien im UNIX Format comitten. Um GIT zu sagen, dass es nicht die Platformeinstellung nehmen soll, reicht eine Änderung der GIT Konfiguration core.autocrlf.

$ git config --global core.autocrlf input

Der Wert input besagt, dass alle Dateien in das UNIX Format konvertiert werden sollen. Dies gillt für alle neu zum Repository hinzugefügte Dateien, bzw. beim klonen von Repositories. Auf github ist beschrieben wie sich core.autocrlf genau auswirkt und welche Werte die Option annehmen kann.

Ansichten
Meine Werkzeuge

Contao Community Documentation

Chuck Norris programmiert kein PHP, er diktiert das Ergebnis. Den Rest macht der Editor aus Angst.

Stefan Lindecke
Navigation
Verstehen
Verwenden
Entwickeln
Verschiedenes
Werkzeuge