Development:Git Patch erstellen
Wer einen Patch bereitstellen möchte, kann mit Git speziell importierbare Patchfiles erstellen. Die nötigen Funktionen werden durch Git ohne Zusatzsoftware zur Verfügung gestellt. Zusätzliche Tools wie diff und patch werden nicht benötigt.
Durch diese Git Eigenheit wird das Arbeiten mit Git auch für die Entwickler deutlich vereinfacht. Anders als CVS oder auch SVN unterscheidet Git zwischen Committer und Autor des Patches. Dies hat unter Anderem auch zur Folge, das durch einen mit Git formatierter Patch, sofern er korrekt erzeugt und angewendet wurde, auch der Autor in die Historie des Repostories aufgeführt wird.
Da mit Git formatierte Patche in der Regel auf lokale Commits des Autors basieren, werden auch die darin bereits vorhandenen Commit Messages übernommen. Sofern diese auch den Patch erklären, ist es für den Entwickler, der den Patch erhält auch schneller nachvollziebar, worum es bei diesem oder jenem Patch geht und braucht sich nicht selbst um die Commit Message zu kümmern. Andererseits kann der Autor vor der Überführung in das Remote-Repo und auch Dank der vorhandenen Autordaten im Repo später um Nachbesserung gebeten werden.
Inhaltsverzeichnis
Vorbereitung
Sicherstellen das ein gültiger Authorname und eine gültige Emailadresse hinterlegt ist. Wenn nicht, dies global für alle Git Repositories nachholen.
git config --global user.name "Firstname Lastname"
git config --global user.email "your_email@youremail.com"
Oder nur für das lokale Git Repository.
cd /Pfad/zum/Repository
git config user.name "Firstname Lastname"
git config user.email "your_email@youremail.com"
Es ist übrigens unangemessen ungültige, falsche, keine oder gar sinnlose Angaben zu machen und zeugt gegenüber anderen Entwicklern und Contributoren eher von schlechtem Stil und ist deshalb nicht gern gesehen!
Quellcode verändern
Diese Schritt ist genauso wie bei anderen SCM-Systemen. Man verändert den Quellcode mit den eigenen gewünschten Veränderungen.
git pull
# adding some modifications
Patch erstellen
Patche werden unter Git üblicherweise aus Commits erstellt und lassen sich somit entwicklerfreundlich weitergeben. Patche, die herkömmlich ohne Commits erzeugt werden (git diff), sind lediglich ein Mittel für Schnelltests. Auch wenn man dies evtl. von früheren zentralen Versionskontrollsystemen so gewohnt ist, sollte man beim Arbeiten mit Git davon absehen, unformatierte bzw. rohe Patches an Entwickler zu übergeben. Der Aufwand hierfür geht im Verhältnis gegenüber alten Methoden gegen Null, wenn man bedenkt, dass mehr als nur ein einfacher Patch dabei herauskommt. Diese Arbeitsweise scheint vor allem für Umsteiger ein Problem zu sein, aber dies ist auch eine Frage des Teamworks innerhalb des Projektes und diese unter Git übliche Vorgehensweise wird man sehr schnell schätzen lernen.
Grundlage: Commit erzeugen
Um seine Änderungen weitergeben zu können, müssen die Quellcodeveränderungen zunächst committet werden. Wenn Ihr wirklich nur die Dateien verändert habt, die zum Commit gehören, kann einfach dieses Kommando verwendet werden.
git commit -a
Wenn nicht per
git add <Datei1> <Datei2> ...
die relevanten Dateien selektiv hinzufügen und abschließend
git commit
aufrufen. Hier im Beispiel eine einfache Veränderung der neutrino.cpp.
user@pc~/gitprojects/buildsystem-cs/source/neutrino-hd [tuxbox-port]$ vi src/neutrino.cpp
user@pc~/gitprojects/buildsystem-cs/source/neutrino-hd [tuxbox-port]$ git commit -a
[tuxbox-port 5756abf] neutrino.cpp: changing debug output to use macro dprintf
1 files changed, 2 insertions(+), 2 deletions(-)
Nun liegen die Veränderungen im lokalen Git Repo und können mit
git format-patch [BRANCH]
als Patch ausgegeben werden.
Spätestens jetzt sollte man erkennen, dass man für seine lokalen Änderungen, die man für eine bestimmte Aufgabe abarbeitet immer mit Branches arbeiten sollte und darin seine Commits klein und nachvollziebar hält. Möchte man später trotzdem mehrere Commits zu einem oder weniger Commits zusammenfassen, kann man das über git rebase -i nachholen.
Im Beispiel wurde die neutrino.cpp vom Branch tuxbox-hd/tuxbox-port verändert. Daher dann auch der git-format-patch Befehl gegen diesen Branch. Würde man gegen origin/master in dem Falle den Befehl anwenden, dann würden auch alle Patches bzw. Änderungen aus weiteren Commits ausgegegeben werden, die sich zwischen tuxbox-hd/tuxbox-port und origin/master ergeben.
user@pc~/gitprojects/buildsystem-cs/source/neutrino-hd [tuxbox-port]$ git format-patch tuxbox-hd/tuxbox-port
Ergebnis:
0001-neutrino.cpp-changing-debug-output-to-use-macro-dpri.patch
Das ist eigentlich schon alles. Diese Datei(en) können nun an einen Entwickler geschickt werden.
Patch von einem Einzel-Commit erstellen
zunächst das Log aufrufen, um den benötigten Commit zu finden. In diesem Beispiel liegt der betreffende Commit ein einem lokalem Branch und sollte unter den letzten paar commits zu finden sein. Pauschal suchen wir nun die letzten Commits ab:
git log -3
Dies gibt nun die letzten Commits aus:
commit ac7abd8db402724f9c195b2091c7a92997edce6e
Author: Thilo Graf <###@n###x.de>
Date: Mon Apr 16 10:51:07 2012 +0200
target ntp: add target for ntp
neutrino sectionsd missed ntpdate with error log
"getUTC: read: invalid argument
ntpdate not found"
ntpdate should also now can be intstalling with system-tools
Signed-off-by: Thilo Graf <###@n###x.de>>
commit 3caecd682aea585f101286ec7cb550813c7ac1df
Author: Stefan Seyfried <seife@tuxbox-git.#######.de>
Date: Sun Apr 15 19:52:05 2012 +0200
start_neutrino: prepare for deep standby
commit 874ba0c75afe65ebd0a2482000634ac0c75303f2
Author: Stefan Seyfried <seife@tuxbox-git.#######.de>
Date: Sun Apr 15 18:48:23 2012 +0200
spark: use aotom FP to switch the box into deep standby
For this to be really useful, we need support in neutrino.
lines 1-28/28 (END)
Wenn der gewünschte Commit dieser ist: ac7abd8db402724f9c195b2091c7a92997edce6e erzeugt folgendes Kommando einen entsprechenden Patch
git format-patch -M -C ac7abd8db402724f9c195b2091c7a92997edce6e~1...ac7abd8db402724f9c195b2091c7a92997edce6e
Heraus kommt ein nummerierter Patch:
0001-target-ntp-add-target-for-ntp.patch
- Die Tilde (~) bei der ersten SHA1 Summe hat die Bedeutung das Git den Bezug auf die Anzahl nach der Tilde angegebenen Comit vor der SHA1 Summe nimmt (auf Commit 3caecd6), im Beispiel eben genau einen Commit davor. Man könnte so z.B. auch Bezug auf den drittletzten oder zehnten Comit vor der angebeben SHA1 Summe nehmen. Damit kann man auch mehrere Commits zu einem in Form eines Patches ohne Rebasing zusammen fassen.
- Man muss sich nicht die langen SHA1 IDs merken. Git begnügt sich auch mit den ersten sieben Zahlen der SHA1 Summe, wenn es nicht andere Commits gibt die mit den selben Zahlen beginnen.
- Der obere Befehl kann also auch verkürzt werden:
git format-patch -M -C ac7abd8~1...ac7abd8
0001-target-ntp-add-target-for-ntp.patch
Patch aus mehreren Commits erstellen
Angenommen man arbeitet lokal an einer Sache, die man in üblicherweise in mehreren Commits und in einem separaten Branch abgearbeitet hat und möchte genau diese Commits als Patch weitergeben, kann man diese ebenfalls als Folge von Einzelpatches erzeugen. Befindet sich also z.B. im lokalen Branch "commit" und dieser beinhaltet 4 Commits, würde man das etwa so machen:
$ git format-patch commit~1
Ergebnis:
0001-dvbsi-try-to-fix-broken-neutrino-build-with-cst-dvbs.patch 0002-libdvbsi-add-patch-for-src-time_date_section.cpp.patch
Den oder die erzeugten Patche kann man nun per eMail an eine Mailingliste oder direkt an einen Entwickler schicken.
einen Patch von einer dritten Person erhalten
Es ist möglich, das Ihr von einer anderen Person einen Patch erhalten habt und diesen weitergeben wollt. Wenn diese Person nun wiederum den Patch nicht selbst weitergeben wollte, aber trotzdem einverstanden ist, das der Patch weitergegeben werden kann, dann könnt Ihr diesen Patch noch mit einem SignOff versehen. Dazu einfach die Option --signoff beim git-format-patch mit angeben.
user@pc~/gitprojects/buildsystem-cs/source/neutrino-hd [tuxbox-port]$ git format-patch tuxbox-hd/tuxbox-port --signoff
Ergebnis:
0001-neutrino.cpp-changing-debug-output-to-use-macro-dpri.patch
Danach wie oben schon beschrieben den Patch an einen Developer weiter geben.
einen Patch einspielen
Es gibt einige Möglichkeiten einen Patch direkt anzuwenden. Git stellt hierfür einige Kommandos bereit
git apply
git apply ist quasi das Git-Gegenstück zum allgemein bekannten Unix-Werkzeug patch. Dazu wird dieser Befehl benutzt:
git apply [/Pfad/zur/Patchdatei]
Einzige Bedingung ist, das Ihr im entsprechenden Git Repository seid.
user@pc~/gitprojects/buildsystem-cs/source/neutrino-hd [tuxbox-port]$ git apply 0001-neutrino.cpp-changing-debug-output-to-use-macro-dpri.patch
Die Anwendung eines solchen Patches ist also recht einfach, ist aber nur für lokales Arbeiten sinnvoll, um Schnelltests durchzuführen, ansonsten sollte man vorzugsweise auf git am zurückgreifen, insbesondere dann, wenn der Patch vom Autor als "commitreif" zugestellt wurde und für einen Commit in das Remote-Repo vorgesehen ist.
git am
Im Unterschied zu git apply werden angewendete Patche wie Commits behandelt, also stellt quasi jeder Patch einen Commit dar. Hat man also einen mit git format-patch formatierten Patch erhalten, kann man diesen Patch mit git am anwenden und überträgt gleichzeitig relevante Daten wie z.B. Autor-Informationen und übernimmt diese in die Historie des Repos. Diese Möglichkeit ist daher gegenüber der git apply Methode vorzuziehen, da hier auch die Leistungen von Contributoren eines Projektes gewürdigt werden. Unter anderen Versionskontrollsystemen wie Subversion oder CVS würde dies nie ins Gewicht fallen.
Ursprünglich ist git am dazu gedacht, Patche direkt aus EMails zu übernehmen, jedoch werden auch Dateien direkt übernommen. Befinden sich der oder die Patche im Stammverzeichnis des Gitrepos, reicht dieser Befehl:
git am 0001-neutrino.cpp-changing-debug-output-to-use-macro-dpri.patch
Bei mehreren Patchdateien kann man auch Platzhalter verwenden:
git am *.patch