I've accidentally commit corrupted file (long story... ;-) into subversion repository, so I would like to revert to a previous version - but only this one particular file.
My file (l6208.lib) had been corrupted in version 309 (revision 308 was the last good one), so I type:
svn merge -c -309 l6208.lib
please note minus sign before 309. This mean apply differences between 309 and 308. You can also type:
svn merge -c -r 309:308 l6208.lib
Now it's time to commit recovered file.
svn ci l6208.lib -m "Reverted last revision"
I don't know if it is best method, but it works for me.
Miałem ciekawy przypadek błędu w repozytorium. Od razu powiem, że bez kopi zapasowej nie udało by mi się go rozwiązać.
Kopia robocza na jednym komputerze - wszystko działa (latami). Po jakimś czasie zachciało mi się (akurat - po prostu musiałem) w nim grzebnąć, ale już na nowym sprzęcie i ... klops. Okazało się, że repozytorium jest uszkodzone, co gorsza, jak się później okazało, już na wersji 2 (błąd dysku ???).
Komunikaty błędu miałem różne. Komenda svn pokazywała:
svn: REPORT of '/svnprv/reponame/!svn/vcc/default': Could not read \ chunk size: connection was closed by server (http://localhost)
w error_log apache'a było:
[error] [client 127.0.0.1] Provider encountered an error while \ streaming a REPORT response. [500, #0] [error] [client 127.0.0.1] A failure occurred while driving \ the update report editor [500, #160004]
a polecenie svnadmin verify reponame zwracało:
svnadmin: Checksum mismatch while reading representation: expected: 10b6f87d95a8283b4dc96607a662c4de actual: 1865015a5837bc21ea73397ee68e1c44
Po przejrzeniu backup'ów (makaronizm, ale "kopia zapasowa" jest taka długa...) znalazłem taki który miał poprawnie zapisaną wersję drugą - z przed 2 lat! W ten sposób posunąłem się o 400% (z wersji 1 do 4 ;-) do pełni szczęścia trochę brakuje...
Niby coś-tam działało, bo WebSVN ładnie pokazywał historie i doszedłem do tego, że mogę ściągać diff'y między różnymi wersjami, np.:
svn di http://localhost/svn/reponame@7 \ http://localhost/svn/reponame@15
W ten sposób dowiedziałem się, że tylko wersja 2 jest uszkodzona. Niestety próby odzyskania reszty danych z bieżącego repozytorium nie dawały pozytywnych rezultatów (testowałem na różnych wersjach):
svnadmin dump -r3 reponame svnadmin: Checksum mismatch while reading representation: expected: 959148e046aafa5f51db215c9ee0796d actual: 98824bfc23034f920d603d42a0810843
Oczywiście działało dla wersji 0 i 1. Kluczem okazał się przełącznik --incremental !
svnadmin dump -r3 --incremental reponame * Dumped revision 3.
Teraz już poszło gładko. Trzeba założyć nowe repozytorium i załadować do niego dane z kopii (była spakowana bzip2):
svnadmin create reponame-new bzcat reponame-2011-09-25.dump.bz2 | svnadmin load reponame-new ... ------- Committed revision 4 >>>
ustalić numer ostatniej wersji, powiedzmy 45 (żeby nie było równo) i wtedy (jak widać wersję 4 już miałem):
for x in `seq 5 45` ; do svnadmin dump --incremental -r $x reponame \ | svnadmin load reponame-new; done
... no trochę to trwało, ale za to pełen sukces.
Teraz wystarczy skasować stare i zmienić nazwę "nowego":
rm -rf reponam mv reponame-new reponame
Ładowane dane były do pustego repozytorium, więc UUID się nie zmienił.
Teraz trzeba poprawić skrypt, żeby po pierwsze wychwytywał błędy przy robieniu zrzutu (dump) i może dodatkowo wykonywał jeszcze zrzut ostatnich np. 10 wersji...
Przetestowałem zabezpieczenie przed przypadkowy zrobieniem commit'a do repozytorium bez podania numeru zgłoszenia (ticket). Zrobiłem to za pomocą hook'a pre-commit. Wszystkie polecenia podaję względem katalogu repozytorium, u mnie jest to /var/lib/svn/test. Skopiowałem szablon skryptu (parametr -p jest ważny, bo inaczej można popsuć uprawnienia)
cp -p hooks/pre-commit.tpl hooks/pre-commit chmod u+x hooks/pre-commit
i wykomentowałem linię:
commit-access-control.pl "$REPOS" "$TXN" commit-access-control.cfg || exit 1
na koniec po innych testach, tuż przed linią
exit 0
dopisałem taki kawałek kodu
blad=0 $SVNLOOK log -t "$TXN" "$REPOS" \ | grep "#[1-9][0-9]*" > /dev/null || blad=1 if [ $blad -eq 1 ] ; then echo -e "Dodaj numer ticket'a,\nnp.: Zgloszenie #123" 1>&2 exit 2 fi
który sprawdza czy w treści komentarza zawiera #N (gdzie N to dowolna liczba naturalna większa od 0) i zwraca komunikat błędu - użytkownik zobaczy to co wysyłane jest na wyjście błędu. Właściwy test to:
grep "#[1-9][0-9]*"
Dla Trac'a to wystarczy. Można go rozbudować, np. o sprawdzenie czy zawiera refs #N (N to znowu ciąg cyfr) - tak, żeby w Redmine ładnie pokazywał. Wtedy warunek będzie wyglądał tak (ja używam tylko refs):
grep "refs #[1-9][0-9]*"
Oczywiście można jeszcze dodać sprawdzanie pozostałych Referencing keywords oraz Fixing keywords.
Wypadało by też zmienić wyświetlany komunikat na np. Podaj numer zgłoszenia poprzedzony słowem refs, np:\nrefs #123, ale by wstawić tam znak końca wiersza (\n) trzeba dodać parametr -e do polecenia echo. Razem wygląda tak:
echo -e "Podaj numer zgłoszenia poprzedzony słowem refs, \ np:\nrefs #123" 1>&2
Mechanizm uchwytów (hook) do zdarzeń można wykorzystać dowolnie, także do bardziej zaawansowanych testów: np. by zabezpieczyć przed commit'em kodu który się nie da skompilować (chociaż ja bym tego nie robił) lub automatycznego budowania po commit'cie za pomocą post-commit (tego też bym nie robił).
Jak już postawiłem usługę katalogową, to chciałem użyć jej do autoryzacji do repozytoriów SVN do których był dostęp przez Apache.
W sumie jest to proste:
<IfModule mod_dav.c> <Location /svn> DAV svn SVNParentPath /var/lib/svn/repositories SVNListParentPath on AuthType Basic AuthName "Dostep do repozytorium" AuthBasicProvider ldap AuthLDAPURL "ldap://localhost/dc=jaqb,dc=gda,dc=pl" NONE AuthLDAPBindDN "cn=Manager,dc=jaqb,dc=gda,dc=pl" AuthLDAPBindPassword jakiesmocnehaslo AuthLDAPGroupAttribute memberUid AuthLDAPGroupAttributeIsDN off Require ldap-group cn=svnowcy,ou=groups,dc=jaqb,dc=gda,dc=pl </Location> </IfModule>
kluczowe są dwa wpisy:
AuthLDAPGroupAttribut memberUid AuthLDAPGroupAttributeIsDN off
bez tego Apache zakładał, że użytkownicy są wpisani jako member lub uniquemember i na dodatek jako np.:
uid=jaqb,ou=People,dc=jaqb,dc=gda,dc=pl
a domyślnie LAM zakłada jako np.: jaqb w memberUid.
Do wyszukiwania plików po atrybutach przygotowałem sobie pomocniczy skrypt havesvnproperty.bash:
#!/bin/bash if [ $# -lt 1 ] ; then echo "Skrypt sprawdza, czy plik ma ustawioną etykietę \ we właściwości 'wlasne:etykiety'." echo " " echo "Za mało parametrów" echo " " echo "Przykładowe użycie:" echo "$0 sciezka/do/pliku szukana_etykieta" echo "find /home/repozytorium -path '*/.svn' -prune -o \ -exec $0 \\{\\} etykieta \\;" exit 1 fi filename=$1 propval=$2 tags=`svn propget wlasne:etykiety "$filename"` ma=1 for x in $tags ; do if [ $x == $propval ] ; then ma=0 fi done if [ $ma -eq 0 ] ; then echo "Plik $filename jest oznaczony jako $propval" fi exit $ma
potem wyszukiwać można za pomocą polecenia find, np. tak:
find /home/jaqb/myrepo -path '*/.svn' -prune -o \ -exec havesvnproperty.bash \{\} etykieta \;
Zdarzyło mi się modyfikować wersjonowane pliki z dwóch komputerów i jak to zwykle bywa wersje SVN były na nich różne. Po modyfikacji nowszym klientem gdy chciałem znowu pracować na starszej wersji dostałem komunikat:
This client is too old to work with working copy
rozwiązanie (inne niż aktualizacja) jest bardzo proste i opisane w FAQ. Wystarczy użyć przygotowanego skryptu change-svn-wc-format.py który jako parametr przyjmuje ścieżkę kopii roboczej i wersję którą ma ustawić. W moim przypadku popsułem sobie katalog galerie i chciałem wrócić do wersji 1.5 więc wywołanie było takie:
./change-svn-wc-format.py galerie 1.5 --verbose
parametr --verbose dodałem bo lubię widzieć co się dzieje.
Po zainstalowaniu Eclipse na Ubuntu 11.04 nie mogłem się doszukać Subclipse. Okazało się, że do poprawnej współpracy z Subversion (repozytoria SVN) teraz trzeba zainstalować Subversive SVN Team Provider, Subversive SVN Connectors oraz SVNKit (np: 1.3.0).
Add comment