ftblog

:: widerstand zwecklos ::
email jabber gpgkey
hackergotchi

October 02, 2007

format-patch+send-email

Filed under: computer -- 17:22

Beim distributiven SCM Ansatz hat man prinzipiell (mindestens) zwei
Möglichkeiten einem Projekt die eigenen Veränderungen/Verbesserungen zukommen zu
lassen. Man kann einen git-daemon starten (was trivial ist), oder man schickt
die eigenen Commits per Email an die Maintainer des Projekts.

Letzteres ist eine sehr beliebte Methode, da man dem Projekt so die einfache
Möglichkeit gibt, den Code den man verbrochen hat nachzusehen und wenn nötig zu
kommentieren. Code Review, eben.

git unterstützt einen beim Austausch von Patches deshalb auf sehr angenehme Art
und Weise. Und damit meine ich nicht nur den Absender, sondern auch den
Empfänger, der die empfangenen Patches gegebenenfalls einpflegen muß.

Machen wir uns mal eben einen Spielplatz, zum probieren:
% mkdir /tmp/git_test ; cd /tmp/git_test
% mkdir hello ; cd hello
% cat > hello.c
#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char *argv[])
{
    (void)printf("Hello world!\n");
    return EXIT_SUCCESS;
}
% git init
Initialized empty Git repository in .git/
% cat >> .git/config
[user]
    name = Frank Terbeck
    email = ft@bewatermyfriend.org
% cat > .gitignore
.*
!.gitignore
*~
core
core.*
*.o
hello
% git add .
% git commit -m 'Initial commit'
Created initial commit 0641529: Initial commit
 2 files changed, 16 insertions(+), 0 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 hello.c

So, machen wir davon einen Clon, um zu simulieren, daß da jemand in einem
eigenen Repository an unserem Projekt arbeitet. Und wir machen ein paar
Commits zum spielen (in einer eigenen Branch, natürlich. In der Branch, mit der
man ein anderes Repository tracked zu basteln, ist in fast allen Fällen eine
sehr schlechte Idee):
% cd /tmp/git_test
% git clone hello hello_clone
Initialized empty Git repository in /tmp/git_test/hello_clone/.git/
0 blocks
% cd hello_clone
% cat >> .git/config
[user]
    name = Joe 'dev' User
    email = jdu@bewatermyfriend.org
% git checkout -b greatfeature
Switched to a new branch "greatfeature"
% cat > Makefile
BINARY=hello
SOURCE=hello.c

all: binary

clean:
        rm -f *.o core core.[0-9]* $(BINARY) *~

binary:
        cc -o $(BINARY) $(SOURCE)
% git add Makefile
% git commit -m 'Adding Makefile'
Created commit b2b1908: Adding Makefile
 1 files changed, 10 insertions(+), 0 deletions(-)
 create mode 100644 Makefile
% ed hello.c
138
/^{$/
{
a
    (void)printf("Hi mom!\n");
.
+
    (void)printf("Hello world!\n");
s/Hello/Oh, and hello sick sad/
w
186
q
% git commit -a -m 'Changed output'
Created commit 4084fed: Changed output
 1 files changed, 2 insertions(+), 1 deletions(-)
% git log | git shortlog
Frank Terbeck (1):
     Initial commit

Joe 'dev' User (2):
     Adding Makefile
     Changed output

Uhm, und wie drücken wir das nun dem Author auf? Damit der das mal reviewen
kann...
% git format-patch -n -2
0001-Adding-Makefile.patch
0002-Changed-output.patch

Das '-n' sagt 'format-patch', es soll doch bitte '[PATCH n/m] Subject' an Stelle
von '[PATCH] Subject' im Subject: Header verwenden (was eine gute Idee ist,
besonders, wenn es sich um eine ganze Reihe Patches handelt). '-2' bedeutet, wir
wollen Patches zu den letzten zwei Commits haben, die wir gemacht
haben.

Da wir in einer eigenen Branch sind, hätten wir schlauerweise auch
'git format-patch -n master' machen können, um patches zu allen Commits zu
generieren, die in der 'greatfeature' Branche sind, aber nicht in 'master'.

Wenn man sich nun diese patches ansieht, dann bemerkt man, das diese Dateien
fertige mbox files sind. Ziemlich schick, um das per Mail zu
verschicken. Vielleicht sollten wir noch ein zwei Sachen einfügen:

git edit patch 0

Nun könnte man das Ganze in den Mailclient seiner Wahl laden und wegschicken.
Allerdings, ist das alles schon ziemlich das, was man wegschicken will, und git
hat da etwas, daß einem das Verschicken abnimmt (hier sende ich an mich selbst,
es ist ja nur ein Test):

% git send-email --to ft@bewatermyfriend.org *.patch

'git send-email' kennt auch einen --dry-run Schalter. Den sollte man gerade bei
den ersten Sendeversuchen benutzen. Er führt dazu, daß das Programm alles macht,
was es sonst auch macht, nur das abschliessende Senden macht es nicht.

Aber es werden einem dann sicherheitshalber so oder so noch ein paar Fragen
gestellt:

git send email 0

Die erste Frage, erklärt sich von selbst.
Die zweite sollte man mit ja beantworten (was auch der Wert ist, der bei einfach
nur ENTER angenommen wird), denn sollte man viele Patches verschicken, so
trudeln diese beim Empfänger als Thread ein. Das hilft Übersicht zu halten. Das
sollte man wirklich nur abschalten, wenn der Empfänger das ausdrücklich wünscht.

Nun schaue ich in meine Mailbox und speichere den empfangenen Thread in eine
eigene mbox, sagen wir mal '~/jdu.patches'. Und um diese Patches einzupflegen,
kann man 'git am' benutzen (normalerweise würde ich das in einer seperaten
Branch machen, aber hier der Einfachheit halber direkt in 'master'):

% cd ../hello ;: ja, ersmal zurueck in das "upstream-repository"
% git am < ~/jdu.patches

Applying Adding Makefile

Wrote tree de4ee65ab8b5d31ad4f3bb2be2503f2cb04627bb
Committed: 9307ec6a6b67a804b90d69d5141b91d7fb2e1f00

Applying Changed output

Wrote tree 92991631e9c710388ed424b9a8f924ae31ff1f4a
Committed: a8feab9577bc614bbe749116aea5f25b791edfb2
% git log | git shortlog
Frank Terbeck (1):
     Initial commit

Joe 'dev' User (2):
     Adding Makefile
     Changed output

Ja, das macht auch gleich entsprechende Commits.
So, nun kann der Patch submitter die Änderungen vom Upstream in seine 'master'
Branch pullen, und seine 'greatfeature' Branch wieder löschen (denn die ist ja
nun unnötig):

% cd ../hello_clone
% git checkout master
Switched to branch "master"
% git pull
remote: Generating pack...
remote: Done counting 8 objects.
Result has 6 objects.
Deltifying 6 objects...
 100% (6/6) done/6) done
Total 6 (delta 1), reused 0 (delta 0)
Unpacking 6 objects...
 100% (6/6) done
* refs/remotes/origin/master: fast forward to branch 'master' of /tmp/git_test/hello/
  old..new: 0641529..a8feab9
Updating 0641529..a8feab9
Fast forward
 Makefile | 10 ++++++++++
 hello.c | 3 ++-
 2 files changed, 12 insertions(+), 1 deletions(-)
 create mode 100644 Makefile
% git branch -D greatfeature
Deleted branch greatfeature.
% make
cc -o hello hello.c
% ./hello
Hi mom!
Oh, and hello sick sad world!

Ich glaube nicht, daß das hier viel einfacher zu machen ist. Weder für den
Sender, noch für den Empfänger. Also nichts für Masochisten. :-)
Nur immer schön dran denken, im '[user]' Abschnitt der .git/config 'name' und
'email' passend zu setzen (oder global in ~/.gitconfig).

Siehe git-format-patch(1) sowie git-send-email(1) und git-config(1).

Powered by zblog
valid css | valid xhtml | utf-8 encoded | best viewed with anybrowser