Am Rande der PHP Unconference finde ich nun doch ein paar Minuten, mal wieder hier in meinem Blog einen kleinen technischen Artikel zu veröffentlichen. Nun aber zum Thema.
Ein häufiges Szenario ist, dass man lokal eine Versionsverwaltung in der Entwicklungsumgebung einsetzt, während man im Produktivsystem die Sourcen aber nicht aus dem Versionierungssystems holt, sondern ein komplettes Release hoch lädt. Wenn man jetzt nur einen kleinen Teil der Applikation ändert, geht der Entwickler dazu über die geänderten Files hoch zuladen. Dabei kann es zu diversen Fehlern führen:
- Vergessen einzelner Files
- Produktivsystem wurde dummerweise bereits geändert -> Änderungen gehen verloren
- erzeugt Fehler während der Uploads
- Dateien werden versehentlich an die falsche Stelle geladen und verwaisen
- u.s.w.
Eine Möglichkeit dies zu umgehen ist der Patch. Jeder kennt Ihn, aber nur die Wenigsten wenden dies auch auf Quellcodes an. Wir werden jetzt mit Git, zwei Branches und patch einen Patch erzeugen und einspielen. Im Grunde ist das eine genial einfache Geschichte.
laptop:Manuals nico$ mkdir Patch #Verzeichnis anlegen
laptop:Manuals nico$ cd Patch/ #in dieses Verzeichnis wechseln
laptop:Patch nico$ git init #Git Repository initialisieren
Initialized empty Git repository in /Users/nico/Workspaces/Manuals/Patch/.git/
laptop:Patch nico$ vim index.php #Datein anlegen und Bearbeiten
In die index.php schreiben wir nun folgenden Quellcode:
<?php
echo "Hallo Welt";
Speichern. Datei für Commit hinzufügen und commiten.
laptop:Patch nico$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
# (use "git add ..." to include in what will be committed)
#
# index.php
nothing added to commit but untracked files present (use "git add" to track)
laptop:Patch nico$ git add index.php
laptop:Patch nico$ git commit
[master (root-commit) 1b5b9e7] asdf
1 files changed, 3 insertions(+), 0 deletions(-)
create mode 100644 index.php
laptop:Patch nico$ git status
# On branch master
nothing to commit (working directory clean)
Der Einfachheit halber legen wir einen neuen Branch an, diesen brauchen wir später um den Patch einzuspielen.
laptop:Patch nico$ git branch version1
Wir gehen davon aus, dass der Branch version1 irgendwo produktiv läuft.
Nun wollen wir den Quellcode ändern.
laptop:Patch nico$ vim index.php
<?php
echo halloWelt();
function halloWelt()
{
return "Hallo Welt";
}
Nun noch committen:
laptop:Patch nico$ git add index.php
laptop:Patch nico$ git commit
[master f58e5d6] implement function
1 files changed, 6 insertions(+), 1 deletions(-)
Jetzt geht es daran einen Patch zu erstellen, damit wir dies tun können müssen wir die Revisionsnummern wissen, von welcher Revision auf welche der Patch erstellt werden soll. Zum Glück haben wir nur zwei und können so gesehen hier nicht viel falsch machen ;o)
laptop:Patch nico$ git log --oneline
f58e5d6 implement function
1b5b9e7 init
Der Befehl sagt uns, dass wir den Patch von der Revision 1b5b9e7 auf f58e5d6 erzeugen wollen. Dies tun wir mit folgenden Befehl.
laptop:Patch nico$ git format-patch 1b5b9e7..f58e5d6
0001-implement-function.patch
Schauen wir uns den Inhalt des Patches an:
laptop:Patch nico$ cat 0001-implement-function.patch
From f58e5d66c18c59e0e11e394dbfec0b97c1661783 Mon Sep 17 00:00:00 2001
From: Nico Hofmann mail@nico-hofmann.de
Date: Sat, 25 Sep 2010 19:57:32 +0200
Subject: [PATCH] implement function
---
index.php | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/index.php b/index.php
index f203f7f..742c38f 100644
--- a/index.php
+++ b/index.php
@@ -1,3 +1,8 @@
-echo "Hallo Welt";
+echo halloWelt();
+
+function halloWelt()
+{
+ return "Hallo Welt";
+}
--
1.7.0.2
Kann man verstehen, muss man aber nicht. Wir simulieren jetzt das entfernte System, in dem wir zurück auf den Branch version1 wechseln.
laptop:Patch nico$ git checkout version1
Switched to branch 'version1'
laptop:Patch nico$ git branch
master
* version1
laptop:Patch nico$ cat index.php
<?php
echo "Hallo Welt";
Wir machen nun den Testlauf für unseren Patch.
laptop:Patch nico$ patch -p 1 --dry-run < 0001-implement-function.patch
patching file index.php
Läuft! Das -p sagt die Verzeichnistiefe vom Patch zum Verzeichnis in dem man sich befindet an.
laptop:Patch nico$ patch -p 1 < 0001-implement-function.patch
patching file index.php
laptop:Patch nico$ cat index.php
<?php
echo halloWelt();
function halloWelt()
{
return "Hallo Welt";
}
Das wars. Der Patch wäre eingespielt! Einen solchen Patch könnte man z.B. auf dem System seines Kunden einspielen, ohne in die oben genannten Fehlerquellen zu tappen.




[...] einen. Nico, ein Co-Author von dev.Talk hat sich an die Arbeit gemacht und ein Tutorial zu “Patches mit Hilfe von Git erstellen und einspielen” auf seinem Blog [...]
git diff reicht doch oder??