Subversion ist eines der nützlichsten Dienste überhaupt wenn man auf verschiedenen Computern an seinen Dateien arbeiten möchte ohne die Ergebnisse immer per Hand überall synchronisieren zu müssen.
Hier ist das
Subversion Handbuch (
Schnellstart)
mkdir -p /usr/local/var/my_svn/
svnadmin create /usr/local/var/my_svn/
mkdir -p ~/foo/; cd ~/foo/
svn co file:///usr/local/var/my_svn/
svn add ...
svn diff -r HEAD
svn diff -r 3:5
svn diff -r {2004-11-28\ 15:30}
svn update
svn commit
Die Datei FOO als binär markieren
svn propset svn:mime-type 'application/octet-stream' FOO
svn proplist -v FOO
svn diff mit Argumenten starten (z.B. um leere Zeile zu ignorieren)
svn diff --diff-cmd diff -x -iEbBu
Um diese Option permanent zu aktivieren einfach in ~/.subversion/config als diff Befehl ein kleines Shellscript angeben.
Die aktuelle Version in trunk kopieren, z.B. um neue, experimentelle Funktionen entwickeln zu können
# svn copy trunk branch/beta1
# svn ci branch/beta1
Committed revision 123.
Änderungen mit dem alten Code mischen:
# cd trunk/
# svn log --stop-on-copy ../branch/beta1
# svn diff -r 123:HEAD ../branch/beta1
# svn merge -r 123:HEAD ../branch/beta1
So sieht eine Apache2 Konfiguration aus die unter /usr/local/var/repositories/svn/NAME Subversion Repositories über die URL http://HOSTNAME/repositories/svn/NAME zur Verfügung stellt:
<Location /repositories/svn/>
DAV svn
SVNParentPath /usr/local/var/repositories/svn/
AuthType Basic
AuthName "My Subversion Repository"
AuthUserFile /usr/local/var/repositories/svn/user_passwd
Satisfy Any
Require valid-user
AuthzSVNAccessFile /usr/local/var/repositories/svn/user_authorisation
</Location>
Und so kann man die Rechte unter den Benutzer verteilen:
user_authorisation
## Default is NO
[/]
* =
[REPOS1:/]
usera = rw
userb = r
[REPOS1:/trunk/test]
userb = rw
Zeilenumbruch für eine Datei festlegen
Property:
svn:eol-style LF
svn:eol-style CRLF
svn:eol-style native
Dateien ausschließen
Property:
svn:ignore *
In Winmerge die ganzen .svn Ordner automatisch ignorieren
Winmerge -> Tools -> Filters -> FileFilters -> New -> For all Users -> Install
Diese Datei ablegen und dort auswählen
WinmergeSVNFilter.txt
Ab sofort ignoriert Winmerge .svn Dateien
22-08-2010 14.19
- großteils vom git Tutorial übernommen
- git-gui und gitk --all sind gut geeignet um Auswirkungen der Befehle zu beobachten
- Im Abschnitt SPECIFYING REVISIONS in git-rev-parse(1) enthält eine Reihe Möglichkeiten eine Revision in git zu benennen
Sich gegenüber git vorstellen
git-config --global user.name "Mr Foo"
git-config --global user.email "foo@example.com"
Entweder einen neuen, leeren Ordner anlegen ...
mkdir project
cd project
git-init # git-init-db
... oder einen vorhandenen Ordner nutzen
tar xzf project.tar.gz
cd project
git-init # git init-db
Hinweis: gitk funktioniert in neu angelegt git Repositories erst nach dem ersten Commit. Ansonsten erscheint folgende Fehlermeldung
Error in startup script: child process exited abnormally
while executing
"close $refd"
(procedure "readrefs" line 47)
invoked from within
"readrefs"
(file "/usr/bin/gitk" line 6370)
Alles im Ordner dem Repository hinzufügen und committen
git-add .
git-add--interactive
git-commit
Erst mal sehen was verändert wurde
git-diff
git-diff path/to/file
Im Gegensatz zu Subversion muss man vor dem commit nochmal alle Dateien auswählen die für den commit relevant sind. Das geht ebenfalls mit git-add
git-add path/to/file
Man kann sie auch sehr bequem mit git-gui auswählen.
Nachdem man die betroffenen Dateien mit git-add übernommen hat, sind die anstehenden Änderungen mit einem einfachen git-diff nicht mehr zu sehen. Man kann sie sich aber trotzdem ansehen
git-diff --cached
git-diff --cached path/to/file
Die ausgewählten Änderungen committen.
git-commit path/to/new/file
git-commit -m "* Bla bla" path/to/new/file
Man kann aber auch alle veränderten Dateien committen ohne dass man sie mit git-add nochmal explizit hinzufügen muss
git-commit -a
Wenn man mit dem letzten Commit nicht zufrieden ist lässt sich noch schnell korrigieren
git-commit --amend
Alternativ
git-reset --soft HEAD^
...
git-commit -c ORIG_HEAD
Änderungen anzeigen
git-diff
git-diff --color --color-words
git-diff --ignore-space-at-eol --ignore-space-change
git-diff -- path/to/file
git-diff HEAD -- path/to/file
git-diff HEAD^ -- path/to/file
git-diff HEAD^^ -- path/to/file
git-diff HEAD^^ HEAD^ -- path/to/file
git-diff 68fcc0 ef6274 -- path/to/file
git-diff HEAD ef6274 -- path/to/file
git-diff ef6274 ef6274^ -- path/to/file
git-diff master experimental -- path/to/file
git-diff master origin/master -- path/to/file
git-whatchanged 68fcc0 ef6274 -- path/to/file
git-diff --name-only 68fcc0 ef6274
git-status
git-log
Nur bestimmt Änderungen anzeigen, z.B. nur gelöschte Dateien oder nur veränderte Dateien
git diff --diff-filter=D --name-only
git diff --diff-filter=M --name-only
Dateien löschen und aus dem Repository entfernen
rm path/to/file # git-rm path/to/file
Dateien nur aus dem Repository löschen
git-rm --cached foo
Anzeigen wer was in einer Datei verändert hat
git-gui blame foo/bar/file.cpp
Es gibt zwei Möglichkeiten Dateien aus dem Repository auszuschließen
Weiter Informationen finden sich in gitignore(5).
Unterschiede im Repository in per E-Mail versendbare Patches umwandeln und in den angegebenen Ordner speichern.
git-format-patch --numbered --thread -o /tmp/mypatches/ HEAD^^ HEAD
git-format-patch --numbered --thread -o /tmp/mypatches/ -2
Alle Commits die im Branch origin sind, aber nicht im aktuellen Branch als Patch abspeichern
git-format-patch -o /tmp/mypatches/ origin
Alle patches die in einer mbox liegen extrahieren und auf den aktuellen Branch anwenden
git-am mymbox
git-format-patch -k --stdout HEAD^^ HEAD | git-am --3way --keep
Patches per E-Mail versenden (lässt man Empfänger oder Absender weg wird der automatisch aus Repository extrahiert)
git-send-email --from foo@example.com --envelope-sender foo@example.com --to bar@example.com /tmp/mypatches/
Einen Patch anwenden
git-apply --check foo.patch
git-apply foo.patch
git-apply --reject foo.patch
git-apply --reverse foo.patch
Einen Commit auf den aktuellen Branch anwenden
git-cherry-pick f6a2c
Repository durch Komprimierung beschleunigen
(regelmäßig anwenden)
git-gc
Repository auf Fehler überprüfen
git-fsck
Alte Version der Datei ansehen
git-show abcde:path/to/file
git-show HEAD:path/to/file
git-show HEAD^:path/to/file
git-show HEAD^^:path/to/file
git-show HEAD~3:path/to/file
Alte Version der Datei wiederherstellen
git-checkout HEAD^ path/to/file
Ein Tag setzten
git-tag v1.0
Einen neuen Branch anlegen und in ihn wechseln
git-branch experimental; git-checkout experimental
git-checkout -b experimental
Alle Branches anzeigen
git-branch
git-branch -r
git-branch -a
Der aktuelle Branch
ls -l .git/HEAD
Den Branch wechseln
git-checkout experimental
Zur ursprünglichen zurückwechseln
git-checkout master
Alle lokalen Änderungen im Branch die noch nicht committet wurden rückgängig machen
git-checkout -f
Änderungen aus experimental übernehmen
git-pull . experimental
Branch löschen
git-branch -D experimental
Branch wieder vereinigen
Der aktuelle Branch erhält alle Änderungen aus dem Branch experimental
git-merge experimental
Konflikt beim Mergen vereinigen
git-add path/to/new/file
git-commit
Angenommen folgende Branches
-->A-->B-->C foo
/
D-->E-->F-->G master
Man will den foo Zweig
A-->B-->C
Auf den Kopf des master Zweiges draufsetzten
-->A-->B-->C foo
/
D-->E-->F-->G master
Ist man schon im foo Zweig reicht ein
git-rebase master
um als Aufsetzpunkt für den aktuellen Zweig den Kopf des master Zweiges zu setzen.
Ansonsten kann man mit
git-rebase master foo
unabhängig vom aktuellen Zweig den foo Zweig auf den Kopf des master Zweiges setzten.
Schließlich kann man noch einen beliebigen Zweig ab einer beliebigen Stelle auf einen beliebiegen anderen Zweig draufsetzten. Aus
F-->G-->H bar
/
C-->D-->E foo
/
A-->B master
wird mit
git-rebase --onto master foo bar
dann
C-->D-->E foo
/
A-->B master
\
F-->G-->H bar
Angenommen Alice hat ein git repository in /home/alice/project, jetzt möchte Bob ihr helfen und am Projekt mitarbeiten. Mit dem folgenden Befehl bekommt er einen Klon des Repositories in den Ordner myrepo.
git-clone /home/alice/project myrepo
Nach dem Klonen eines entfernten Repositories findet man einen Zweig vor, master
git branch
* master
Das entfernte Repository kann natürlich zusätzliche Zweige beinhalten. Glücklicherweise stehen diese auch bereit
git branch -r
git branch -a
Man kann sich jetzt entweder sofort den Inhalt dieser Zweige erst einmal ansehen
git checkout origin/SuperBranchNr1
Oder aber man erzeugt einen entsprechenden lokalen Zweig, der automatisch so konfiguriert wird, dass er Änderungen per Default mit dem entfernten Branch abgleicht
git branch --track SuperBranchNr1 origin/SuperBranchNr1
Bob muss keine URL angeben um Updates von Alice zu ziehen
git-pull
Nachdem er Änderungen commited hat kann Alice sie direkt in ihr Repository übernehmen.
git-pull /home/bob/myrepo
Wenn Bob neue Zweige erzeugt hat, kann er sie so in Alicess Repository kopieren
git push --all origin
So kann er einen einzelnen neuen Zweig namens MyNewBranch in das entfernte Repository origin kopieren
git-push origin MyNewBranch
Man kann auch erst mal nur die Änderungen herunterladen ohne sie gleich anzuwenden
git-fetch /home/bob/myrepo
Es ist auch möglich mehr als ein entferntes Repository einzurichten. So kann man ein weiteres hinzufügen
git remote add origin git@foo/bar
git remote add origin2 git://foo/bar
git remote add origin3 ssh://user@foo.bar/~/foobar.git
Zeige alle entfernten Repositories
git remote show
git remote show origin
Entferne ein entferntes Repository
git remote rm origin2
Möglich über verschiedene Protokolle:
- git-deamon
Schnell, nur lesender Zugriff
- http
Langsamer, dafür kein Problem hinter restriktiven Firewalls. Normalerweise auch nur lesend.
- ssh
Schreibender Zugriff
- Zugriff über lokales Dateisystem
Schnell, schreibender Zugriff möglich
Anleitung
öffentliches git Repository einrichten.
Server, hat einen Ordner als Basis, z.B. /var/cache/git
git-daemon --verbose --base-path=/var/cache/git
Client, wir wollen ein vorhandenes Repository (z.B. /home/foo/bar) exportieren
git-clone --bare /home/foo/bar MyFirstRepository.git
Zum Export freigeben:
touch MyFirstRepository.git/git-daemon-export-ok
Diesen Ordner auf den Server kopieren
scp -r MyFirstRepository.git myserver.example.com:/var/cache/git/
Ab jetzt sollte es möglich sein das Repository per git zu ziehen
git-clone git://myserver.example.com/MyFirstRepository.git
Wir wenden wieder clone auf ein Repository an (oder benutzen ein bereits vorhandenes)
git-clone --bare /home/foo/bar MyFirstRepository.git
Einen neuen User erzeugen, z.B. git mit dem wir uns via ssh einloggen (man kann natürlich auch einen vorhandenen User benutzen).
Wenn man einen neuen User für den git ssh Zugang benutzt, sollte man überlegen den User auf die Shell /usr/bin/git-shell zu beschränken (/etc/passwd)
So kann man einen anderen Port für den ssh Dienst nutzen, der über ssh angeboten wird
git clone ssh://git@foo.bar:9418/~/foo.git
Ein Subversion Repository einmalig in ein git repository importieren.
git-svnimport http://example.com/mysvnrepository
Erwartet wird per Default die empfohlene Subversion Struktur:
trunk/
branches/foo
branches/bar
branches/...
mit entsprechenden Kommandozeilenparametern können aber auch andere Strukturen vermittelt werden.
In einem meiner Projekte wurde anfangs kein trunk Ordner benutzt. Dann wurde in einem Commit ein trunk und ein branches Ordner angelegt und alle Dateien in den trunk Ordner verschoben. Da die ersten Commits direkt in das Repository gingen und nicht in einen Order (wie z.B. trunk), kann git-svnimport damit noch nicht umgehen (Stand August 2007). Es gibt aber einen kleinen Patch mit dem
git-svnimport mit leeren trunk Ordnern umgehen kann. In meinem Projekt wurde ab Revision 325 dann ein trunk Ordner angelegt und alle Dateien und Ordner dorthin verschoben.
Hat man eine Version von git-importsvn die mit leeren trunk Ordnern umgehen kann funktioniert der Import zweistufig:
git-svnimport -s 1 -T '' -l 324 http://example.com/myproject
git-svnimport -o tmp1 -s 325 -T 'trunk' http://example.com/myproject
git-checkout tmp1
git-rebase master
Das Mischen der beiden Teile benötigte allerdings einige manuelle Eingriffe.
Will man sowohl git als auch Subversion verwenden lohnt sich vielleicht ein Blick auf git-svn:
git-svn init
Wenn etwas schief ging kann man als letzten Schritt versuchen die letzten git Aktionen rückgängig zu machen
# git reflog
24f34f2... HEAD@{0}: pull : Fast forward
68fh47g... HEAD@{1}: checkout: moving to master
90cdrt3... HEAD@{2}: pull : Fast forward
62dgs35... HEAD@{3}: rebase: ...
# git reset --hard HEAD@{1}
Wenn das aktuelle Projekt einen Fehlverhalten zeigt dass in früheren Versionen noch nicht enthalten war, kann man mit git-bisec die Version markieren die noch funktioniert hat und git-bisec findet dann die Änderung die das Problem verursacht.
git-bisect start
git-bisect bad
git-bisect good v2.6.13-rc2
Jetzt erhält man eine Version zwischen der funktionierenden und der kaputten. Nach einem teste gibt man wieder an ob das Problem dort enthalten ist oder nicht.
git-bisect good
Wenn man das Problem gefunden hat kann man bisec beenden und zurück zur aktuellsten Version gehen
git-bisect reset
Das (komplette!) Kernel Repository von Linus ziehen
git-clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git linux-2.6
Achtung in diesem git Repository befinden sich
keine Tags für stabile kernel Zweig. Wenn man diesen verfolgen möchte also lieber das git für den stabilen Kernel benutzen
git-clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-2.6.16.y.git
Dieser hat
Tags für den stabilen Kernel Zweig.
Alle verfügbaren Tags auflisten
ls .git/refs/tags/
Wenn man schon den Zweig vom Linus git geladen hat kann man den Ordner als Quelle für das git des stabilen Zweiges nutzen (ungetestet, geht erst ab git 1.3)
git-clone --reference oldfolder git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-2.6.16.y.git newfolder
Die Veränderung in der der Datei MAKEFILE aufzeigen
git-diff v2.6.17-rc4..HEAD Makefile
Einen neuen Branch erzeugen und den Kernel mit dem gegebenen Tag in ihn kopieren (benötigt keine Netzwerkverbindung wenn man schon das aktuelle Repository hat).
Mit diesem Befehl kann man also einen bestimmten Kernel aus dem git extrahieren.
git-checkout -f master
git-pull
git-checkout -f -b my-new-branch tags/v2.6.16.19
04-08-2010 00.07