Seit einiger Zeit bin ich auf das Verteilte Versionskontrollsystem Mercurial umgestiegen. Es bietet einige Vorteile gegenüber altbekannten Systemen wir z.B. CVS. Aber darauf will ich hier nicht eingehen, sondern einige Tipps und Tricks vorstellen, die den täglichen Umgang mit hg vereinfachen.
Push und Update des Ziels in einem
Mit hg push
werden die Änderungen des eigenen Repositories in das Eltern-Repo hochgeladen. Dort werden die Änderungen aber nur im Repository eingetragen, das Arbeitsverzeichnis wird aber nicht aktuallisiert. Dies muss normalerweise per Hand mit einem hg update
im entsprechenden Verzeichnis erfolgen. Beim Pull-Befehl gibt es den Schalter -u, der ein Update nach dem Pull ausführt leider gibt es das nicht für das Push-Kommando.
Aber es gibt zwei Möglichkeiten, um diesen Schritt einzusparen (und vor Allem nicht zu vergessen):
Ausführen von Push und Update in einem Befehl
Man kann bei Linux & Co. die Ausführung von mehreren Kommandos auf einer Zeile bewirken, in dem man die Kommandos mit „&&“ verbindet. Außerdem kann man bei hg
über den Parameter -R
ein Repository angeben, in dem der Befehl ausgeführt werden soll. Somit lässt sich der Push und das Update des Ziel-Repositories verbinden:
hg push && hg -R pfad_zum_ziel_repository update
Dazu muss man aber den Pfad des Ziels kennen. Dies lässt sich mit hg path
ermitteln. Es spricht aber auch nichts dagegen, das direkt auf der Kommandozeile zu integrieren:
hg push && hg -R `hg path | awk -F = '{ print $2; }'` update
Am Besten legt man sich einen Alias dafür an, in dem man z.B. folgendes in die .bashrc einträgt:
pushup () { hg push && hg -R `hg path | awk -F = '{ print $2; }'` update ; }
Dann braucht man nur noch pushup
eingeben, um ein Push mit nachfolgendem Update des Eltern-Repository zu machen.
Automatisches Update bei jedem Push
Unter 4.15. Any way to ‚hg push‘ and have an automatic ‚hg update‘ on the remote server? in den Mercurial-FAQs ist ein weiterer Weg beschrieben, wie man erzwingt, das bei einem Push auch ein Update des Ziels erfolgt. Dieses Verfahren hat aber aus meiner Sicht zwei Nachteile:
- Es wird immer ein Update gemacht, man kann es nicht „mal eben“ ausschalten. Bei der oben beschriebenen Lösung kann man immer den original
hg push
Befehl ausführen, wenn man gerade nicht will, dass ein Update durchgeführt wird.
- Die Änderung wirkt nur in dem Repository, in dem es in die hgrc eingetragen wurde. Arbeitet man in einem anderen Repository (z.B. eines anderen Projektes), in dem diese Änderung nicht durchgeführt wurde, kann das zu Verwirrungen führen, wenn man gewohnt ist, dass ein Push auch ein Update auslöst.
Die beschriebene Lösung über Hooks hat natürlich auch Vorteile (z.B. kann wirklich keiner das Update vergessen) und schlussendlich muss jeder selbst entscheiden, welchen Weg er beschreiten möchte.
Gibt es Unterschiede zwischen Repository und Working-Directory?
Klar, wenn man selbst Änderungen durchgeführt hat, kann man das über hg status
erkennen. Was aber, wenn man ein hg pull
oder ein hg push
auf das Repository ausführt hat (Es kann ggf. auch jemand anderes ein Push auf „mein“ Repository gemacht haben, wenn er die Rechte dazu hat)? Dann hilft ein hg status
nicht weiter. Ob es Unterschiede gibt, kann man aber mit
hg diff -r tip
herausfinden. Will ich nur wissen ob und welche Dateien betroffen sind, verwende ich
hg diff -r tip | grep '^diff'
Gibt es Änderungen im Eltern-Repository?
Auch hier gibt hg status
keine Auskunft. Aber mit hg incoming
(oder kurz: hg in
erfahren wir, was es an Änderungen gibt, die bei einem Pull übertragen würden. Will ich wissen, welche Dateien sich ändern, setze ich den Schalter -v
hinten an.
Ein Verzeichnis mit allen Unterverzeichnissen hinzufügen
Führt man hg add ./images/*
aus, so werden nur die Dateien im Verzeichnis ./images hinzugefügt, nicht aber die Dateien, die sich in weiteren Unterverzeichnissen tummeln. Hier kann man sich mit find
helfen:
hg add `find ./images -type d -printf '%p/* '`