Git verfügt über Schnittstellen zu anderen Versionsverwaltungssystemen, die für zwei grundsätzliche Anwendungsfälle von Bedeutung sind:
- 'Bidirektionale Kommunikation'
-
Sie wollen lokal in einem Git-Repository entwickeln, die Veränderungen aber auch in ein externes Repository übertragen bzw. Veränderungen von dort nach Git importieren.
- 'Migration'
-
Sie wollen aus einem bestehenden Repository eines anderen Systems die dort gespeicherte Versionsgeschichte nach Git importieren.
Folgende Schnittstellen bietet Git von Haus aus — alle erlauben beidseitige Kommunikation und vollständige Konvertierung:
- Subversion (
svn
) -
Das Werkzeug
git-svn
bietet alle wesentlichen Subkommandos um mit Subversion-Repositories umzugehen und wird in diesem Kapitel ausführlich behandelt. Das Programm ist in Perl implementiert und verwendet die Perl-Bindings für Git und Subversion. Es wird zusammen mit den Git-Quellen imgit.git
-Repository verwaltet (liegt alsgit-svn.perl
vor). Hinweis: Das Tool heißt zwargit-svn
, wird aber wie üblich mitgit svn <command>
aufgerufen. Die technische Dokumentation finden Sie in der Man-Pagegit-svn(1)
. - Concurrent Versioning System (
cvs
) -
Das Kommando
git cvsimport
bewerkstelligt Import und Abgleich eines CVS-Repositorys — das Pendant istgit cvsexportcommit
. - Perforce (
p4
) -
Mit
git p4
sprechen Sie Repositories des proprietären Systems Perforce an.
Für das Zusammenspiel mit anderen VCS gibt es zudem eine Vielzahl zusätzlicher Werkzeuge und Scripte, die die genannten Kommandos verbessern, erweitern und zum Teil ersetzen. Aber auch Schnittstellen zu weiteren Versionsverwaltungssystemen, wie z.B. Mercurial, werden angeboten. Sollten die in diesem Kapitel beschriebenen Kommandos und Rezepte nicht ausreichen, lohnt sich eine Internet-Recherche. Als ersten Anlaufpunkt empfehlen wir das Git-Wiki.[1]
Neben den unmittelbaren Kommunikationsmöglichkeiten mit anderen Systemen verfügt Git über ein eigenes, simples Plaintext-Protokoll, mit dem Sie die Versionsgeschichte aus einem beliebigen System so übersetzen, dass Git daraus ein Repository erstellt. Für eine detaillierte Beschreibung inklusive Beispiel siehe [sec.fast-import] über 'Fast-Import'.
Im Folgenden geht es um die Handhabung von git-svn
. Wir
zeigen Ihnen, wie Sie Subversion-Repositories konvertieren und wie Sie
es einsetzen, um Änderungen zwischen einem Subversion-Repository und
Git auszutauschen.
Ziel ist es, die Versionsgeschichte aus einem Subversion-Repository in ein Git-Repository zu übertragen. Bevor Sie starten, müssen Sie Vorbereitungen treffen, die je nach Projektgröße einige Zeit in Anspruch nehmen. Gute Vorbereitung hilft Ihnen aber, Fehler von vornherein zu vermeiden.
Folgende Informationen sollten Sie zur Hand haben:
-
Wer sind die Autoren? Wie lauten ihre E-Mail-Adressen?
-
Wie ist das Repository strukturiert? Gibt es Branches und Tags?
-
Sollen Metadaten zu der Subversion-Revision in den Git-Commits abgelegt werden?
Später werden Sie das Kommando git svn clone
aufrufen. Die
Antworten auf die oben genannten Fragen entscheiden, mit welchen
Optionen und Argumenten Sie dies tun.
Tip
|
Unsere Erfahrung hat gezeigt, das es selten bei nur einem
Konvertierungsversuch bleibt. Wenn das Subversion-Repository nicht
schon lokal vorliegt, lohnt es sich auf jeden Fall eine lokale Kopie
anzulegen — dadurch müssen Sie, bei einem zweiten Versuch, die
Revisionen nicht erneut übers Netzwerk herunterladen. Hierfür können
Sie bspw. |
Subversion nutzt weniger umfangreiche Metadaten zu Autoren als Git;
Revisionen werden lediglich mit einem Subversion-Benutzernamen
gekennzeichnet, und es gibt keinen Unterschied zwischen Autor und
Committer einer Revision. Damit git-svn
die
Subversion-Benutzernamen in für Git typische vollständige Namen mit
E-Mail-Adressen übertragen kann, bedarf es einer sog.
'Authors-Datei':
jplenz = Julius Plenz <[email protected]> vhaenel = Valentin Haenel <[email protected]>
Die Datei, z.B. `authors.txt`, übergeben Sie später mit
--authors-file=
bzw. -A
an git-svn
.
Folgender Einzeiler ermittelt alle Subversion-Benutzernamen und hilft Ihnen, die Datei zu erstellen:
$ svn log --xml | grep author | sed 's_^.*>\(.*\)<.*$_\1_' | \ sort --unique
Geben Sie bei der Konvertierung keine Authors-Datei an (oder fehlt ein
Autor), so verwendet git-svn
den Subversion-Benutzernamen als
Autor. Die E-Mail-Adresse setzt sich aus dem Subversion-Benutzernamen
und der UUID des Subversion-Repositorys zusammen.
Finden Sie im nächsten Schritt heraus, wie das Repository strukturiert ist. Dabei helfen folgende Fragen:
-
Verfügt das Repository über einen sog. 'Trunk' (Hauptentwicklungsstrang), Branches und Tags?
-
Wenn ja, wird das Standardlayout von Subversion (
trunk/
,branches/
,tags/
) eingesetzt? -
Wenn nicht, in welchen Verzeichnissen befinden sich Trunk, Branches und Tags dann?
-
-
Werden nur ein einzelnes oder mehrere Projekte in dem Repository verwaltet?
Folgt das Projekt dem Subversion-Standardlayout
(Standardlayout Subversion), verwenden Sie für die Konvertierung das
Argument --stdlayout
bzw. kurz -s
.
Das Argument --no-metadata
verhindert, dass zusätzliche
Metadaten in die Commit-Message einfließen. Inwieweit das für Ihren
Anwendungsfall sinnvoll ist, müssen Sie selbst entscheiden. Aus
technischer Sicht sind die Metadaten nur notwendig, wenn Sie weiterhin
mit dem Subversion-Repository interagieren wollen. Es kann allerdings
auch hilfreich sein, die Metadaten zu erhalten, wenn Sie bspw. in Ihrem Bugtracking-System die
Subversion-Revisionsnummer verwenden.
Die SVN-Metadaten tauchen jeweils in der letzten Zeile einer Commit-Nachricht auf und haben die folgende Form:
git-svn-id: <URL>@<Revision> <UUID>
<URL>
ist die URL des Subversion-Repositorys,
<Revision>
die Subversion-Revision und <UUID>
('Universally Unique Identifier') eine Art
``Fingerabdruck'' des Subversion-Repositorys. Zum Beispiel:
git-svn-id: file:///demo/trunk@8 2423f1c7-8de6-44f9-ab07-c0d4e8840b78
Wie Sie den Benutzernamen angeben, hängt vom Transport-Protokoll ab.
Für solche, bei denen Subversion die Authentifizierung regelt (z.B. `http`, https
und svn
), nutzen Sie die
Option --username
. Für andere (svn+ssh
) müssen
Sie den Benutzernamen als Teil der URL angeben, also beispielsweise
svn+ssh://[email protected]
.
Ein SVN-Repository im Standardlayout konvertieren Sie mit dem folgenden Aufruf (nachdem Sie eine Authors-Datei erstellt haben):
$ git svn clone <http://svn.example.com/> -s -A <authors.txt> \ --no-metadata <projekt-konvertiert>
Ist das Repository nicht nach dem Subversion-Standardlayout ausgelegt,
passen Sie den Aufruf von git svn
entsprechend an: Statt
--stdlayout
geben Sie explizit den Trunk mit
--trunk
bzw. -T
an, die Branches mit
--branches
bzw. -b
und die Tags mit
--tags
bzw. -t
— wenn beispielsweise mehrere
Projekte in einem Subversion-Repository verwaltet werden (Non-Standard Layout).
Um projekt1
zu konvertieren, würde der Aufruf wie folgt
lauten:[3]
$ git svn clone <http://svn.example.com/> -T trunk/projekt1 \ -b branches/projekt1 -t tags/projekt1 \ -A <authors.txt> <projekt1-konvertiert>
Ein SVN-Repository ohne Branches oder Tags klonen Sie einfach über die
URL des Projektverzeichnisses und verzichten dabei vollständig auf
--stdlayout
:
$ git svn clone <http://svn.example.com/projekt> -A authors.txt \ --no-metadata <projekt-konvertiert>
Sollten mehrere unabhängige Projekte in einem Repository verwaltet werden, empfehlen wir Ihnen, pro Projekt ein eigenes Git-Repository zu erstellen. Git eignet sich – im Gegensatz zu Subversion – nicht, um mehrere Projekte in einem Repository zu verwalten. Das Objektmodell führt dazu, dass die Entwicklungsgeschichten (Commit-Graphen) untrennbar miteinander verschmelzen würden. Wie Sie Projekte aus unterschiedlichen Git-Repositories miteinander ``verknüpfen'', ist in [sec.subprojects] beschrieben.
Ist git svn clone
durchgelaufen, müssen Sie das Repository
meist noch ein wenig nachbearbeiten.
Tip
|
Bei der Konvertierung ignoriert $ git svn create-ignore Die |
Git erzeugt für den Subversion-Trunk sowie die Subversion-Branches und
-Tags spezielle Git-Branches unter remotes/origin
. Sie haben
große Ähnlichkeit mit den Remote-Tracking-Branches, da sie den Zustand
des Subversion-Repositorys abbilden — es sind also quasi
'Subversion-Tracking-Branches'. Sie dienen vor allem der
bidirektionalen Kommunikation und werden bei einer Synchronisation mit
dem Subversion-Repository aktualisiert. Wollen Sie allerdings das
Repository nur konvertieren, haben diese Branches keinen Nutzen mehr
und sollten entsprechend in ``echte'' Git-Branches
umgeschrieben werden (s.u.).
Für den Trunk und jeden Subversion-Branch wird je ein
Subversion-Tracking-Branch
angelegt,[4] und für jedes Subversion-Tag
ebenfalls ein Subversion-Tracking-Branch ('kein' Git-Tag,
s.u.), aber unter remotes/origin/tags
.
Angenommen, das Subversion-Repository hat folgende Subversion-Branches und -Tags:
In diesem Fall erzeugt git svn
folgende Git-Branches:
Das Präfix passen Sie mit der Option --prefix=
an. So
werden zum Beispiel mit der Anweisung --prefix=svn/
alle
konvertierten Referenzen unter remotes/svn/
statt unter
remotes/origin
abgelegt.
Wie schon erwähnt, erzeugt git-svn
für Subversion-Tags
'keine' Git-Tags. Das liegt daran, dass sich Subversion-Tags aus
technischer Sicht kaum von Subversion-Branches unterscheiden. Sie
werden auch mit git svn copy
erstellt und können — im
Gegensatz zu Git-Tags — im Nachhinein verändert werden. Um solche
Aktualisierungen verfolgen zu können, werden Subversion-Tags daher
auch als Subversion-Tracking-Branches dargestellt. Wie auch die
Subversion-Branches, haben diese in einem konvertierten
Repository keinen Nutzen (sondern stiften eher Verwirrung) und
sollten daher in echte Git-Tags umgeschrieben werden.
Wenn Sie die Subversion-Branches und -Tags beibehalten wollen, sollten
Sie die Subversion-Tracking-Branches in Lokale-Git-Branches bzw.
Lightweight-Git-Tags übersetzen. Im ersten Schritt hilft Ihnen
folgendes Shell-Script git-convert-refs
:[5]
#!/bin/sh . $(git --exec-path)/git-sh-setup svn_prefix='svn/' convert_ref(){ echo -n "converting: $1 to: $2 ..." git update-ref $2 $1 git update-ref -d $1 echo "done" } get_refs(){ git for-each-ref $1 --format='%(refname)' } echo 'Converting svn tags' get_refs refs/remotes/${svn_prefix}tags | while read svn_tag do new_ref=$(echo $svn_tag | sed -e "s|remotes/$svn_prefix||") convert_ref $svn_tag $new_ref done echo "Converting svn branches" get_refs refs/remotes/${svn_prefix} | while read svn_branch do new_ref=$(echo $svn_branch | sed -e "s|remotes/$svn_prefix|heads/|") convert_ref $svn_branch $new_ref done
Das Script nimmt an, dass das Repository mit der Option
--prefix=svn/
konvertiert wurde. Die beiden
while
-Schleifen machen Folgendes:
-
Für jeden Subversion-Tracking-Branch, der einem Subversion-'Tag' entspricht, wird ein Git-Tag erzeugt (z.B. `refs/remotes/svn/tags/v1.0` →
refs/tags/v1.0
). -
Für jeden Subversion-Tracking-Branch, der einem Subversion-'Branch' entspricht, wird ein
`echter'' lokaler Git-Branch erzeugt (z.B. `refs/remotes/svn/bugfix
→refs/heads/bugfix
).
Das Script nutzt die Plumbing-Kommandos git for-each-ref
, das
auf den angegebenen Ausdruck passende Referenzen zeilenweise ausgibt,
und git update-ref
, das Referenzen umschreibt und
löscht.[6]
In Konvertierte Branches und Tags vor der Übersetzung und
Konvertierte Branches und Tags nach der Übersetzung sehen Sie, wie das Script
funktioniert. In dem Subversion-Repository existieren der Trunk, ein Branch
feature
sowie das Tag v1.0
. Bei der Konvertierung erstellt
git-svn
drei Branches unter remotes/svn
, wie oben beschrieben.
Das Script git-convert-refs
übersetzt schließlich
remotes/svn/trunk
→ trunk
, remotes/svn/feature
→ feature
und aus remotes/svn/tags/v1.0
wird ein
Lightweight Tag.
Nachdem Sie die Subversion-Branches und Tags umgeschrieben haben,
werden Sie feststellen, dass alle Git-Tags auf ganz kurzen
Abzweigungen `sitzen'' (siehe Tag `v1.0
in der
Konvertierte Branches und Tags nach der Übersetzung
und Konvertierte Git-Tags auf Abzweigungen). Das liegt daran, dass jedes
Subversion-Tag mit einem Subversion-Commit erzeugt wurde. Das
Konvertierungsverhalten von git-svn
ist also prinzipiell korrekt, weil
pro Subversion-Revision ein Git-Commit erzeugt wird – aber für ein
Git-Repository etwas unhandlich: Sie können z.B. nicht git
describe --tags
einsetzen.
Da jedoch, sofern das Subversion-Tag nicht noch nachträglich verändert
wurde, der getaggte Commit den gleichen Tree referenziert wie sein
Vorfahre, können Sie die Tags auf die Vorfahren verschieben. Dabei
hilft folgendes Shell-Script git-fix-tags
[7]:
#!/bin/sh . $(git --exec-path)/git-sh-setup get_tree(){ git rev-parse $1^{tree}; } git for-each-ref refs/tags --format='%(refname)' \ | while read tag do sha1=$(git rev-parse $tag) tree=$(get_tree $tag ) new=$sha1 while true do parent=$(git rev-parse $new^) git rev-parse $new^2 > /dev/null 2>&1 && break parent_tree=$(get_tree $parent) [ "$parent_tree" != "$tree" ] && break new=$parent done [ "$sha1" = "$new" ] && break echo -n "Found new commit for tag ${tag#refs/tags/}: " \ $(git rev-parse --short $new)", resetting..." git update-ref $tag $new echo 'done' done
Das Script untersucht jeden getaggten Commit. Ist unter den Vorfahren
ein Commit, der denselben Tree referenziert, wird das Tag erneuert.
Hat der Commit oder einer seiner Vorfahren selbst mehrere Vorfahren
(nach einem Merge), wird die Suche abgebrochen. In Konvertierte Git-Tags auf Abzweigungen sehen Sie zwei Tags, die in Frage
kommen: v1.0
und v2.0
. Das Tag v1.0
wurde
von Commit C1
aus erstellt und enthält keine nachträglichen
Veränderungen. Das Tag v2.0
hingegen wurde nach seiner
Erstellung von Commit C2
nochmals verändert.
In Tag v1.0
wurde umgeschrieben sehen Sie, wie das Tag
v1.0
von obigem Script auf den Vorfahren verschoben wurde
(weil die Trees gleich sind). Das Tag v2.0
bleibt jedoch an
Ort und Stelle (weil die Trees aufgrund nachträglicher Veränderungen
verschieden sind).
Tip
|
Das Tool
|
Sie sollten noch entscheiden, wie Sie mit der Referenz für den Trunk
(trunk
bzw. git-svn
) umgehen wollen. Nach der
Konvertierung zeigt dieser auf denselben Commit wie master
— von daher können Sie ihn eigentlich löschen:
$ git branch -d trunk
Eventuell befinden sich nach der Konvertierung noch Git-Branches in
dem Repository, die bereits in den master
gemergt wurden.
Entfernen Sie diese mit folgendem Kommando:
$ git checkout master $ git branch --merged | grep -v '^*' | xargs git branch -d
Außerdem können Sie die übrigen Altlasten entsorgen, die sich sowohl
in der Repository-Konfiguration als auch in .git/
befinden:
$ rm -r .git/svn $ git config --remove-section svn $ git config --remove-section svn-remote.svn
Sie sind dann bereit, die konvertierte Geschichte in ein Remote-Repository hochzuladen, um es mit anderen Entwicklern gemeinsam zu benutzen.
$ git remote add <example> <[email protected]:projekt1.git> $ git push <example> --mirror
Subversion-Merges werden von git-svn
anhand der
svn:mergeinfo
-Properties erkannt und als Git-Merges übersetzt — allerdings nicht immer. Es kommt darauf an, welche
Subversion-Revisionen gemergt wurden und wie. Wurden alle
Revisionen, die einen Branch betreffen, gemergt (svn
merge -r <N:M>
), so wird dies durch einen Git-Merge-Commit
abgebildet. Wurden jedoch nur einzelne Revisionen gemergt (via
svn merge -c <N>
), dann werden diese stattdessen einfach mit
git cherry-pick
übernommen.
Für folgendes Beispiel haben wir ein Subversion-Repository
mit einem Branch feature
erstellt, der zweimal
gemergt wird. Einmal als Subversion-Merge, der als Git-Merge-Commit
gewertet wird, und einmal als Subversion-Merge, der als Cherry-Pick
übersetzt wird. Das mit git-svn
konvertierte Resultat ist
unten abgebildet.
Die Commits im Subversion-Repository wurden in der folgenden Reihenfolge gemacht:
-
Standardlayout
-
C1
auftrunk
-
Branch
feature
-
C1
auffeature
-
C2
auffeature
-
C2
auftrunk
-
svn merge branches/feature trunk -c 5
(commitC2
auffeature
) -
svn merge branches/feature trunk -r 3:5
(commitC1
&`C2` auffeature
)
Abschließend ist noch zu erwähnen, dass git-svn
bei weitem nicht das
einzige Tool zur Konvertierung ist. git-svn
leidet oft an Geschwindigkeitsproblemen bei
sehr großen Repositories. In diesem Kontext
werden zwei Tools sehr häufig genannt, die schneller arbeiten: einerseits svn2git
[10]
und auch svn-fe
[11] (svn-fast-export). Sollten Sie bei der Konvertierung auf Probleme stoßen
(z.B. wenn die Konvertierung schon seit mehreren Tagen läuft und noch kein Ende in Sicht ist), lohnt sich der Blick auf die Alternativen.
Das Werkzeug git-svn
kann nicht nur ein Subversion-Repository
konvertieren, es taugt vor allem auch als besserer Subversion-Client. Das heißt, Sie
haben lokal alle Vorzüge von Git (einfaches und flexibles Branching,
lokale Commits und Geschichte) — können aber Ihre Git-Commits aus dem
lokalen Git-Repository als Subversion-Commits in ein
Subversion-Repository hochladen. Außerdem erlaubt es git-svn
,
neue Commits anderer Entwickler aus dem Subversion-Repository in Ihr
lokales Git-Repository herunterzuladen. Sie sollten git-svn
dann einsetzen, wenn eine vollständige Umstellung auf Git nicht
durchführbar ist, Sie aber gerne lokal die Vorzüge von Git nutzen
möchten. Beachten Sie hierbei aber, dass git-svn
eine etwas
eingeschränkte Version von Subversion ist und nicht alle Features in
vollem Umfang zur Verfügung stehen. Vor allem beim Hochladen gibt es
einige Feinheiten zu beachten.
Zunächst eine Zusammenfassung der wichtigsten
git-svn
-Befehle:
git svn init
-
Git-Repository zum Verfolgen eines Subversion-Repositorys anlegen.
git svn fetch
-
Neue Revisionen aus dem Subversion-Repository herunterladen.
git svn clone
-
Kombination aus
git svn init
undgit svn fetch
. git svn dcommit
-
Git-Commits als Subversion-Revisionen in das Subversion-Repository hochladen ('Diff Commit').
git svn rebase
-
Kombination aus
git svn fetch
undgit rebase
, die üblicherweise vor einemgit svn dcommit
ausgeführt wird.
Um das Repository zu beziehen, gehen Sie zunächst so vor wie im
Abschnitt zur Subversion-Konvertierung — erstellen Sie eine
Authors-Datei und ermitteln Sie das Repository-Layout. Dann können
Sie mit git svn clone
das Subversion-Repository klonen,
z.B.:
$ git svn clone http://svn.example.com/ -s \ -A <authors.txt> <projekt-git>
Der Aufruf lädt alle Subversion-Revisionen herunter und erzeugt aus
dem Verlauf ein Git-Repository unter <projekt-git>
.
Tip
|
Das Klonen eines gesamten Subversion-Verlaufs kann unter Umständen
sehr, sehr zeitaufwendig sein. Aus Subversion-Sicht ist eine lange
Historie kein Problem, da der Befehl $ git svn init http://svn.example.com/trunk projekt-git $ cd projekt-git $ git svn fetch -r HEAD Alternativ zu |
Im Rahmen der Konvertierung haben wir beschrieben, wie Sie das
Repository nachbearbeiten. Da Sie in Zukunft weiter mit dem
Subversion-Repository interagieren wollen, ist das hier nicht
notwendig. Außerdem darf die Option --no-metadata
nicht
benutzt werden, weil sonst die Metadaten der Form git-svn-id:
aus der Commit-Message verschwinden und Git die Commits und Revisionen
nicht mehr zuordnen könnte.
Der Aufruf von git-svn
erzeugt diverse Einträge in der
Konfigurationsdatei .git/config
. Zunächst ein Eintrag
svn-remote.svn
, der, ähnlich einem Eintrag remote
für ein Git-Remote-Repository, Angaben zu der URL und den zu
verfolgenden Subversion-Branches und -Tags enthält. Haben Sie
beispielsweise ein Repository mit Standardlayout geklont, könnte
das wie folgt aussehen:
[svn-remote "svn"] url = http://svn.example.com/ fetch = trunk:refs/remotes/origin/trunk branches = branches/*:refs/remotes/origin/* tags = tags/*:refs/remotes/origin/tags/*
Im Gegensatz zu einem regulären remote
-Eintrag enthält dieser
jedoch zusätzlich die Werte branches
und tags
. Diese
wiederum enthalten jeweils eine Refspec, die beschreibt, wie
Subversion-Branches und -Tags lokal als Subversion-Tracking-Branches
abgelegt werden. Der Eintrag fetch
behandelt nur den
Subversion-Trunk und darf keinerlei Glob-Ausdrücke enthalten.
Haben Sie keine Subversion-Branches und -Tags, fallen die entsprechenden Einträge weg:
[svn-remote "svn"] url = http://svn.example.com/ fetch = :refs/remotes/git-svn
Wenn Sie das Repository mit der Präfix-Option klonen, beispielsweise mit
--prefix=svn/
, passt git svn
die Refspecs an:
[svn-remote "svn"] url = http://svn.example.com/ fetch = trunk:refs/remotes/svn/trunk branches = branches/*:refs/remotes/svn/* tags = tags/*:refs/remotes/svn/tags/*
Sofern Sie eine Authors-Datei angeben, wird für diese ein gesonderter Eintrag erzeugt. Die Datei wird auch in Zukunft noch gebraucht, wenn Sie neue Commits aus dem Subversion-Repository herunterladen.
[svn] authorsfile = /home/valentin/svn-testing/authors.txt
Tip
|
In dem Abschnitt über die Konvertierung haben wir beschrieben, wie Sie
$ git svn show-ignore > .git/info/excludes |
Zusätzlich bietet git-svn
noch einige Kommandos zum
Untersuchen der Geschichte sowie anderer Eigenschaften des
Repositorys:
git svn log
-
Eine Kreuzung aus
svn log
undgit log
. Das Subkommando produziert Output, dersvn log
nachempfunden ist, verwendet aber das lokale Repository, um dies zu erstellen. Es wurden diverse Optionen vongit svn
nachgebaut, z.B. `-r <N>:<M>`. Unbekannte Optionen, z.B. `-p`, werden direkt angit log
weitergegeben, so dass Optionen aus beiden Kommandos gemischt werden können:$ git svn log -r 3:16 -p
Angezeigt würden nun die Revisionen 3—16, inklusive einem Patch der Änderungen.
git svn blame
-
Ähnlich wie
svn blame
. Mit der Option--git-format
hat der Output dasselbe Format wiegit blame
, aber mit Subversion-Revisionen anstelle der SHA-1-IDs. git svn find-rev
-
Zeigt die SHA-1-ID des Git-Commits, der das Changeset einer bestimmten Subversion-Revision darstellt. Die Revision wird mit der Syntax
r<N>
übergeben, wobei<N>
die Revisionszahl ist:$ git svn find-rev r6 c56506a535f9d41b64850a757a9f6b15480b2c07
git svn info
-
Wie
svn info
. Gibt diverse Informationen zu dem Subversion-Repository aus. git svn proplist
-
Wie
svn proplist
, gibt eine Liste der vorhandenen Subversion-Properties aus. git svn propget
-
Wie
svn propget
, gibt den Wert einer einzelnen Subversion-Property aus.
Leider kann git-svn
bisher nur Subversion-Properties
abfragen, aber weder erstellen, modifizieren noch löschen.
Analog zu git fetch
laden Sie mit git svn fetch
neue
Commits aus dem Subversion-Repository herunter. Dabei lädt
git-svn
alle neuen Subversion-Revisionen herunter, übersetzt
diese in Git-Commits und aktualisiert schließlich die
Subversion-Tracking-Branches. Als Ausgabe erhalten Sie eine
Auflistung der heruntergeladenen Subversion-Revisionen, die Dateien,
die durch die Revision verändert wurden, sowie die SHA-1-Summe und den
Subversion-Tracking-Branch des daraus resultierenden Git-Commits, also
z.B.:
$ git svn fetch A COPYING M README r21 = 8d707316e1854afbc1b728af9f834e6954273425 (refs/remotes/trunk)
Sie können wie gewohnt in dem Git-Repository lokal arbeiten — beim
Hochladen der Commits in das Subversion-Repository gilt es jedoch eine
wichtige Einschränkung zu beachten: Zwar ist git-svn
in der
Lage, Subversion-Merges einigermaßen darzustellen (s.o.), allerdings
kann das Tool keine lokalen Git-Merges auf Subversion-Merges abbilden — daher sollten ausschließlich lineare Verläufe per git svn
dcommit
hochgeladen werden.
Um diese Linearisierung zu erleichtern, gibt es das Kommando
git svn rebase
. Es lädt zuerst alle neuen Commits aus dem
Subversion-Repository herunter und baut danach via git rebase
den aktuellen Git-Branch auf den entsprechenden
Subversion-Tracking-Branch neu auf.
Im Wesentlichen besteht der Arbeitsablauf aus den folgenden Kommandos:
$ git add/commit ... $ git svn rebase $ git svn dcommit
git svn rebase
integriert die neu hinzugekommene Subversion-Revision als Commit C
– vor D
, was dadurch zu D'
wird. zeigt, was git svn rebase
bewirkt. Zuerst werden neue Revisionen aus dem
Subversion-Repository heruntergeladen, in diesem Fall C
.
Danach wird der Tracking-Branch remotes/origin/trunk
soz. `vorgerückt'' und entspricht dann dem aktuellen Zustand im
Subversion-Repository. Zuletzt wird per `git rebase
der
aktuelle Branch (in diesem Fall master
) neu aufgebaut. Der
Commit D' kann nun hochgeladen werden.
git svn rebase
integriert die neu hinzugekommene Subversion-Revision als Commit C
– vor D
, was dadurch zu D'
wird.Mit git svn dcommit
laden Sie das Changeset eines Git-Commits
als Revision in das Subversion-Repository hoch. Als Teil der Operation
wird die Revision erneut als Git-Commit, diesmal aber mit
Subversion-Metadaten in der Commit-Message, in das lokale Repository
eingepflegt. Dadurch ändert sich natürlich die SHA-1-Summe des
Commits, was in Nach einem git svn dcommit
hat der Commit D'
eine neue SHA-1-ID und wird zu D''
, weil seine Commit-Beschreibung verändert wurde, um Metainformationen abzuspeichern. durch die
unterschiedlichen Commits D
und D''
dargestellt
ist.
git svn dcommit
hat der Commit D'
eine neue SHA-1-ID und wird zu D''
, weil seine Commit-Beschreibung verändert wurde, um Metainformationen abzuspeichern.Ähnlich wie bei git push
dürfen Sie keine Commits, die Sie
bereits mit git svn dcommit
hochgeladen haben, nachträglich
mit git rebase
oder git commit --amend
verändern.
Mit den Subkommandos git svn branch
und git svn tag
erzeugen Sie Subversion-Branches und -Tags. Zum Beispiel:
$ git svn tag -m "Tag Version 2.0" v2.0
Im Subversion-Repository entsteht dadurch das Verzeichnis
tags/v2.0
, dessen Inhalt eine Kopie des aktuellen
HEAD
ist.[12] Im Git-Repository entsteht dafür ein neuer
Subversion-Tracking-Branch (remotes/origin/tags/v2.0
). Mit der
Option -m
übergeben Sie optional eine Nachricht. Wenn nicht,
setzt git-svn
die Nachricht Create tag <tag>
.
Git Version 1.7.4 führte ein Feature ein, mit dem Sie
Subversion-Merges durchführen können. Das Feature ist über die Option
--mergeinfo
für git svn dcommit
verfügbar und
sorgt dafür, dass die Subversion-Property svn:mergeinfo
gesetzt wird. Die Dokumentation dieser Option in der Man-Page
git-svn(1)
ist erst ab Version 1.7.4.5 dazugekommen.
Im Folgenden stellen wir exemplarisch einen Ablauf vor, um mit
git-svn
einen Branch zu erstellen, in diesem Commits zu
tätigen und ihn später wieder, im Sinne von Subversion, zu mergen.
Zuerst den Subversion-Branch erzeugen — das Kommando funktioniert im
Prinzip wie git svn tag
:
$ git svn branch <feature>
Dann erstellen Sie sich einen lokalen Branch zum Arbeiten und tätigen
in diesem Ihre Commits. Der Branch muss auf dem
Subversion-Tracking-Branch <feature>
basieren:
$ git checkout -b <feature> origin/<feature> $ git commit ...
Danach laden Sie die Commits in das Subversion-Repository hoch. Der
Aufruf git svn rebase
ist nur nötig, wenn zwischenzeitlich
ein anderer Nutzer Commits in dem Subversion-Branch feature
getätigt hat.
$ git svn rebase $ git svn dcommit
Nun müssen Sie noch die Merge-Informationen gesondert übertragen.
Dafür gehen Sie wie folgt vor: Zuerst mergen Sie den Branch lokal im
Git-Repository und laden dann den entstandenen Merge-Commit unter
Verwendung von --mergeinfo
hoch. Die Syntax für diese
Option ist:
$ git svn dcommit --mergeinfo=<branch-name>:<N>-<M>
Hierbei ist <branch-name>
die Subversion-Bezeichnung des
Branches, also z.B. `/branches/<name>`, <N>
die
erste Subversion-Revision, die den Branch verändert, und <M>
die letzte.[13] Angenommen, Sie haben den Branch mit Revision 23 erzeugt
und wollen nun, nach zwei Commits, den Branch wieder mergen, dann
würde das Kommando wie folgt lauten:
$ git checkout master $ git merge --no-ff <feature> $ git svn dcommit --mergeinfo=/branches/feature:23-25
-t
bzw. -b
an.
-T
oder --stdlayout
angegeben, wird ein einziger Branch namens remotes/git-svn
generiert.
mv
unterhalb von .git/refs/
ausführen. Die Plumbing-Kommandos machen es aber möglich, auch exotische'' Fälle wie
Packed Refs'' bzw. Referenzen, die Symlinks sind, korrekt zu behandeln. Außerdem schreibt git update-ref
entsprechende Einträge in das Reflog und gibt Fehlermeldungen aus, falls etwas schiefgeht. Siehe hierzu auch [sec.scripting].
contrib/svn-fe
svn copy trunk tags/v2.0
svn merge -r 23:25 branches/feature trunk