|
Um schnell Änderungen an versionierter Open Source Software vornehmen zu können, nutzen wir Patch-Dateien. Natürlich könntest Du auch einen Fork des Projekts erstellen und diesen regelmäßig warten... und alle zukünftigen Änderungen vom Original-Projekt auf diesen Fork anwenden... doch das ist mit einem sehr großen Aufwand verbunden und oft keine langfristige Option.
Eine Alternative ist, im Original-Projekt einen Pull-Request zu stellen. Manchmal dauert es aber zu lange, bis dort ein Pull-Request mit den gewünschten Änderungen in einem Release landet. Hier ist es dann oft hilfreich, eigene Patches zu erstellen und diese anzuwenden. Oft sind die gewünschten Änderungen auch fallspezifisch und haben daher im Original-Projekt nichts verloren. Dann ist ein Patch-File notwendig.
Wie du mit Git dein erstes Patch-File erstellst
Nachdem du deine Änderungen am Projekt vorgenommen hast, generierst du deine Patch-Datei mit dem Befehl git format-patch
.
Um deine Änderung anschließend anzuwenden, führst Du git apply-patch
aus. Alternativ kann das zum Beispiel ebenfalls mit patch -p0 < some-changes.patch
gemacht werden.
Patch-Datei von GitHub-URLs generieren
Bei GitHub und anderen Plattformen kann ganz einfach über ein .patch
oder .diff
in der URL bei Commits und Pull-Requests eine entsprechende Datei ausgegeben werden.
Beispiel:
Ein Link zu einem Commit auf GitHub.
https://github.com/magento/magento2/commit/158 ... d6
Ein Link zum gleichen Commit, aber als Raw Patch-Datei auf GitHub. Achte auf das .patch
am Ende der URL.
https://github.com/magento/magento2/commit/158 ... d6.patch
Damit erhält man direkt eine passende .patch
-Datei, um die Änderungen ganz einfach lokal einzuspielen.
Der Aufbau einer .patch
-Datei ...
So eine .patch
-Datei kann folgendermaßen aussehen:
From c7b9e39a070857e62a1e7728bb873f7f084d61d2 Mon Sep 29 00:00:00 2001
From: user <[email protected]>
Date: Sun, 28 Oct 2018 17:01:06 +0530
Subject: commit message
---
.../some/path/file.ext | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/some/path/from/git/root/file.ext b/some/path/from/git/root/file.ext
index 3a6574bff894..447d626b339b 100644
--- a/some/path/from/git/root/file.ext
+++ b/some/path/from/git/root/file.ext
@@ -35,9 +35,8 @@ define([
some code
- if (something) {
- console.log(test);
- }
+ /* some comment */
+ newmethod();
some code
Nachfolgend eine Erklärung der Zeilen anhand von Kennzeichnungen:
--- Angabe des Commit-Hash, aus dem der Patch stammt
--- inklusive eines Datums, wann er erstellt wurde.
From c7b9e39a070857e62a1e7728bb873f7f084d61d2 Mon Sep 29 00:00:00 2001
--- Der Git-User, der den Commit erstellt hat
From: user <[email protected]>
--- Das Datum vom Commit, wann dieser erstellt wurde.
Date: Sun, 28 Oct 2018 17:01:06 +0530
--- Die Nachricht des Commits.
Subject: commit message
--- Trennung der optionalen Metadaten vom Patch.
---
--- Liste der geänderten Dateien.
.../some/path/file.ext | 5 ++---
--- Zusammenfassung der Änderungen aufgelöst auf die Anzahl
--- der Dateien und Art der Änderungen (hinzugefügte / entfernte Zeilen).
1 file changed, 2 insertions(+), 3 deletions(-)
--- Angabe der betroffenen Dateien. a ist die originale,
--- b die neue Datei mit den Änderungen.
diff --git a/some/path/from/git/root/file.ext b/some/path/from/git/root/file.ext
--- Infos für git inklusive der Dateirechte für die
--- Erstellung und Anpassung der Dateien.
index 3a6574bff894..447d626b339b 100644
--- Die alte/geänderte Datei bzw. ihr alter Pfad.
--- a/some/path/from/git/root/file.ext
--- Die neue Datei bzw. ihr neuer Pfad mit den Änderungen.
+++ b/some/path/from/git/root/file.ext
--- @@ gefolgt von der Startzeilennummer in der Original-Datei (-35),
--- gefolgt von einem Komma und der Anzahl der betroffenen Zeilen
--- in der Quelldatei (9), gefolgt von der Startzeilennummer in der
--- Zieldatei (+35) und der dort betroffenen Zeilenanzahl.
--- Gefolgt von @@ und einer groben Kontextinformation.
@@ -35,9 +35,8 @@ define([
--- Der aktuelle Code vor den gewünschten Änderungen.
some code
--- Die ersten Änderungen. Es werden 3 Zeilen entfernt.
- if (something) {
- console.log(test);
- }
--- Der neue Stand der Datei. Es werden an der Stelle
--- zwei neue Zeilen eingefügt.
+ /* some comment */
+ newmethod();
--- Gleichbleibender Code nach den Änderungen zur Orientierung.
some code
Node Modules patchen mit patch-package
Damit manuelle Änderungen an Dateien aus Abhängigkeiten einfach in eine .patch
-Datei überführt und später jederzeit angewendet werden können, nutzen wir zum Beispiel für Node.js-Projekte patch-package
.
Für Composer-Pakete gibt es composer-patches.
Im Grunde machen beide Konzepte genau das, was das native patch
von vielen Betriebssystemen macht. Es werden anhand einer patch-Datei entsprechende Änderungen auf Dateisystem-Ebene durchgeführt.
Für die Verwendung von patch-package
muss dieses zunächst als devDependency dem Projekt hinzugefügt werden:
yarn add --dev patch-package postinstall-postinstall
oder mit npm
:
npm i --dev patch-package
Damit nach der Installation von Paketen (npm install
oder yarn install
) lokale Patches angewendet werden, muss patch-package
bei den Scripten in der package.json eingerichtet werden
"scripts": {
"postinstall": "patch-package"
}
Wenn wir zum Beispiel Änderungen am Package lodash
vorgenommen haben, führen wir folgenden Befehl aus:
yarn patch-package lodash
patch-package
installiert dann nochmal die Abhängigkeit in einem temporären Ordner, vergleicht diesen mit dem der geänderten Abhängigkeit und erstellt daraus einen Diff bzw. eine .patch
-Datei im Ordner patches
und wendet diese dann darauf an.
Mit dem Ausführen von patch-package
bzw., wenn über npm oder yarn Änderungen an node_modules
durchgeführt werden (update / upgrade, install / add, remove /uninstall) werden die Patches angewendet.
Es ist dann hilfreich die Patches irgendwo zu sammeln und bei mehreren Projekten wiederzuverwenden. Ich habe hierzu zum Beispiel ein eigenes Projekt auf GitHub.