Tag Archives: Versionsverwaltung

Git unter Windows

Ganz ehrlich, ich hab die Schnauze voll von Windows. Es begann damit, dass ich mehrere Tage gebraucht habe, um Qt 4.8.x selbst zu kompilieren, weil die pre-built Binaries mit einem alten MinGW mit GCC 4.4.x gebaut wurden, dieses aber nicht mit Qt mitgeliefert wird. MinGW selbst stellt aber keine älteren Releases bereit und wegen ABI-Änderungen bei GCC lässt sich Qt (GCC 4.4) nicht mit aktuellem MinGW (GCC 4.8) zusammen nutzen. Das allein schon war frustrierend genug, aber es tauchen dann ja noch so Schwierigkeiten auf, wie dass der Snakeoil Virenscanner selbst kompilierte Software hart löscht. Jetzt habe ich endlich ein Qt und dann beschwert sich CMake noch lange vor dem Build der Anwendung, dass es ein “sh” im PATH gefunden hat. Git für Windows bringt das mit, wozu auch immer. Dachte ich, schauste mal, ob das unbedingt nötig ist, aber die Git-GUIs für Windows brauchen das und auch sonst ist das mit den GUIs für Git unter Windows höchst schmerzhaft. Eine Liste gibt es zwar, aber das ist alles unbrauchbar:

GitHub for Windows
Verbirgt große Teile der Komplexität von Git, ist damit für gewisse Workflows unbrauchbar und arbeitet, oh Wunder, nur mit GitHub.
Git Extensions
Ist nicht plattformunabhängig und installiert mir Dinge mit, die ich schon habe.
git-cola
Braucht erstmal noch Python und PyQt und letzteres wiederum bringt im Binary-Installer gleich wieder ein ganzes Qt mit. Was hatte ich noch gleich selbst kompiliert?
GitEye
Ist ein komplettes Eclipse, für Git, also riesengroß, nur für ein Versionsverwaltungssystem. Irre.
SmartGit
Nicht frei.
SourceTree
Braucht mindestens Windows 7.

Dann wäre da noch TortoiseGit, aber das ist nur ein Fork von dem für Subversion super geeigneten TortoiseSVN und dementsprechend ungeeignet für einen Git-Workflow. Git ist halt kein zentralisiertes Versionsverwaltungssystem wie CVS, wie soll ich dafür dann das selbe Interface gebrauchen können?

Bei Mercurial hat man wenigstens ein schönes plattformunabhängiges GUI in Qt geschrieben. Das heißt zwar auch TortoiseHg, hat aber von der Bedienung her kaum was mit den zuvor genannten gemein und spült mir auch keine zusätzliche kaputte Shell auf meinen Rechner.

Hölle, ist das alles broken. Ich will mein Linux zurück. :-/

Ach so ja, das Problem mit CMake lässt sich übrigens lösen, indem man das CMake-GUI mit einem sauberen PATH startet, bspw. mit einer Batch-Datei cmake-gui.bat:

cd "C:\Programme\CMake 2.8"
PATH=C:\MinGW\bin;C:\Qt\Qt4.8.5-x86\bin
"C:\Programme\CMake 2.8\bin\cmake-gui.exe"

Farbige, seitenweise Diffs mit Mercurial

Bei der Mitarbeit an verschiedenen Projekten ist man heutzutage beinahe schon gezwungen sich mit verschiedenen Versionsverwaltungssystemen auseinanderzusetzen. Ich selbst benutze am liebsten Mercurial, aber es gibt auch Projekte, wo Git oder Subversion benutzt werden. Alle haben ihre Vor- und Nachteile aber so gewisse Dinge, die das eine per default macht, hätte man gern auch im anderen und bei einigen Dingen bekommt man das sogar hin.

Ein wirklich praktisches Feature von Git ist beispielsweise, dass es bei einem `git diff` den Output farbig und im Pager darstellt. Um dieses Verhalten in Subversion nutzen zu können, kann man ein externes Skript nutzen, das ich letztens im Netz gefunden habe: Color highlighted diffs with git, svn and cvs. Für Mercurial hab ich mich gerade nochmal selbst auf die Suche gemacht und folgende Lösung gefunden:

Im Grunde muss man nur die beiden Erweiterungen color und pager aktivieren und konfigurieren. Das sieht bei mir in der ~/.hgrc jetzt wie folgt aus:

[extensions]
color =
pager =

[pager]
pager = LESS='FSRX' less

Die Aktivierung der Extensions ist selbsterklärend, die Optionen habe ich so von der Wikiseite zur pager-Extension übernommen bzw. über `man less` nochmal nachgelesen. Wichtig hier ist auf jeden Fall das ‘R’, damit die Farbcodes von less auch interpretriert werden.

Automatische Keyword-Ersetzung mit Mercurial

In der Diskussion zu CRE130 über verteilte Versionsverwaltungssysteme kam die Frage auf, ob man Mercurial für die Bearbeitung von LaTeX-Files nutzen und dort dann vielleicht sogar eines der Pakete rcs, rcsinfo, rcs-multi, svn, svninfo, svn-multi oder vc verwenden kann. Ersteres ist kein Problem. Selbstverständlich kann man mit Mercurial seine LaTeX-Dokumente versionieren.

Die automatische Ersetzung von sogenannten Keywords, wie man das von RCS, CVS oder Subversion kennt, lässt sich bei Mercurial über die Erweiterung Keyword Extension realisieren, die bei Mercurial gleich dabei ist. Damit das möglicherweise mit einem der oben genannten LaTeX-Pakete zusammenspielt, beschreibe ich nun, wie man die Keywords denen von Subversion maximal ähnlich aussehen lässt.

Zunächst muss man die Erweiterung aktivieren. Das macht man am besten nicht global sondern einzeln im Repository, indem man im Repo in die Datei .hg/hgrc folgendes einfügt:

[extensions]
keyword =

Auf welche Dateien die automatische Ersetzung angewendet wird, bestimmt man in einem weiteren Abschnitt, hier z.B. für alle Dateien mit der Endung .txt in allen Unterordnern des Repositorys:

[keyword]
**.txt =

Die Ausgestaltung der Keywords kann man nun mit der Template Engine (in anderem Zusammenhang in Kapitel »Customizing the output of Mercurial« des großartigen Mecurial Buchs beschrieben) von Mercurial selbst vornehmen. Es gibt zwar default Keywords, aber in der .hg/hgrc definiert man die besser selbst. Meine aktuellen Einstellungen sehen wie folgt aus:

[keywordmaps]
Author = {author}
Date = {date|isodate}
Id = {file|basename} {rev}:{node|short} {date|isodate} {author|user}
Revision = {rev}:{node|short}

In einer Testdatei führt das dann zu folgendem Ergebnis bei der Ersetzung:

$Author: Alexander Dahl <alex@antiblau.de> $
$Date: 2009-08-13 10:43 +0200 $
$Id: bar.txt 1:986b794ecbb1 2009-08-13 10:43 +0200 alex $
$Revision: 1:986b794ecbb1 $

Um das dem Output von Subversion noch ähnlicher zu machen, könnte man den Teil für die Revision sogar noch auf {rev} abkürzen. Hier ist allerdings zu beachten, dass die Revisionsnummern von Mercurial nicht global eindeutig sind, sondern nur für das jeweilige Repository gelten.

HowTo: Migration von Subversion Repositories mit eisfair

eisfair-2 steht vor der Tür, ich erwähnte es bereits im letzten Jahr und auch dieses Jahr anlässlich des LinuxTag. Da es kein Upgrade von eisfair-1 auf eisfair-2 geben wird, muss man die Kiste mehr oder weniger von Hand migrieren. Wie man seine Subversion-Repositories umzieht, beschreibe ich in diesem Artikel.

Falls aktiv und häufig mit den Repositorys gearbeitet wird, sollte der erste Schritt darin bestehen, die Schreibrechte auf dem alten Server zu entziehen. Das einfachste ist, in der Subversion-Konfiguration die Variablen SVN_REPOS_?_ANON_ACCESS und SVN_REPOS_?_AUTH_ACCESS für das umzuziehende Repository auf ‘read’ oder auf ‘none’ zu setzen.

Dann folgt das Backup des alten Repositorys. Dies sollte man an dieser Stelle manuell anstoßen, weil man nicht sicher sein kann, dass nicht noch jemand nach dem letzten automatischen Backup was eingecheckt hat. Dazu wählt man im Setup-Menü den entsprechenden Punkt für das Backup und im folgenden Dialog aus einer Liste das entsprechende Repository. Danach läuft der Dump vom Repository durch. Wenn das abgeschlossen ist, wird beim Subversion Paket ab 0.5.0 dann der Pfad und Name vom soeben erstellten Backup angezeigt, den man sich merken sollte, um zu wissen, welche Datei man gleich auf den Zielrechner zu kopieren hat. Bei älteren Paketversionen muss man im Setup-Menü nochmal den Menüpunkt ‘List backup files’ auswählen. Das grad erstellte Backup steht wahrscheinlich ganz oben, im Zweifelsfall schaut man auf Datum und Uhrzeit, die im Dateinamen mit drin stehen.

Der nächste Schritt besteht darin, die Backupdatei auf den Zielrechner zu kopieren, auf dem man bereits das Subversion-Paket installiert hat. Um das Backup über das Setup-Menü wieder einspielen zu können, muss der Zielpfad für die Kopieraktion der in SVN_BACKUP_TARGET angegebene sein. Außerdem sollte man ein neues leeres Repository einrichten, in das gleich das Backup eingespielt wird.

Aus dem Setup-Menü des Subversion-Pakets wählt man dann den Punkt ‘Restore repository’. Aus der Liste wählt man das soeben neu erstellte leere Repository. Das war es schon. Jetzt nur noch den Nutzern die neue Adresse mitteilen und fröhlich mit dem umgezogenen Repository weiter arbeiten. Das ganze nochmal in Kürze:

  • altes Repo auf dem Quellrechner deaktivieren oder wenigstens die Schreibrechte entziehen, nicht löschen natürlich!
  • setup -> Administration of services -> subversion administration -> Subversion Administration Tools -> Subversion backup and restore -> Backup repository
  • gewünschtes Repo auswählen
  • bei Paket vor 0.5.x: List backup files, entsprechende Datei steht wahrscheinlich ganz oben, auf die Zeit achten, um von cron-generierten zu unterscheiden, hier: /mnt/data2/backup/svn/repos1-2008-09-24-095600.backup.bz2
  • ansonsten angezeigten Dateinamen des Backup kopieren
  • auf den Zielrechner kopieren in das Verzeichnis was dort bei SVN_BACKUP_TARGET angegeben ist
  • neues Repo anlegen auf Zielrechner
  • Restore repository: richtiges Backup-File aus der Liste wählen
  • das neu erstellte Repo aus der Liste wählen

Alte Revisionen wiederherstellen mit Subversion

Im täglichen Umgang mit Subversion passiert es, dass man Dateien eincheckt, die man dann doch eigentlich nicht commiten wollte. Zum Glück kann man alte Revisionen wiederherstellen, dafür hat man ja das Versionsverwaltungssystem, man muss nur wissen wie.

Die erste Idee: revert – das funktioniert nicht, weil revert nur Änderungen an der lokalen Working Copy rückgängig macht, nach dem Commit kann revert nichts mehr ausrichten.

Die zweite Idee: update auf die ursprüngliche Version. Dann hat man in der Working Copy zwar zunächst mal die alte Version liegen. Man kann sie aber nich direkt commiten, weil Subversion sie für aktuell hält. Das ist sie im Grunde auch, nur halt in einer vorherigen Revision. Lokale Änderungen gibt es in dem Sinne nicht an der Datei. Bei Binärdateien kommt man an dieser Stelle nicht weiter, wenn man nicht jedesmal wieder ein update auf die alte Revision machen will.

Die dritte Idee: ins Handbuch schauen. Das exzellente Subversion-Buch hat natürlich auch zu dieser Problematik die passenden Tipps parat: Undoing Changes. (Wir arbeiten hier noch mit Subversion 1.4, daher der Link ins »alte« Buch.) Was auf den ersten Blick überraschend klingt: merge ist die Lösung für das Problem. Der Trick ist, dass wir dieses Mal rückwärts mergen. Dadurch gelangt die ältere Revision wieder in die Working Copy und nachdem man kontrolliert hat, ob damit alles stimmt, kann man die erneut commiten.

Genug der Vorrede, ich zeige den Vorgang mit dem Kommandozeilen-Client und mit TortoiseSVN am Beispiel. Ich habe hier eine Binärdatei driftcompgui.fig, die ich zuletzt in Revision 297 korrekt eingecheckt habe. In Revision 300 habe ich versehentlich eine falsche Version der Datei eingecheckt und möchte jetzt wieder die Version aus Revision 297 haben. Auf der Kommandozeile sieht das recht einfach aus (mit anschließendem Screenshot der Ausgaben):

svn merge -c -300 driftcompgui.fig

Wie man sieht liegt die Datei nun geändert in der Working Copy und zwar in der gleichen Version wie in Revision 297. Jetzt kann man die so einchecken oder noch weiter damit arbeiten. Bei TortoiseSVN erschließt sich diese Funktion aus dem GUI eher überhaupt nicht. Ich zeige zunächst mal den entscheidenden Screenshot und erkläre dann nochmal:

Hier wählt man zunächst im Feld »From:« die gewünschte Datei aus und klickt »HEAD Revision« an. Das ist sozusagen der Startpunkt des Rückwärts mergens. Bei »To:« natürlich »Use “From:” URL« auswählen, da es um die selbe eine Datei geht. Als Ziel Revision gibt man hier die an, die man wiederherstellen will, in meinem Fall 297. Jetzt kann man ohne weiteres auf »Merge« klicken und dann die Datei in der Working Copy untersuchen. Sollte irgendetwas nicht stimmen, kommt man mit revert wieder zur HEAD Revision, da wie bei jedem anderen Merge kein automatischer Commit passiert sondern die Änderungen des merge nur in der Working Copy landen. Wenn alles ok ist, kann man commiten und hat danach wieder die alte Version der Datei im HEAD des Repository.

CLI siegt

Spontane Erkenntnis: Ich nutze lieber den Kommandozeilenclient als die Shell-Extension im Kontextmenü – jedenfalls wenn es um Subversion geht. Gerade Routineaufgaben wir update und commit gehen damit einfach schneller.

Mögliche Erklärung: In der KDE kommt man aus dem Dateimanager per F4 in ein Konsolenfenster mit dem aktuellen Verzeichnis. Dort muss ich dann nur noch svn up eingeben, mit das Ergebnis anschauen und die Konsole mit Strg+D wieder schließen. Das geht wesentlich schneller, als mit der Maus im Kontextmenü die entsprechende Option zu suchen.

Die HCI-Community spricht hierbei von habit, also der Gewohnheit beziehungsweise Routine. Während man bei der Mausbedienung zuerst den Mauszeiger suchen muss, um ihn dann auf die richtige Position im Dateimanager und im Kontextmenü zu navigieren, ist die Position der Tasten fest, die Tastaturbedienung bedarf also wesentlich weniger Planung und fördert daher eher ein routiniertes Vorgehen. Letztendlich entlastet das das Gehirn und wird deshalb als energiesparende Maßnahme bevorzugt. Aber wer gern Shortcuts benutzt, kennt das ja … 8)

Nachtrag: Da war ich wohl etwas eilig und hab die Abkürzungen nicht erklärt…

CLI = Command Line Interface; eine Form von Kommandozeile, entweder auf der Konsole oder in ein Programm eingebettet.

HCI = Human-Computer-Interaction oder Human-Computer-Interface, also die Schnittstelle beziehungsweise Interaktion zwischen Mensch und Computer.

Branches und Merges mit Subversion 1.5

Nachdem letzte Woche der RC 5 von Subversion 1.5 veröffentlicht wurde, beschreibt Ben Collins-Sussman heute in seinem Blog ganz kurz das Feature von Subversion 1.5, auf das viele warten. Subversion 1.5 behält selbst ein Auge auf Branches und Merges und macht das Arbeiten mit Branches damit um einiges leichter. Er demonstriert dies an einem beispielhaften Arbeitsablauf:

1. Make a branch for your experimental work:

$ svn cp trunkURL branchURL
$ svn switch branchURL

2. Work on the branch for a while:

# ...edit files
$ svn commit
# ...edit files
$ svn commit

3. Sync your branch with the trunk, so it doesn’t fall behind:

$ svn merge trunkURL
--- Merging r3452 through r3580 into '.':
U button.c
U integer.c

$ svn commit

4. Repeat the prior two steps until you’re done coding.
5. Merge your branch back into the trunk:

$ svn switch trunkURL
$ svn merge --reintegrate branchURL
--- Merging differences between repository URLs into '.':
U button.c
U integer.c

$ svn commit
6. Go have a beer, and live in fear of feature branches no more.

Wenn man bedenkt, wie aufwändig manuelles Merging bei Subversion vorher war, könnte das jetzt kaum einfacher sein. Man musste in den Commit-Messages die Revisionsnummern mitloggen und aufpassen auch ja die richtigen Sachen von einem Branch in den anderen zu tun. Jetzt brauch man sich um die Revisionsnummern nicht mehr kümmern, das wird alles wegfallen, super coole Sache!

svnsync und relocate

Ich spiegel bei mir zu Haus ein paar Subversion-Repositories von Software, die mir sehr wichtig ist oder wo ich persönlich schon mal in den Quellcode geschaut oder auch mal einen Patch eingereicht habe. Das ganze geschieht mit svnsync und einem kleinen Shell-Skript, das per Cronjob alle acht Stunden läuft. In den letzten Tagen bekam ich Fehlermeldungen, dass ein Quell-Repository nicht mehr auffindbar war. Eine kurze Recherche ergab, dass der anonyme Zugriff per https eingestellt wurde und nur noch Zugriff per http möglich ist, was de facto einer anderen URL gleich kommt, quasi einem Umzug des Repos. Bei einer normalen Working Copy von Subversion hat man kein Problem, da macht man in einem solchen Fall

svn switch --relocate https://svn.quelle.foo/svn/trunk 
    http://svn.quelle.bar/svn/trunk

und fertig. Bei svnsync gestaltet sich das etwas schwieriger. Die URL des Quellrepos wird dort in den Properties der Revision 0 des Zielrepos gespeichert, so dass man bei der Synchronisation nur noch die Ziel-URL angibt. Ein “Relocate” muss dann durch eine Änderung des entsprechenden Properties geschehen, in meinem Fall sah das dann so (ähnlich) aus:

svn ps svn:sync-from-url --revprop -r 0 
    'http://svn.licq.org/svn' https://foo.local/svn/licq-mirror 
    --username syncuser --password syncpass

Man überschreibt also einfach die bisherige Quell-URL mit der neuen, das ist alles, danach einfach wie gewohnt

svnsync sync https://foo.local/svn/licq-mirror 
    --username syncuser --password syncpass

aufrufen und alles funktioniert wie vorher auch, nur eben mit neuer Quell-URL.

Subversion Relocate mit Eclipse und TortoiseSVN

Wir sind vor einigen Tagen mit unserem Projekt IMPULS von Sourceforge auf unseren eigenen, diesen Webserver umgezogen. Das heißt, wir haben nicht nur die Homepage migriert und ein Trac eingerichtet, sondern auch das Subversion-Repo verschoben. Für ausgecheckte Working Copies ist dann ein sogenannte Relocate fällig. In Verbindung mit Eclipse kann man da auf die Nase fallen.

Subversion mit Eclipse ist eigentlich erstmal kein Problem. Es gibt Subclipse und da funktionieren Checkout, Update, Commit usw. wunderbar. Rechtsklick auf auf’s Projekt, »Team« angeklickt und los geht’s – leider ohne Relocate. Wenn ich das jetzt einfach außerhalb von Eclipse machen würde, zerschieße ich mein Projekt, weil in den Projekteinstellungen der Pfad auf’s Repository vermerkt ist. Es gibt aber eine Lösung. Zunächst vergewissern wir uns, welche URL grad für das Projekt angegeben ist:

Subversion Pfad in Projekteinstellungen

Hier ist also noch der alte Pfad des Repos bei Sourceforge eingetragen. Der nächste Schritt in der Punkt »Disconnect« im bereits erwähnten Menü »Team«. Draufklicken und dann kommt folgender Dialog. Dort bestätigt man mit der Option, die Subversion-Dateien zu behalten.

Disconnect im Menü »Team« von Eclipse

Dann kommt das eigentliche Relocate. Das geschieht unter Windows am einfachsten mit TortoiseSVN, wie im folgenden Bild zu sehen ist. Natürlich kann man hier auch die Kommandozeilenversion von Subversion benutzen, wenn man grad kein TortoiseSVN zur Hand hat. Wie das geht, steht im Subversion-Buch.

Relocate mit TortoiseSVN

Der letzte Schritt besteht darin, dem Projekt in Eclipse wieder beizubringen, dass es eigentlich ein mit Subversion verwaltetes ist. Dazu wieder ein Rechtsklick auf das Projekt und im Menü »Team« den Punkt »Share« und dann natürlich »SVN«. Subclipse erkennt, dass es sich bereits um eine korrekte Working Copy handelt und übernimmt den richtigen Pfad aus Schritt drei. Nur noch einmal den folgenden Dialog abnicken und fertig ist die Laube.

Subversion Working Copy Eclipse wieder bekannt machen

Subversion Keywords und Doxygen

Gestern habe ich den Arbeitstag damit verbracht, mir selbst Doxygen näher zu bringen und mein Projekt mit den entsprechenden Kommentaren zu versehen. Laut interner Konvention gehört hier an den Anfang jeder Datei ein für Doxygen formatierter Kommentarblock mit Standardinformationen, wo unter anderem auch spezielle Tags drin stehen, die Subversion beim Commit/Update automatisch aktualisiert. Der dafür relevante Teil sieht jetzt (fast) so aus:

/**
 * \$Revision: 19 $\n
 * \$LastChangedBy: dahl $\n
 * \$LastChangedDate: 2007-08-16 11:04:15 +0200 (Thu, 16 Aug 2007) $\n
 */

Der Grund für diesen Blog-Eintrag ist die Tatsache, dass man das erste Dollarzeichen escapen muss, um in der von Doxygen erzeugten Doku auch tatsächlich diese Tags wiederzufinden. Der Grund dafür wiederum liegt darin, dass Doxygen normalerweise Umgebungsvariablen, die mit dem Dollarzeichen beginnen, expandiert. Das kann man mit gutem Willen aus der Doku zu Doxygen raus lesen. Am Ende der Zeile hab ich dann noch jeweils einen Umbruch gesetzt, damit nicht alle Tags in einer Zeile der Doku landen.

Ein kleiner Schönheitsfehler besteht dabei noch: die Einträge landen genau so, nämlich mit Dollarzeichen und Bezeichner in der Doku. Das Problem hat man bei anderen Projekten auch, die was mit den Tags von Subversion anfangen. Um das noch schicker zu machen, müsste man noch einen Filter für Doxygen schreiben. Wenn da jemand was passendes kennt, bitte mal bei mir melden! ;-)

Update: Mit doxygen 1.6.2 unter WindowsXP und C-Quellcode tritt das Problem nicht mehr auf. Man muss hier nicht mehr die Dollar-Zeichen escapen und doxygen filtert das selbst sauber raus und zeigt es schick formatiert an.