Versjonskontroll med Subversion

For Subversion 1.4

(Bokrevisjon 4250)

Ben Collins-Sussman

Brian W. Fitzpatrick

C. Michael Pilato

Øyvind A. Holm

Oversettelse til norsk 

Dette verket er lisensiert under Creative Commons Attribution License. For å se en kopi av denne lisensen, gå til http://creativecommons.org/licenses/by/2.0/ eller send et brev til Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.


Innholdsfortegnelse

Forord
Innledning
Publikum
Hvordan lese denne boka
Konvensjoner brukt i boka
Typografiske konvensjoner
Ikoner
Organiseringen av denne boka
Denne boka er fri
Krediteringer
Fra Ben Collins-Sussman
Fra Brian W. Fitzpatrick
Fra C. Michael Pilato
Hva er Subversion?
Subversions historie
Subversions fordeler
Subversions arkitektur
Subversions komponenter
1. Grunnleggende konsepter
Depotet
Versjoneringsmodeller
Problemet med fildeling
Lås-rediger-lås opp-løsningen
Kopier-rediger-flett-løsningen
Subversion i aksjon
Depot-URLer i Subversion
Arbeidskopier
Revisjoner
Hvordan arbeidskopier holder følge med depotet
Arbeidskopier med blandede revisjonsnumre
Oppdateringer og innlegginger er separate
Blandede revisjoner er normalt
Blandede revisjoner er nyttige
Blandede revisjoner har begrensninger
Oppsummering
2. Grunnleggende bruk
Hjelp!
Importering
Tidsreiser med Subversion
Innledende uthenting
Grunnleggende arbeidssyklus
Oppdater arbeidskopien din
Gjør forandringer i arbeidskopien
Studer forandringene dine
svn status
svn diff
svn revert
Løse konflikter (Flette inn andres forandringer)
Løse konflikter for hånd
Kopiere ei fil over arbeidsfila din
Bruke svn revert
Legg inn forandringene dine
Studere historien
svn log
svn diff
Undersøke lokale forandringer
Sammenligne arbeidskopi med depot
Sammenligne depot med depot
svn cat
svn list
Et siste ord om historie
Andre nyttige kommandoer
svn cleanup
svn import
Oppsummering
3. Avanserte emner
Revision Specifiers
Nøkkelord for revisjoner
Revisjonsdatoer
Egenskaper
Hvorfor bruke egenskaper?
Manipulering av egenskaper
Egenskaper og arbeidsflyten i Subversion
Automatic Property Setting
File Portability
File Content Type
File Executability
End-of-Line Character Sequences
Ignoring Unversioned Items
Keyword Substitution
Locking
Creating locks
Discovering locks
Breaking and stealing locks
Lock Communication
Externals Definitions
Peg and Operative Revisions
Nettverksmodellen
Forespørsler og reponser
Lagring av klientlegitimasjon
4. Forgrening og fletting
Hva er en forgrening?
Bruke forgreninger
Opprette en forgrening
Arbeide med grenen
Nøkkelkonseptet bak forgreninger
Kopiere forandringer mellom forgreninger
Kopiere spesifikke forandringer
Nøkkelkonseptet bak fletting
Beste praksiser for fletting
Følge flettinger manuelt
Vise flettinger på forhånd
Konflikter under fletting
Legge merke til eller ignorere slektskap
Vanlige bruksområder
Flette en hel gren til en annen
Omgjøre forandringer
Hente tilbake slettede elementer
Vanlige forgreningsmønstre
Utgivelsesgrener
Funksjonalitetsgrener
Bytte om en arbeidskopi
Merker (tags)
Lage et enkelt merke
Lage et komplekst merke
Vedlikehold av grener
Utseendet på depotet
Levetid for data
Leverandørgrener
Generell prosedyre for vedlikehold av leverandørgrener
svn_load_dirs.pl
Oppsummering
5. Depotadministrasjon
Det grunnleggende ved et depot
Forståelse av transaksjoner og revisjoner
Uversjonerte egenskaper
Datalagring i depotet
Berkeley DB
FSFS
Opprettelse og konfigurering av depotet
Påhakningsskript
Konfigurasjon av Berkeley DB
Vedlikehold av depotet
En administrators verktøykasse
svnlook
svnadmin
svndumpfilter
Berkeley DB-verktøy
Depotvedlikehold
Bruken av diskplass
Depotgjenoppretting
Flytte et depot
Sikkerhetskopi av depotet
Legge til prosjekter
Velge en depot-layout
Opprette layouten og importere grunndataene
Oppsummering
6. Serverkonfigurasjon
Oversikt
The Apache HTTP Server
The svnserve Server
svnserve over SSH
Choosing the Best Server Configuration
svnserve, en tilpasset server
Starte serveren
svnserve as Daemon
svnserve via inetd
svnserve i en tunnel
svnserve as Windows Service
Innebygget autentisering og autorisasjon
Opprette en brukerfil og område
Sette tilgangskontroll
Autentisering og autorisasjon via SSH
Konfigurasjonstriks i SSH
Innledende oppsett
Kontrollere den startede kommandoen
HTTP-serveren Apache (httpd)
Systemkrav
Grunnleggende oppsett av Apache
Autentiseringsvalg
Enkel HTTP-autentisering
Håndtering av SSL-sertifikater
Autorisasjonsvalg
Adgangskontroll for hele depotet
Adgangskontroll på katalognivå
Slå av stibaserte kontroller
Flere lure ting
Bla gjennom depotet
Apache Logging
Annen funksjonalitet
Path-Based Authorization
Støtte for flere metoder for tilgang til depotet
7. Tilpasse Subversion til din smak
Konfigurasjonsområdet for bruk under kjøring
Oppbygningen av konfigurasjonsområdet
Konfigurasjon og Windows-registryen
Konfigurasjonsvalg
Servere
Konfigurasjon
Localization
Understanding locales
Subversion's use of locales
Using External Differencing Tools
External diff
External diff3
8. Developer Information
Layered Library Design
Repository Layer
Repository Access Layer
RA-DAV (Repository Access Using HTTP/DAV)
RA-SVN (Custom Protocol Repository Access)
RA-Local (Direct Repository Access)
Your RA Library Here
Client Layer
Using the APIs
The Apache Portable Runtime Library
URL and Path Requirements
Using Languages Other than C and C++
Inside the Working Copy Administration Area
The Entries File
Pristine Copies and Property Files
WebDAV
9. Subversion Complete Reference
The Subversion Command Line Client: svn
svn Switches
svn Subcommands
svn add
svn blame
svn cat
svn checkout
svn cleanup
svn commit
svn copy
svn delete
svn diff
svn export
svn help
svn import
svn info
svn list
svn lock
svn log
svn merge
svn mkdir
svn move
svn propdel
svn propedit
svn propget
svn proplist
svn propset
svn resolved
svn revert
svn status
svn switch
svn unlock
svn update
svnadmin
svnadmin Switches
svnadmin Subcommands
svnadmin create
svnadmin deltify
svnadmin dump
svnadmin help
svnadmin hotcopy
svnadmin list-dblogs
svnadmin list-unused-dblogs
svnadmin load
svnadmin lslocks
svnadmin lstxns
svnadmin recover
svnadmin rmlocks
svnadmin rmtxns
svnadmin setlog
svnadmin verify
svnlook
svnlook Switches
svnlook
svnlook author
svnlook cat
svnlook changed
svnlook date
svnlook diff
svnlook dirs-changed
svnlook help
svnlook history
svnlook info
svnlook lock
svnlook log
svnlook propget
svnlook proplist
svnlook tree
svnlook uuid
svnlook youngest
svnserve
svnserve Switches
svnversion
svnversion
mod_dav_svn
mod_dav_svn Configuration Directives
Subversion properties
Subversion-defined properties
A. Hurtiginnføring i Subversion
Installering av Subversion
Høyhastighetsopplæring
B. Subversion for CVS-brukere
Revisjonsnumre er forskjellige nå
Katalogversjoner
Flere frakoblede operasjoner
Skille mellom status og oppdatering
Status
Update
Forgreninger og merker
Metadata-egenskaper
Reparering av konflikter
Binære filer og konverteringer
Versjonerte moduler
Autentisering
Konvertere et depot fra CVS til Subversion
C. WebDAV and Autoversioning
Basic WebDAV Concepts
Original WebDAV
DeltaV Extensions
Subversion and DeltaV
Autoversioning
Client Interoperability
Standalone WebDAV applications
Microsoft Office, Dreamweaver, Photoshop
Cadaver, DAV Explorer
File-explorer WebDAV extensions
Microsoft Web Folders
Nautilus, Konqueror
WebDAV filesystem implementation
WebDrive, NetDrive
Mac OS X
Linux davfs2
D. Third Party Tools
E. Copyright
Indeks

Figuroversikt

1. Subversions arkitektur
1.1. Et typisk klient/server-system
1.2. Problemet som må unngås
1.3. Lås-rediger-lås opp-løsningen
1.4. Kopier-rediger-flett-løsningen
1.5. Kopier-rediger-flett-løsningen (forts.)
1.6. Depotets filsystem
1.7. Depotet
4.1. Forgreninger av utviklingen
4.2. Depotets utseende til å begynne med
4.3. Depot med ny kopi
4.4. Forgreningen av ei fils historie
8.1. Files and directories in two dimensions
8.2. Versioning time—the third dimension!

tabelloversikt

1.1. URLer for tilgang til et depot
5.1. Sammenligning av datalagring i depoter
6.1. Sammenligning av nettverksservere
8.1. A Brief Inventory of the Subversion Libraries
C.1. Common WebDAV Clients

Eksempeloversikt

5.1. txn-info.sh (Rapporterer utestående transaksjoner)
6.1. Et eksempel på oppsett for anonym tilgang.
6.2. Eksempel på oppsett for autentisert tilgang.
6.3. Eksempel på oppsett for blandet autentisert/anonym tilgang.
6.4. Slå av alle filstikontroller
7.1. Eksempel på registryposter i ei .reg-fil.
7.2. diffwrap.sh
7.3. diffwrap.bat
7.4. diff3wrap.sh
7.5. diff3wrap.bat
8.1. Using the Repository Layer
8.2. Using the Repository Layer with Python
8.3. A Python Status Crawler
8.4. Contents of a Typical .svn/entries File

Forord

Karl Fogel

Chicago, 14. mars 2004

En dårlig FAQ (Ofte stilte spørsmål) er en som ikke er satt sammen av spørsmål brukere faktisk stiller, men det som forfatterne ønsker at de ville spørre om. Du har kanskje sett noe lignende som dette før:

Spm.: Hvordan kan jeg bruke Glorbosoft XYZ til å øke lagproduktiviteten?

Sv.: Mange av våre kunder vil vite hvordan de kan maksimere produktiviteten gjennom våre patenterte kontor-gruppevareløsninger. Svaret er enkelt: Først, klikk på Fil-menyen, rull ned til Øk produktiviteten, deretter …

Problemet med slike FAQ-er er at de er, bokstavelig talt, ikke FAQ-er i det hele tatt. Ingen ringer teknisk support og spør: Hvordan kan vi øke produktiviteten? Istedenfor spør folk høyst spesifikke spørsmål som for eksempel: Hvordan kan vi forandre kalendersystemet til å sende påminnelser to dager i forveien istedenfor en? og så videre. Men det er er mye lettere å lage spørsmål istedenfor å oppdage de spørsmålene som egentlig blir stilt. Det å sette sammen en FAQ må være en sammenhengende og organisert prosess som varer hele levetiden til programmet, innkommende spørsmål må bli lagret, responsen fulgt, og alt dette må samles i en fyldig, søkbar helhet som avspeiler den kollektive opplevelsen for brukerne ute i det fri. Det krever en tålmodig og observant innstilling hos en som befinner seg i felten. Ingen store hypoteser, ingen visjonære uttalelser her – åpne øyne og nøyaktige notater er det som trengs mest.

Det jeg liker med denne boka er at den vokste fram nettopp gjennom en slik prosess, og dette vises på hver eneste side. Den er det direkte resultatet av forfatterens møter med brukerne. Det begynte med Ben Collins-Sussmans observasjon av at folk spurte de samme enkle spørsmålene om og om igjen på mailinglisten til Subversion: Hva er standard fremgangsmåte for å bruke Subversion? Virker forgreninger og merker på samme måte som i andre versjonskontrollsystemer? Hvordan kan jeg finne ut hvem som gjorde en spesiell forandring?

Frustrert over å se de samme spørsmålene dag etter dag, jobbet Ben intenst over en måned sommeren 2002 for å skrive The Subversion Handbook, en 60-siders håndbok som tok for seg all grunnleggende bruk av Subversion. Håndboka tok ikke mål av seg å være komplett, men den ble distribuert med Subversion og hjalp brukere over den innledende humpen i lærekurven. Da O’Reilly and Associates bestemte seg for å publisere en fullversjon av Subversion-boka, var minste motstands vei opplagt: Å utvide håndboka.

De tre medforfatterne av den nye boka ble dermed presentert for en uvanlig mulighet. Offisielt var deres oppgave å skrive ei bok ovenfra og ned, å starte med innholdet og et innledende utkast. Men de hadde også tilgang til en jevn strøm – faktisk en ukontrollerbar geysir – av materiale som kom fra gressrotplan. Subversion var allerede i hendene på tusenvis av tidlige brukere, og disse brukerne ga tonnevis med tilbakemeldinger, ikke bare om Subversion, men om den eksisterende dokumentasjonen.

Gjennom hele tiden de skrev denne boka, trålte Ben, Mike og Brian konstant malilinglisten til Subversion og fulgte med i snakkerom mens de nøye skrev ned problemer brukere hadde i virkelige situasjoner. Å holde øye med slike tilbakemeldinger var en del av deres arbeidsoppgaver hos CollabNet uansett, og det ga dem en stor fordel når de satte i gang med å dokumentere Subversion. Boka de produserte er fast forankret i erfaringens grunnfjell, ikke i den skiftende sanden av ønsketenkning; den kombinerer de beste aspektene av en brukerhåndbok og en liste over ofte spurte spørsmål. Denne tosidigheten er kanskje ikke så merkbar ved første gjennomlesing. Tatt i rekkefølge, forside til bakside, er boka rett og slett en likefrem beskrivelse av et stykke programvare. Oversikten finnes der, den obligatoriske guidede gjennomgangen, kapittelet om administrativ konfigurasjon, noen avanserte tema, og selvfølgelig en referanse over kommandoer og problemer som kan dukke opp. Bare når du kommer tilbake til den senere, når du vil lete opp løsningen på et spesifikt problem, da viser det seg: Detaljene i fortellingen kan bare være resultatet av møter med det uventede, eksemplene finslipt av virkelige bruksmåter, og mest av alt forståelsen av brukerens behov og hvordan situasjonen tar seg ut fra brukerens ståsted.

Selvfølgelig, ingen kan love at denne boka vil kunne svare på hvert eneste spørsmål du har om Subversion. Noen ganger vil presisjonen i hva den forventer av spørsmål være uhyggelig telepatisk; andre ganger kan du finne et hull i fellesskapets kunnskap, og du står tomhendt tilbake. Når dette skjer, er den beste tingen du kan gjøre å sende en epost til og legge fram problemet ditt. Forfatterne er fortsatt der, de følger fortsatt med, og disse består ikke bare av de tre på forsiden, men også mange andre som har bidratt med korreksjoner og originalt materiale. Fra fellesskapets synspunkt er det å løse problemet ditt bare en behagelig bieffekt av et mye større prosjekt – det å sakte tilpasse boka, og aller helst Subversion selv, til å samsvare mer med hvordan den faktisk brukes. De er ivrige etter å høre fra deg, ikke bare fordi de kan hjelpe deg, men fordi du kan hjelpe dem. Det er med Subversion som med alle aktive prosjekter innen fri programvare, du er ikke alene.

La denne boka bli din første ledsager.

Innledning

 

Det er viktig å ikke la det perfekte bli fienden til det gode, selv når du kan være enig i hva det perfekte er. Dobbelt så mye når du ikke kan det. Samme hvor ubehagelig det er å bli fanget av tidligere feil, kan du ikke gjøre fremskritt ved å være redd din egen skygge når du designer.

 
 --Greg Hudson

I opensource-verdenen var Concurrent Versions System (CVS) i flere år førstevalget innen versjonskontroll. Og det er fortjent. CVS var selv fri programvare, og dens ikke-restriktive virkemåte og støtte for nettverksbaserte operasjoner tillot dusinvis av programmerere spredt over et geografisk område å dele på arbeidet. Den passet veldig bra sammen med samarbeidsånden i opensource-verdenen. CVS med sin halvkaotiske utviklingsmodell har siden blitt hjørnesteiner i kulturen omkring fri programvare.

Men CVS hadde sine feil, og det å fikse disse feilene så ut til å bli litt av en jobb. Så kom Subversion. Subversion var originalt konstruert som en etterfølger til CVS, og Subversionutviklerne gikk inn for å vinne hjertene til CVS-brukerne på to måter – ved å lage et opensource-system med en design (og look and feel) som ligner på CVS, og samtidig prøve å unngå mesteparten av de åpenbare feilene i CVS. Selv om resultatet nødvendigvis ikke er det neste store steget innen versjonskontrolldesign, er Subversion meget kraftig, brukbart og veldig fleksibelt. Og i de fleste tilfeller velger nå nesten alle nye opensource-prosjekter Subversion istedenfor CVS.

Denne boka er skrevet for å dokumentere 1.4-serien av versjonskontrollsystemet Subversion. Vi har gjort hva vi kan for å være grundig i dekningen av systemet. Subversion har imidlertid et livlig og energisk utviklermiljø, så det er allerede et antall funksjoner og forbedringer planlagt i fremtidige versjoner av Subversion som kan forandre noen av kommandoene og de spesifikke notatene i denne boka.

Publikum

Denne boka er skrevet for datamaskinkyndige personer som vil bruke Subversion til å behandle sine data. Selv om Subversion kjører under flere forskjellige operativsystemer, er det primære brukergrensesnittet kommandolinjebasert. Dette kommandolinjeverktøyet (svn) og tilleggsprogrammer er satt i fokus i denne boka.

For å være konsekvent går vi ut i fra at leseren bruker et Unix-lignende operativsystem og er relativt komfortabel med Unix og kommandolinjemiljø. Når det er sagt, kjører svn-programmet også på andre plattformer enn Unix, for eksempel Microsoft Windows. Med noen få unntak, som bruken av omvendte skråstreker (\) istedenfor vanlige skråstreker (/) som stiseparatorer, er inndataene og utdataene til og fra dette verktøyet når det kjøres under Windows identisk med den tilsvarende versjonen på Unix.

De fleste leserne er sannsynligvis programmerere eller systemadministratorer som har behov for å følge forandringer i kildekode. Dette er den vanligste bruken av Subversion, og derfor legges dette scenariet til grunn for alle eksemplene i boka. Men Subversion kan også brukes til å holde rede på forandringer i alle typer informasjon – bilder, musikk, databaser, dokumentasjon og så videre. For Subversion sin del er alle data bare data.

Selv om denne boka er skrevet med antakelsen om at brukeren aldri har brukt et versjonskontrollsystem, har vi også forsøkt å gjøre det lett for brukere av CVS (og andre systemer) å foreta en smertefri overgang til Subversion. Spesielle sidenotater kan nevne andre versjonskontrollsystemer nå og da, og et spesielt tillegg summerer opp mange av forskjellene mellom CVS og Subversion.

Merk at kildekodeeksemplene som er brukt i boka er bare eksempler. Selv om de vil kompilere med den riktige kompilatorbesvergelsen, er de beregnet på å illustrere en spesiell situasjon, ikke nødvendigvis være eksempler på god programmeringsstil eller praksis.

Hvordan lese denne boka

Denne boka tar sikte på å være nyttig for folk med varierende bakgrunn – fra folk med ingen tidligere erfaring fra versjonskontroll til erfarne systemadministratorer. Avhengig av bakgrunnen din kan enkelte kapitler være mer eller mindre nyttig for deg. Det som kommer nå kan sees på som en anbefalt leseliste for forskjellige typer lesere:

Erfarne systemadministratorer

Antakelsen her er at du sannsynligvis har brukt CVS før, og klør i fingrene etter å få en Subversionserver opp og gå så fort som mulig. Kapittel 5, Depotadministrasjon og Kapittel 6, Serverkonfigurasjon vil vise deg hvordan du lager ditt første depot og gjør det tilgjengelig over nettverket. Etter at det er gjort, er Kapittel 2, Grunnleggende bruk og Tillegg B, Subversion for CVS-brukere den raskeste veien for å bli kjent med Subversionklienten.

Nye brukere

Administratoren din har muligens satt opp Subversion allerede, og du trenger å lære hvordan klienten skal brukes. Hvis du aldri har brukt et versjonskontrollsystem før, er Kapittel 1, Grunnleggende konsepter en vital introduksjon til idéene bak versjonskontroll. Kapittel 2, Grunnleggende bruk er en gjennomgang av Subversionklienten.

Avanserte brukere

Enten du er en bruker eller administrator, vil prosjektet ditt etterhvert vokse seg større. Du vil ønske å lære hvordan man gjør mer avanserte ting med Subversion, som å bruke forgreninger og utføre flettinger (Kapittel 4, Forgrening og fletting), hvordan bruke Subversions støtte for egenskaper (Kapittel 3, Avanserte emner), hvordan konfigurere valg for kjøring (Kapittel 7, Tilpasse Subversion til din smak) og andre ting. Disse kapitlene er ikke absolutt nødvendige til å begynne med, men pass på å lese dem når du er komfortabel med det grunnleggende.

Utviklere

Antagelig er du allerede kjent med Subversion, og vil nå enten utvide den eller lage ny programvare på toppen av dens mange programmeringsgrensesnitt. Kapittel 8, Developer Information er bare for deg.

Boka slutter med referansemateriale – Kapittel 9, Subversion Complete Reference er en referanseguide for alle Subversionkommandoer, og tilleggene dekker en rekke nyttige emner. Dette er kapitlene du mest sannsynlig vil komme tilbake til når du er ferdig med boka.

Konvensjoner brukt i boka

Denne seksjonen tar for seg de forskjellige konvensjonene brukt i denne boka.

Typografiske konvensjoner

Konstant bredde

Brukt om kommandoer, utdata fra kommandoer og om valg.

Skrå skrift med konstant bredde

Brukt til utbyttbare elementer i kode og tekst

Skrå skrift

Brukes for fil- og katalognavn

Ikoner

[Notat]Notat

Dette ikonet indikerer et notat som har sammenheng med den omkringliggende teksten.

[Tips]Tips

Dette ikonet indikerer et nyttig tips som har sammenheng med den omkringliggende teksten.

[Advarsel]Advarsel

Dette ikonet indikerer en advarsel som har sammenheng med den omkringliggende teksten.

Organiseringen av denne boka

Kapitlene som følger og innholdet deres er listet her:

Innledning

Dekker historien til Subversion så vel som funksjoner, arkitektur og komponenter.

Kapittel 1, Grunnleggende konsepter

Forklarer det grunnleggende om versjonskontroll og forskjellige versjoneringsmodeller, sammen med Subversions depot, arbeidskopier og revisjoner.

Kapittel 2, Grunnleggende bruk

Tar deg med gjennom en dag i livet til en Subversionbruker. Det demonstrerer hvordan man bruker en Subversionklient for å hente, modifisere og sende inn data.

Kapittel 3, Avanserte emner

Dekker mer kompleks funksjonalitet som vanlige brukere etterhvert vil komme i kontakt med, som versjonerte metadata, låsing av filer og peg-revisjoner.

Kapittel 4, Forgrening og fletting

Diskuterer forgreninger, fletting og merking, inkludert beste praksiser for å lage forgreninger og fletting, vanlige bruksmåter, hvordan angre på forandringer og hvordan man lett kan svinge seg fra en gren til en annen.

Kapittel 5, Depotadministrasjon

Beskriver det grunnleggende ved et Subversiondepot, hvordan man lager, konfigurerer og vedlikeholder et depot, og verktøyene du kan bruke for å gjøre alt dette.

Kapittel 6, Serverkonfigurasjon

Forklarer hvordan du konfigurerer Subversionserveren din og de tre måtene å få tilgang til depotet ditt: HTTP, svn-protokollen og lokal disktilgang. Det dekker også detaljer omkring autentisering, tilgangskontroll og anonym tilgang.

Kapittel 7, Tilpasse Subversion til din smak

Utforsker Subversion-klientens konfigurasjonsfiler, behandling av internasjonalisert tekst og hvordan få eksterne verktøy til å samarbeide med Subversion.

Kapittel 8, Developer Information

Beskriver den interne funksjonaliteten til Subversion, Subversions filsystem, og de administrative områdene i arbeidskopien sett fra en programmerers synspunkt. Demonstrerer hvordan man bruker de offentlige programmeringsgrensesnittene til å skrive et program som bruker Subversion, og viktigst av alt, hvordan bidra til utviklingen av Subversion.

Kapittel 9, Subversion Complete Reference

Forklarer i stor detalj hver eneste delkommando i svn, svnadmin og svnlook med nok eksempler for hele familien!

Tillegg A, Hurtiginnføring i Subversion

En forklaring i full fart for den utålmodige om hvordan Subversion installeres og hvordan den kan brukes med en gang. Du er herved advart.

Tillegg B, Subversion for CVS-brukere

Dekker likheter og forskjeller mellom Subversion og CVS, med flere forslag om hvordan du kan bryte alle de dårlige vanene du har plukket opp etter år med bruk av CVS. Inkludert her er beskrivelser av Subversions revisjonsnumre, versjonerte kataloger, frakoblede operasjoner, update versus status, forgreninger, merker, metadata, konfliktløsing og autentisering.

Tillegg C, WebDAV and Autoversioning

Beskriver detaljene om WebDAV og DeltaV, og hvordan du kan konfigurere Subversiondepotet til å være montert som et delt DAV-område.

Tillegg D, Third Party Tools

Diskuterer verktøy som støtter eller bruker Subversion, inkludert alternative klientprogrammer, verktøy for å utforske depotet og så videre.

Denne boka er fri

Denne boka startet som småbiter av dokumentasjon skrevet av Subversions prosjektutviklere, og deretter satt sammen til et enkeltstående verk og omskrevet. Som sådan har den alltid hatt en fri lisens. (Se Tillegg E, Copyright.) Boka ble faktisk skrevet under offentlig oppsyn, som en del av Subversion. Dette betyr to ting:

  • Du vil alltid finne den seneste versjonen av denne boka i bokas eget Subversiondepot.

  • Du kan gjøre forandringer i denne boka og redistribuere den så mye du ønsker – den er under en fri lisens. Det eneste som kreves er at de originale forfatterne blir kreditert. Selvfølgelig, istedenfor at du distribuerer din egen private versjon av boka, vil vi heller at du sender respons og patcher til utviklermiljøet for Subversion.

En relativt fersk versjon av boka finner du online på http://svnbook.red-bean.com.

Krediteringer

Denne boka ville ikke vært mulig (og heller ikke særlig nyttig) hvis Subversion ikke eksisterte. Derfor vil forfatterne takke Brian Behlendorf og CollabNet for visjonen om å støtte et slikt risikabelt og ambisiøst nytt Open Source-prosjekt; Jim Blandy for det originale Subversion-navnet og designen – vi elsker deg, Jim; Karl Fogel for at han er slik en god venn og stor leder av fellesskapet, i den rekkefølgen.[1]

Takk til O’Reilly og våre redaktører, Linda Mui og Tatiana Diaz for deres tålmodighet og støtte.

Til slutt vil vi takke alle de utallige folkene som har bidratt til denne boka med informative anmeldelser, forslag og korreksjoner: Selv om dette uten tvil ikke er en komplett liste, ville denne boka være ukomplett og ukorrekt uten hjelp fra: David Anderson, Jani Averbach, Ryan Barrett, François Beausoleil, Jennifer Bevan, Matt Blais, Zack Brown, Martin Buchholz, Brane Čibej, John R. Daily, Peter Davis, Olivier Davy, Robert P. J. Day, Mo DeJong, Brian Denny, Joe Drew, Nick Duffek, Ben Elliston, Justin Erenkrantz, Shlomi Fish, Julian Foad, Chris Foote, Martin Furter, Dave Gilbert, Eric Gillespie, David Glasser, Matthew Gregan, Art Haas, Eric Hanchrow, Greg Hudson, Alexis Huxley, Jens B. Jorgensen, Tez Kamihira, David Kimdon, Mark Benedetto King, Andreas J. König, Nuutti Kotivuori, Matt Kraai, Scott Lamb, Vincent Lefevre, Morten Ludvigsen, Paul Lussier, Bruce A. Mah, Philip Martin, Féliciano Matias, Patrick Mayweg, Gareth McCaughan, Jon Middleton, Tim Moloney, Christopher Ness, Mats Nilsson, Joe Orton, Amy Lyn Pilato, Kevin Pilch-Bisson, Dmitriy Popkov, Michael Price, Mark Proctor, Steffen Prohaska, Daniel Rall, Jack Repenning, Tobias Ringström, Garrett Rooney, Joel Rosdahl, Christian Sauer, Larry Shatzer, Russell Steicke, Sander Striker, Erik Sjölund, Johan Sundström, John Szakmeister, Mason Thomas, Eric Wadsworth, Colin Watson, Alex Waugh, Chad Whitacre, Josef Wolf, Blair Zajac, og hele Subversion-fellesskapet.

Fra Ben Collins-Sussman

Thanks to my wife Frances, who, for many months, got to hear, But honey, I’m still working on the book, rather than the usual, But honey, I’m still doing email. I don’t know where she gets all that patience! She’s my perfect counterbalance.

Thanks to my extended family and friends for their sincere encouragement, despite having no actual interest in the subject. (You know, the ones who say, Ooh, you wrote a book?, and then when you tell them it’s a computer book, sort of glaze over.)

Thanks to all my close friends, who make me a rich, rich man. Don’t look at me that way—you know who you are.

Thanks to my parents for the perfect low-level formatting, and being unbelievable role models. Thanks to my son for the opportunity to pass that on.

Takk til min kone Frances, som i mange måneder måtte høre Men kjære, jeg jobber fortsatt på boka, istedenfor den vanlige Men kjære, jeg holder fortsatt på med eposten. Jeg vet ikke hvor hun får all tålmodigheten fra! Hun er min perfekte motvekt.

Takk til min storfamilie og mine venner for deres oppriktige oppmuntring, til tross for at de ikke har noen egentlig interesse for emnet. (Du vet, de som sier Åååja, du har skrevet ei bok?, og når du forteller at det er ei bok om datamaskiner, forsvinner stjerneglansen i øynene deres.)

Takk til alle mine nære venner, som gjør meg til en rik, rik mann. Ikke se på meg på den måten – dere vet hvem dere er.

Takk til foreldrene mine for den perfekte grunnformateringen, og for at de er noen utrolige rollemodeller. Takk til sønnen min for muligheten til å føre det videre.

Fra Brian W. Fitzpatrick

Huge thanks to my wife Marie for being incredibly understanding, supportive, and most of all, patient. Thank you to my brother Eric who first introduced me to UNIX programming way back when. Thanks to my Mom and Grandmother for all their support, not to mention enduring a Christmas holiday where I came home and promptly buried my head in my laptop to work on the book.

To Mike and Ben: It was a pleasure working with you on the book. Heck, it’s a pleasure working with you at work!

To everyone in the Subversion community and the Apache Software Foundation, thanks for having me. Not a day goes by where I don’t learn something from at least one of you.

Lastly, thanks to my Grandfather who always told me that freedom equals responsibility. I couldn’t agree more.

Kjempestor takk til min kone Marie for å være utrolig forståelsesfull, støttende og mest av alt, tålmodig. Takk til min bror Eric som først introduserte meg til UNIX-programmering langt tilbake i tiden. Takk til min mor og bestemor for all deres støtte, for ikke å nevne å holde ut en juleferie hvor jeg kom hjem og med en gang begravde hodet i laptopen for å arbeide på boka.

Til Mike og Ben: Det var en glede å jobbe med dere på boka. Søren heller, det er en glede å arbeide med dere på jobben!

Til alle i Subversion-miljøet og Apache Software Foundation, takk for at dere har meg. Det går ikke en dag uten at jeg lærer noe fra ihvertfall en av dere.

Til sist, takk til min bestefar som alltid fortalte meg at frihet er lik ansvarlighet. Jeg kunne ikke være mer enig.

Fra C. Michael Pilato

Special thanks to my wife, Amy, for her love and patient support, for putting up with late nights, and for even reviewing entire sections of this book—you always go the extra mile, and do so with incredible grace. Gavin, when you’re old enough to read, I hope you’re as proud of your Daddy as he is of you. Mom and Dad (and the rest of the family), thanks for your constant support and enthusiasm.

Hats off to Shep Kendall, through whom the world of computers was first opened to me; Ben Collins-Sussman, my tour-guide through the open-source world; Karl Fogel—you are my .emacs; Greg Stein, for oozing practical programming know-how; Brian Fitzpatrick—for sharing this writing experience with me. To the many folks from whom I am constantly picking up new knowledge—keep dropping it!

Finally, to the One who perfectly demonstrates creative excellence—thank you.

Spesiell takk til min kone Amy for hennes kjærlighet og tålmodige støtte, for å holde ut med sene kvelder, og for å til og med se over hele seksjoner av denne boka – du går alltid den ekstra milen, og gjør det med utrolig ynde. Gavin, når du er gammel nok til å lese, håper jeg du er like stolt av faren din som han er av deg. Mor og Far (og resten av familien), takk for deres konstante støtte og entusiasme.

Hatten av for Shep Kendall, gjennom ham ble verdenen av datamaskiner først åpnet for meg; Ben Collins-Sussman, min turguide gjennom open source-verdenen; Karl Fogel – du er min .emacs; Greg Stein, for å utstråle praktisk know-how innen programmering; Brian Fitz – for å dele denne skriveopplevelsen med meg. Til de mange folkene som jeg til stadighet plukker opp ny kunnskap etter – fortsett med å strø den omkring!

Til sist, til den Ene som så perfekt demonstrerer kreativ fortreffelighet – takk.

Hva er Subversion?

Subversion er et fritt/opensource versjonskontrollsystem. Det betyr: Subversion behandler filer og kataloger og forandringene i dem over tid. Dette lar deg hente fram eldre versjoner av dataene dine, eller studere historien for hvordan dataene dine har forandret seg. På grunn av dette tenker mange på et versjonskontrollsystem som en slags tidsmaskin.

Subversion kan operere over datanettverk, der flere personer kan bruke det på forskjellige maskiner. På et visst nivå gir muligheten for forskjellige personer til å modifisere og behandle den samme datamengden seg utslag i samarbeid. Fremgangen kan gå fortere uten en trang flaskehals som alle forandringene må gå gjennom. Og fordi arbeidet er versjonert, trenger du ikke frykte at kvaliteten er noe du må gi avkall på når du mister denne flaskehalsen – hvis en feil forandring er gjort i dataene, er det bare å omgjøre denne forandringen.

Noen versjonskontrollsystemer er også software configuration management-systemer (SCM). Disse systemene er spesielt beregnet på å vedlikeholde trær av kildekode, og har mange funksjoner som er spesielt tilpasset programutvikling – de kan ha en viss forståelse av programmeringsspråk, eller de tilbyr verktøy for å bygge programvare. Subversion, derimot, er ikke et av disse systemene. Det er et generelt system som kan bli brukt til å vedlikeholde en hvilken som helst samling av filer. For ditt vedkommende kan det være kildekode – for andre, alt fra huskelister til butikken til redigeringsfiler for digital video og annet.

Subversions historie

Tidlig i år 2000 startet CollabNet, Inc. (http://www.collab.net) letingen etter utviklere for å lage en erstatning for CVS. CollabNet tilbyr programvare for å muliggjøre samarbeid – CollabNet Enterprise Edition (CEE)[2] – der en komponent er versjonskontroll. Selv om CEE brukte CVS som sitt første versjonskontrollsystem, var begrensningene i CVS helt fra begynnelsen veldig tydelige, og CollabNet visste at noe bedre måtte finnes på et eller annet tidspunkt. Uheldigvis hadde CVS blitt de facto-standarden i opensource-verdenen fordi det ikke fantes noe bedre, ihvertfall ikke under en fri lisens. Så CollabNet gikk inn for å skrive et nytt versjonskontrollsystem fra bunnen av, basert på de grunnleggende idéene fra CVS, men uten feilene og manglende funksjoner.

I februar 2000 kontaktet de Karl Fogel, forfatteren av Open Source Development with CVS (Coriolis, 1999), og spurte om han ville arbeide på dette nye prosjektet. Tilfeldigvis diskuterte Karl på dette tidspunktet et design for et nytt versjonskontrollsystem med sin venn Jim Blandy. I 1995 startet de to Cyclic Software, et firma som tilbød kontrakter for CVS-støtte, og selv om de senere solgte forretningen, brukte de fortsatt CVS hver dag på jobben. Frustrasjonen deres over CVS hadde fått Jim til å tenke nøye over bedre veier til å behandle versjonerte data, og han hadde allerede kommet opp med ikke bare navnet Subversion, men også med den grunnleggende designen av datalagringen i Subversion. Da forespørselen kom fra CollabNet, gikk Karl øyeblikket med på å arbeide med prosjektet, og Jim fikk sin arbeidsgiver, Red Hat Software, til å hovedsaklig donere ham til prosjektet for en udefinert tidsperiode. CollabNet ansatte Karl og Ben Collins-Sussman, og detaljert designarbeid startet i mai. Med hjelp av noen velplasserte nålestikk fra Brian Behlendorf, Jason Robbins fra CollabNet og Greg Stein (på den tiden en uavhengig utvikler aktiv innen spesifiseringsprosessen for WebDAV/DeltaV), fikk Subversion raskt trukket til seg en samling aktive utviklere. Det viste seg at mange hadde hatt de samme frustrerende opplevelsene med CVS, og ønsket sjansen til å endelig få gjort noe med dette velkommen.

Den originale designgruppen satte seg enkle mål. De ville ikke bryte nytt land innen versjonskontrollteknikken, de ville bare forbedre CVS. De bestemte seg for at Subversion skulle ha de samme funksjonene som CVS og beholde den samme utviklingsmodellen, men uten de mest åpenbare feilene i CVS. Og selv om det nødvendigvis ikke skulle være en fullstendig erstatning for CVS, skulle det være likt nok til at enhver CVS-bruker kunne gjennomføre overgangen med små anstrengelser.

Etter fjorten måneder med programmering ble Subversion selvlagrende den 31. august 2001. Det betydde at Subversionutviklerne avsluttet bruken av CVS til å vedlikeholde Subversions kildekode, og gikk over til å bruke Subversion istedenfor.

Selv om CollabNet startet prosjektet, og fortsatt finansierer en stor del av arbeidet (de betaler lønningene for noen få fulltidsansatte Subversionutviklere), drives Subversion som de fleste opensource-prosjekter, styrt av et løst sammensatt og gjennomsiktig regelverk som oppmuntrer til elitestyre. CollabNets copyrightlisens er fullstendig i samsvar med Debians retningslinjer for fri programvare – Debian Free Software Guidelines. Med andre ord, alle kan hente, modifisere og redistribuere Subversion som de selv ønsker; ingen tillatelse fra CollabNet eller andre er nødvendig.

Subversions fordeler

Når vi diskuterer funksjonalitetene som Subversion bringer til versjonskontrollbordet, hjelper det ofte å snakke om dem i vendinger som beskriver hvordan de er forbedringer i forhold til måten CVS er konstruert. Hvis du ikke er vant med CVS, er det ikke sikkert du forstår alle disse funksjonene. Og hvis du ikke er kjent med versjonskontroll i det hele tatt, kan nok blikket sløves såfremt du ikke har lest Kapittel 1, Grunnleggende konsepter, hvor vi foretar en forsiktig introduksjon til versjonskontroll.

Subversion tilbyr:

Versjonering av kataloger

CVS holder bare rede på historien til individuelle filer, men Subversion implementerer et virtuelt versjonert filsystem som følger forandringer til hele katalogtrær over tid. Filer og kataloger er versjonert.

Sann versjonshistorie

Siden CVS er begrenset til versjonering av filer, er ikke operasjoner som kopiering og navneskifter – som kan hende med filer, men som egentlig er forandringer i innholdet av katalogen de ligger i – støttet i CVS. I tillegg kan du ikke i CVS erstatte en versjonert fil med en ny ting med det samme navnet uten at det nye elementet overtar historien til den gamle – kanskje helt urelaterte – fila. Med Subversion kan du legge til, slette, kopiere og skifte navn på både filer og kataloger. Og hver fil som er nylig lagt til begynner med en frisk, ren historie helt for seg selv.

Atomisk innlegging

En samling av forandringer går enten fullstendig inn i depotet, eller ikke i det hele tatt. Dette tillater utviklerne å konstruere og legge inn forandringer som logiske porsjoner, og forhindrer problemer som kan oppstå når bare en del av forandringene ble lagt inn i depotet.

Versjonerte metadata

Hver fil og katalog har et sett med egenskaper – egenskapsnavn og deres verdier – assossiert med seg. Du kan opprette og lagre ethvert vilkårlig egenskapsnavn/verdi-par som du ønsker. Egenskaper er versjonert over tid, akkurat som filinnhold.

Valg av nettverkslag

Subversion har et løst definert begrep om depottilgang, noe som gjør det enkelt for brukere å implementere nye nettverksmekanismer. Subversion kan plugges inn i Apache HTTP-serveren som en tilleggsmodul. Dette gir Subversion en stor fordel innen stabilitet og kommunikasjon med brukere og prosesser, og øyeblikkelig tilgang til eksisterende funksjoner som denne serveren tilbyr – autentisering, autorisasjon, wire compression og så videre. En lettere egenstående Subversionserver-prosess er også tilgjengelig. Denne serveren snakker en tilpasset protokoll som lett kan bli kjørt gjennom en SSH-tunnel.

Konsekvent databehandling

Subversion uttrykker filforskjeller ved en binær forskjellsalgoritme som fungerer likt både på tekst (lesbar for det menneskelige øye) og binære (uleselige for mennesker) filer. Begge filtypene pakkes på samme måte i depotet, og forskjeller blir overført i begge retninger over nettverket.

Effektiv forgrening og merking

Belastningen ved å lage en gren eller merke trenger ikke å være proporsjonal med prosjektstørrelsen. Subversion lager forgreninger og merker ved å rett og slett kopiere prosjektet, ved hjelp av en mekanisme lik en hard lenke. Dermed tar disse operasjonene bare en liten, konstant mengde tid.

Hackervennlighet

Subversion har ingen historisk bagasje; programmet er implementert som en samling av delte C-biblioteker med veldefinerte programmeringsgrensesnitt. Dette gjør Subversion ekstremt lett å vedlikeholde og lett å bruke av andre applikasjoner og språk.

Subversions arkitektur

Figur 1, “Subversions arkitektur” illustrerer en milehøy oversikt over Subversions design.

Figur 1. Subversions arkitektur

Subversions arkitektur


På den ene kanten er et Subversiondepot som inneholder alle dine versjonerte data. I den andre enden er Subversionklienten din, som holder rede på lokale avspeilinger av deler av disse versjonerte dataene (kalt arbeidskopier). Mellom disse yttergrensene er det flere ruter gjennom diverse tilgangslag – Repository Access (RA). Noen av disse rutene går over datanettverk og gjennom dataservere som deretter aksesserer depotet. Andre dropper hele nettverket og bruker direkte tilgang til depotet.

Subversions komponenter

Subversion, installasjonen er ferdig, består av flere deler. Det følgende er en rask oversikt over hva du får. Ikke bli skremt hvis den snaue beskrivelsen etterlater deg med å klø deg i hodet – det er mange flere sider i denne boka som er beregnet på å fjerne denne forvirringen.

svn

Kommandolinjeklienten.

svnversion

Et program for å rapportere tilstanden (i betydningen av revisjoner for de elementene som finnes) for en arbeidskopi.

svnlook

Et verktøy for å inspisere et Subversiondepot direkte.

svnadmin

Et verktøy for å lage, tilpasse eller reparere et Subversiondepot.

svndumpfilter

Et program for å filtrere strømmer i dumpfil-format for et Subversiondepot.

mod_dav_svn

En programtilleggsmodul for Apache HTTP-serveren, som brukes til å gjøre depotet ditt tilgjengelig for andre over et nettverk.

svnserve

Et tilpasset selvstendig serverprogram, kjørbar som en daemon-prosess eller startbar av SSH; en annen måte å gjøre depotet ditt tilgjengelig for andre over et nettverk.

svnsync

Et program for inkrementell speiling av et depot til et annet over et nettverk.

Forutsatt at du har Subversion korrekt installert, er du klar til å starte. De neste to kapitlene vil vise deg bruken av svn, Subversions klient for kommandolinjebruk.




[1] Å, og takk, Karl, for at du er for overarbeidet til å skrive denne boka selv.

[2] Det finnes også en versjon kalt CollabNet Team Edition (CTE) som er beregnet på mindre grupper.

Kapittel 1. Grunnleggende konsepter

Dette kapittelet er en kort, lettvint introduksjon til Subversion. Hvis du er ny innen versjonskontroll, er dette kapittelet definitivt for deg. Vi begynner med en diskusjon om generelle konsepter innen versjonskontroll, jobber oss gjennom de spesifikke idéene bak Subversion, og viser noen enkle eksempler på bruk av Subversion.

Selv om eksemplene i dette kapittelet viser personer som deler samlinger av kildekode til programmer, husk at Subversion kan behandle alle typer filsamlinger – det er ikke begrenset til å hjelpe dataprogrammerere.

Depotet

Subversion er et sentralisert system for å dele informasjon. Dens kjerne er et depot, som er et sentralt lager av data. Depotet lagrer informasjon i form av et filsystemtre – et typisk hierarki av filer og kataloger. Ethvert antall klienter kobler seg til depotet, og leser eller skriver deretter til disse filene. Ved å skrive data, gjør klienten informasjonen tilgjengelig for andre; ved å lese data henter klienten informasjon fra andre. Figur 1.1, “Et typisk klient/server-system” illustrerer dette.

Figur 1.1. Et typisk klient/server-system

Et typisk klient/server-system


Så hvorfor er dette interessant? Så langt høres dette ut som definisjonen av en typisk filserver. Og det stemmer, depotet er en slags filserver, men ikke den typen du vanligvis kommer ut for. Det som gjør Subversiondepotet spesielt er at det husker hver eneste forandring noensinne skrevet til det: Hver forandring til hver eneste fil, og til og med forandringer i selve katalogtreet, som opprettelser, slettinger og ommøbleringer i filer og kataloger.

Når en klient leser data fra depotet, ser den vanligvis bare den siste versjonen av filsystemtreet. Men klienten har også muligheten til å se tidligere tilstander av filsystemet. For eksempel, en klient kan spørre historiske spørsmål som: Hva inneholdt denne katalogen forrige onsdag? eller Hvem var den siste personen som forandret denne fila, og hvilke forandringer gjorde vedkommende? Dette er typen spørsmål som er hjertet av ethvert versjonskontrollsystem: Systemer som er designet for å lagre og følge forandringer i data over tid.

Versjoneringsmodeller

Hovedmålet for et versjonskontrollsystem er å muliggjøre samarbeidsredigering og deling av data. Men forskjellige systemer bruker forskjellige strategier for å oppnå dette. Det er viktig å forstå disse forskjellige strategiene av et par grunner. For det første vil det hjelpe deg å sammenlige og danne kontrast mot andre systemer som ligner på Subversion. Utenom det, vil det også hjelpe deg til å effektivisere bruken av Subversion, siden Subversion selv støtter et par forskjellige arbeidsmåter.

Problemet med fildeling

Alle versjonskontrollsystemer må løse det samme fundamentale problemet: Hvordan vil systemet tillate brukere å dele informasjon, men forhindre dem fra å tråkke hverandre på tærne? Det er alt for lett for brukere å overskrive hverandres forandringer i depotet ved en ulykke.

Tenk over scenariet vist i Figur 1.2, “Problemet som må unngås”. Sett at vi har to arbeidskolleger, Harry og Sally. De bestemmer seg begge for å redigere den samme fila i depotet samtidig. Hvis Harry lagrer sine forandringer til depotet først, er det (noen øyeblikk senere) mulig at Sally feilaktig overskriver dem med hennes egen nye versjon av fila. Selv om Harrys versjon av fila ikke vil være tapt for alltid (fordi systemet husker hver eneste forandring), vil alle forandringene Harry gjorde ikke være med i Sallys nyere versjon av fila, fordi hun så aldri Harrys forandringer til å begynne med. Harrys arbeid er fortsatt borte – eller i det minste borte fra den siste versjonen av fila – og sannsynligvis ved en ulykke. Dette er definitivt en situasjon vi vil unngå!

Figur 1.2. Problemet som må unngås

Problemet som må unngås


Lås-rediger-lås opp-løsningen

Mange versjonskontrollsystemer bruker en modell av typen lås-rediger-lås opp når de tar for seg problemet med at mange forfattere roter til hverandres arbeid. I denne modellen tillater depotet bare en person å forandre en fil om gangen. Denne eksklusive arbeidsmåten styres ved bruk av låser. Harry må låse ei fil før han kan begynne å gjøre forandringer i den. Hvis Harry har låst ei fil, kan ikke Sally også låse den, og kan derfor ikke gjøre noen forandringer i denne fila. Alt hun kan gjøre er å lese fila og vente på at Harry gjør seg ferdig med sine forandringer og så slipper låsen han har satt opp. Etter at Harry låser opp fila kan Sally ta sin runde med å låse og redigere fila. Figur 1.3, “Lås-rediger-lås opp-løsningen” demonstrerer denne enkle løsningen.

Figur 1.3. Lås-rediger-lås opp-løsningen

Lås-rediger-lås opp-løsningen


Problemet med lås-rediger-lås opp-metoden er at den er ganske restriktiv, og blir ofte en hindring for brukerne:

  • Låsing kan medføre administrative problemer. Noen ganger hender det at Harry låser ei fil og glemmer den. I mellomtiden, fordi Sally fortsatt venter på å få redigere fila, har hun hendene bundet. Og så drar Harry på ferie. Nå må Sally få en administrator til å fjerne Harrys lås. Situasjonen ender opp med mange forsinkelser og mye bortkastet tid.

  • Låsing kan forårsake unødvendig serialisering. Hva hvis Harry redigerer begynnelsen av en tekstfil, og Sally rett og slett bare vil redigere slutten av den samme fila? Disse forandringene overlapper ikke i det hele tatt. De kan enkelt redigere fila samtidig, og ingen stor skade vil skje, såfremt forandringene ble flettet fint sammen. Det er ingen vits i at de må vente på tur i denne situasjonen.

  • Låsing kan skape en falsk følelse av trygghet. Tenk deg at Harry låser og redigerer fil A, mens Sally samtidig låser og redigerer fil B. Men hva hvis A og B er avhengig av hverandre, og forandringene som er lagt til hver av filene er semantisk inkompatible med hverandre? Plutselig virker ikke A og B sammen mer. Låsesystemet var ikke i stand til å forhindre problemet – men skapte likevel en falsk følelse av trygghet. Det er lett for Harry og Sally å tenke seg at ved å låse filer, starter hver av dem en trygg, isolert oppgave, og de bryr seg dermed ikke med å diskutere deres inkompatible forandringer på et tidligere tidspunkt. Låsing blir ofte en erstatning for skikkelig kommunikasjon.

Kopier-rediger-flett-løsningen

Subversion, CVS og en rekke andre versjonskontrollsystemer bruker en modell av typen kopier-rediger-flett som et alternativ til låsing. I denne modellen kontakter klienten til hver bruker prosjektdepotet og lager en personlig arbeidskopi – et lokalt speil av depotets filer og kataloger. Brukere arbeider så parallelt og uavhengig med å modifisere deres private kopier. Til slutt blir de private kopiene flettet inn i en ny, endelig versjon. Versjonskontrollsystemet hjelper ofte til med flettingen, men til syvende og sist er det et menneske som er ansvarlig for å la det skje skikkelig.

Her er et eksempel. La oss si at Harry og Sally hver for seg lager arbeidskopier av det samme prosjektet, kopiert fra depotet. De arbeider samtidig, og gjør forandringer i den samme fila A innenfor sine kopier. Sally lagrer sine forandringer til depotet først. Når Harry prøver å lagre sine forandringer senere, informerer depotet ham om at hans fil A er utdatert. Med andre ord, fil A i depotet har på en eller annen måte forandret seg siden han kopierte den sist. Så Harry ber klienten sin om å flette alle nye forandringer fra depotet inn i hans arbeidskopi av fil A. Sjansene for at Sallys forandringer ikke overlapper med hans egne er store; så når begges forandringer er lagt inn i fila, lagrer han sin egen arbeidskopi til depotet. Figur 1.4, “Kopier-rediger-flett-løsningen” og Figur 1.5, “Kopier-rediger-flett-løsningen (forts.)” viser denne prosessen.

Figur 1.4. Kopier-rediger-flett-løsningen

Kopier-rediger-flett-løsningen


Figur 1.5. Kopier-rediger-flett-løsningen (forts.)

Kopier-rediger-flett-løsningen (forts.)


Men hva hvis Sallys forandringer likevel overlapper med Harrys forandringer? Hva da? Denne situasjonen kalles en konflikt, og er vanligvis ikke mye til problem. Når Harry ber klienten sin om å flette sammen de nyeste forandringene i depotet inn i hans arbeidskopi, blir det vist at hans kopi av fil A er i konflikt: Han vil være i stand til å se begge settene av konfliktskapende forandringer, og velge mellom dem manuelt. Legg merke til at programvare ikke kan løse konflikter automatisk; bare mennesker er i stand til å forstå og gjøre de nødvendige intelligente valgene. Når Harry har løst de overlappende forandringene manuelt – kanskje etter en diskusjon med Sally – kan han trygt lagre den flettede fila tilbake til depotet.

Kopier-rediger-flett-modellen kan høres litt kaotisk ut, men i praksis går det ekstremt glatt. Brukere kan jobbe parallelt, og aldri vente på hverandre. Når de arbeider på de samme filene, viser det seg at mesteparten av de samtidige forandringene ikke overlapper i det hele tatt; konflikter er sjeldne. Og tiden det tar å løse konflikter er vanligvis langt mindre enn tiden tapt med et låsesystem.

Til sist koker det hele ned til en kritisk faktor: Brukerkommunikasjon. Når brukerne kommuniserer dårlig, øker antallet av både programmessige og språkmessige konflikter. Ingen systemer kan tvinge brukerne til å kommunisere perfekt, og ingen systemer kan oppdage språkmessige konflikter. Så, det er ikke mye poeng i å bli lurt av et falskt løfte om at et låsesystem på en eller annen måte vil forhindre konflikter; i praksis ser låsing ut til å hemme produktiviteten mer enn noe annet.

Subversion i aksjon

Det er på tide å gå fra det abstrakte til det konkrete. I denne seksjonen vil vi vise reelle eksempler på bruk av Subversion.

Depot-URLer i Subversion

Gjennom denne boka bruker Subversion URLer for å identifisere versjonerte ressurser i Subversion-depoter. For det meste bruker disse URLene standard syntaks, som tillater servernavn og portnummer å bli spesifisert som en del av URLen:

$ svn checkout http://svn.example.com:9834/repos
…

Men det er noen nyanser i Subversions behandling av URLer som legges merke til. For eksempel, URLer som bruker file:-aksesseringsmetoden (brukt for lokale depoter) må, i henhold til konvensjonene, enten ha servernavnet localhost eller ikke noe servernavn:

$ svn checkout file:///sti/til/depot
…
$ svn checkout file://localhost/sti/til/depot
…

I tillegg må brukere av file:-skjemaet på MS Windows-plattformer bruke en uoffisiell standard syntaks for å aksessere depoter smo er på den samme maskinen, men på en annen disk enn klientens nåværende arbeidsdisk. En av de to følgende URL-syntaksene vil virke der X er disken hvor depotet ligger:

C:\> svn checkout file:///X:/sti/til/depot
…
C:\> svn checkout "file:///X|/sti/til/depot"
…

I den andre syntaksen må du sette URLen i hermetegn ("") så det vertikale stolpetegnet ikke blir tolket som et rør. Legg også merke til at en URL bruker vanlige skråstreker (/) selv om den lokale (ikke-URL) formen i en sti i MS Windows bruker omvendte skråstreker (\).

Til slutt må det legges merke til at Subversionklienten automatisk vil kode URLer etter behov, akkurat som en nettleser gjør det. For eksempel, hvis en URL inneholder et mellomrom eller store bokstaver:

$ svn checkout "http://server/sti med mellomrom/prosjekt/españa"

… så vil Subversion beskytte de usikre tegnene og oppføre seg som om du hadde skrevet:

$ svn checkout http://server/sti%20med%20mellomrom/prosjekt/espa%C3%B1a

Hvis URLen inneholder mellomrom, pass på å plassere den innenfor hermetegn, så skallet behandler hele URLen som et enkelt argument til svn-programmet.

Arbeidskopier

Du har allerede lest om arbeidskopier; nå skal vi demonstrere hvordan Subversionklienten lager og bruker dem.

En arbeidskopi i Subversion er et vanlig katalogtre på ditt lokale system, og inneholder en samling filer. Du kan redigere disse filene sånn som du vil, og hvis det er kildekode, kan du kompilere programmet på den vanlige måten. Arbeidskopien din er ditt eget private arbeidsområde: Subversion vil aldri legge inn andre folks forandringer, heller ikke gjøre dine egne forandringer tilgjengelig for andre før du eksplisitt ber programmet om å gjøre det. Du kan til og med ha flere arbeidskopier av det samme prosjektet.

Etter at du har gjort noen forandringer i filene i arbeidskopien og sjekket at de virker skikkelig, gir Subversion deg kommandoer så du kan publisere forandringene dine til de andre som arbeider med deg på prosjektet ditt (ved å skrive til depotet). Hvis andre personer publiserer deres egne forandringer, gir Subversion deg kommandoer for å flette disse forandringene inn i din arbeidskopi (ved å lese fra depotet).

En arbeidskopi inneholder også noen ekstra filer, opprettet og vedlikeholdt av Subversion, for å hjelpe seg med å utføre disse kommandoene. Hver katalog i arbeidskopien inneholder en underkatalog kalt .svn, også kjent som arbeidskopiens administrative katalog. Filene i hver administrative katalog hjelper Subversion til å se hvilke filer som inneholder upubliserte forandringer, og hvilke filer som er utdaterte i forhold til andres arbeid.

Et typisk Subversiondepot inneholder ofte filene (eller kildekoden) for flere prosjekter; vanligvis har hvert prosjekt sin egen underkatalog i depotets filsystemtre. Med dette arrangementet vil en brukers arbeidskopi samsvare med et spesielt deltre av depotet.

For eksempel, tenk deg at du har et depot som består av to programprosjekter, paint og calc. Hvert prosjekt bor i hver sin toppkatalog, som vist i Figur 1.6, “Depotets filsystem”.

Figur 1.6. Depotets filsystem

Depotets filsystem


For å få deg en arbeidskopi, må du først hente ut (check out) et del av et katalogtre fra depotet. (Det engelske uttrykket check out kan høres ut som det har noe å gjøre med låsing eller reservering av ressurser, men det har ikke det; det lager bare en privat kopi av prosjektet for deg.) For eksempel, hvis du henter ut /calc, vil du få en arbeidskopi som dette:

$ svn checkout http://svn.example.com/repos/calc
A    calc/Makefile
A    calc/integer.c
A    calc/button.c
Checked out revision 56.

$ ls -A calc
Makefile  integer.c  button.c  .svn/

Listen med bokstaven A indikerer at Subversion legger til et antall elementer i arbeidskopien din. Du har nå en personlig kopi av depotets /calc-katalog, med en ekstra komponent – .svn – som tidligere nevnt inneholder den ekstra informasjonen som Subversion trenger.

Tenk at du gjør forandringer til button.c. Siden .svn-katalogen husker filens modifiseringsdato og originale innhold, kan Subversion se at du har forandret fila. Men Subversion offentliggjør ikke dine forandringer før du eksplisitt ber programmet om å gjøre det. Prosessen når du publiserer dine forandringer blir vanligvis omtalt som å legge inn (eller sende/sjekke inn) forandringer til depotet.

For å publisere dine forandringer til andre, kan du bruke Subversions commit-kommando.

$ svn commit button.c -m "Ordnet en skrivefeil i button.c ."
Sender        button.c
Sender fildata .
La inn revisjon 57.

Nå er dine forandringer til button.c lagt inn i depotet, med en melding som beskriver forandringen din (at du ordnet en skrivefeil). Hvis en annen bruker henter ut en arbeidskopi av /calc, vil de se dine forandringer i den seneste versjonen av fila.

Tenk deg at du har en samarbeidspartner, Sally, som hentet ut en arbeidskopi av /calc samtidig med deg. Når du legger inn din forandring til button.c, er Sallys arbeidskopi uforandret; Subversion modifiserer bare arbeidskopier etter brukerens ønske.

For å få sitt prosjekt oppdatert, kan Sally be Subversion om å oppdatere hennes arbeidskopi, ved å bruke Subversionkommandoen update. Dette vil legge inn dine forandringer inn i hennes arbeidskopi, så vel som alle andre forandringer som er blitt lagt inn i depotet siden hun sist hentet det ut.

$ pwd
/home/sally/calc

$ ls -A 
.svn/ Makefile integer.c button.c

$ svn update
U    button.c
Updated to revision 57.

Utdataene fra kommandoen svn update indikerer at Subversion oppdaterte innholdet av button.c. Legg merke til at Sally ikke trengte å spesifisere hvilke filer som skulle oppdateres, Subversion bruker informasjonen i .svn-katalogen sammen med annen informasjon i depotet for å bestemme hvilke filer som trenger en oppdatering.

Revisjoner

En svn commit-operasjon publiserer forandringer til et vilkårlig antall filer og kataloger som en enkeltstående atomisk transaksjon. I arbeidskopien din kan du forandre filenes innhold, opprette, slette, skifte navn og kopiere filer og kataloger, og så legge inn et komplett sett med forandringer som en atomisk transaksjon.

Med atomisk transaksjon mener vi rett og slett dette: Enten skjer alle forandringene i depotet, eller ingen av dem skjer. Subversion prøver å beholde denne atomiteten stilt opp mot programkræsj, systemkræsj, nettverksproblemer og andre brukeres aktiviteter.

Hver gang depotet aksepterer en innlegging, opprettes det en ny tilstand i filsystemtreet, kalt en revisjon. Hver revisjon blir tildelt et unikt naturlig tall, ett større enn nummeret på den forrige revisjonen. Den første revisjonen i et nyopprettet depot har nummeret null, og inneholder ingenting annet enn en tom rotkatalog.

Figur 1.7, “Depotet” illustrerer en fin måte å visualisere depotet på. Tenk deg en rekke av revisjonsnumre som starter på 0 og strekker seg fra venstre mot høyre. Hvert revisjonsnummer har et filsystemtre hengende under seg, og hvert tre er et øyeblikksbilde av hvordan depotet så ut etter en innlegging.

Figur 1.7. Depotet

Depotet


Det er viktig å notere seg at arbeidskopier ikke bestandig samsvarer med en enkelt revisjon i depotet; de kan inneholde filer fra flere forskjellige revisjoner. For eksempel, tenk at du henter ut en arbeidskopi fra et depot der den siste revisjonen er 4:

calc/Makefile:4
     integer.c:4
     button.c:4

For øyeblikket samsvarer arbeidskopien nøyaktig med revisjon 4 i depotet. Men tenk deg så at du gjør en forandring i button.c, og legger inn denne forandringen. Forutsatt at ingen andre innlegginger har forekommet, vil din innlegging opprette revisjon 5 i depotet, og arbeidskopien din vil se ut som dette:

calc/Makefile:4
     integer.c:4
     button.c:5

Så sier vi at Sally på dette tidspunktet legger inn en forandring til integer.c, som lager revisjon 6. Hvis du bruker svn update for å oppdatere arbeidskopien, vil den se ut som dette:

calc/Makefile:6
     integer.c:6
     button.c:6

Sallys forandring i integer.c vil komme til syne i arbeidskopien din, og din forandring vil fortsatt være til stede i button.c. I dette eksempelet er teksten i Makefile identisk i revisjon 4, 5 og 6, men Subversion vil merke kopien av Makefile med revisjon 6 for å indikere at den fortsatt gjelder. Så, etter at du gjør en ren oppdatering fra toppen av arbeidskopien din, vil den vanligvis samsvare med en eksakt revisjon i depotet.

Hvordan arbeidskopier holder følge med depotet

For hver fil i en arbeidskatalog, lagrer Subversion to essensielle deler informasjon i det administrative .svn-området:

  • Hvilken revisjon arbeidsfila di er basert på (dette kalles filas arbeidsrevisjon), og

  • et tidsmerke fra da den lokale kopien sist ble oppdatert av depotet.

Ved hjelp av denne informasjonen kan Subversion ved å kommunisere med depotet se hvilke fire tilstander en arbeidsfil er i:

Uforandret og oppdatert

Fila er uforandret i arbeidskopien, og ingen forandringer til denne fila er blitt lagt inn i depotet siden arbeidskopien ble lagt inn. En svn commit på fila vil ikke gjøre noe som helst, og en svn update på fila vil heller ikke gjøre noe.

Forandret lokalt og samtidig gjeldende

Fila er blitt forandret i arbeidskopien, og ingen forandringer i denne fila er blitt lagt inn i depotet siden sist du oppdaterte. Det er lokale forandringer som ikke er blitt lagt inn i depotet, så en svn commit av fila vil lykkes i å publisere forandringene dine, og en svn update på fila vil ikke gjøre noen ting.

Uforandret og utdatert

Fila er ikke blitt forandret i arbeidskopien, men har forandret seg i depotet. Fila må etterhvert bli oppdatert, for å få den til å samsvare med den nyeste offentlige revisjonen. En svn commit på fila vil ikke gjøre noe, og en svn update på fila vil legge de seneste forandringene inn i arbeidskopien din.

Forandret lokalt og samtidig utdatert

Fila er blitt forandret både i arbeidskopien og depotet. En svn commit av fila vil feile med en out-of-date-feilmelding. Fila må oppdateres først; en svn update-kommando vil prøve å flette inn de offentlige forandringene med de lokale forandringene. Hvis Subversion ikke kan fullføre flettingen automatisk på en skikkelig måte, blir det opp til brukeren å løse konflikten.

Dette kan høres ut som mye å holde greie på, men svn status-kommandoen vil vise deg tilstanden til ethvert element i arbeidskopien din. For mer informasjon om denne kommandoen, se svn status.

Arbeidskopier med blandede revisjonsnumre

Som et generelt prinsipp prøver Subversion å være så fleksibel som mulig. En spesiell type fleksibilitet er muligheten til å ha en arbeidskopi som inneholder filer og kataloger med en blanding av forskjellige arbeidsrevisjonsnumre. Uheldigvis har denne fleksibiliteten en tendens til å forvirre en del nye brukere. Hvis det tidligere eksempelet som viser blandede revisjoner gjør deg litt perpleks, her kommer en forklaring på hvorfor denne funksjonaliteten finnes og hvordan du gjør bruk av den.

Oppdateringer og innlegginger er separate

En av de fundamentale reglene til Subversion er at en skyveoperasjon ikke forårsaker en trekkoperasjon, heller ikke den andre veien. Det at du er klar til å legge inn nye forandringer i depotet betyr ikke at du er klar til å motta forandringer fra andre folk. Og hvis du har nye forandringer som fortsatt er under utvikling, bør svn update flette forandringer i depotet fint og forsiktig inn i dine egne istedenfor å tvinge deg til å publisere dem.

Den største sideeffekten av denne regelen er at det betyr at arbeidskopien må holde ekstra regnskap for å følge med på miksede revisjoner, og også være tolerant i forhold til blandingen. Det blir ytterligere komplisert fordi også selve katalogene er versjonerte.

For eksempel, tenk deg at du har en arbeidskopi der alle elementene er på revisjon 10. Du redigerer fila foo.html og utfører deretter en svn commit som lager revisjon 15 i depotet. Etter at innleggingen er fullført, vil mange brukere forvente at hele arbeidskopien er på revisjon 15, men det er ikke tilfellet! Alle mulige forandringer kan ha skjedd mellom revisjonene 10 og 15. Klienten vet ingenting om disse forandringene i depotet, siden du ikke har kjørt svn update enda, og svn commit ikke henter nye forandringer. Hvis svn commit på den annen side hentet de nyeste forandringene automatisk, ville det være mulig å sette hele arbeidskopien til revisjon 15 – men da ville vi brutt den fundamentale regelen om at skyveoperasjoner og trekkoperasjoner skal være separate handlinger. Derfor, den eneste trygge tingen som Subversionklienten kan gjøre er å kun merke den ene fila – foo.html – som å være på revisjon 15. Resten av arbeidskopien forblir på revisjon 10. Bare ved å kjøre svn update kan de nyeste forandringene bli hentet, og hele arbeidskopien kan merkes som revisjon 15.

Blandede revisjoner er normalt

Faktum er at hver gang du kjører svn commit ender arbeidskopien din opp med en form for blanding av revisjoner. Det elementet som du akkurat la inn er merket som om det har et større revisjonsnummer enn alt det andre. Etter flere innlegginger (uten noen oppdateringer i mellomtiden) vil arbeidskopien din inneholde en stor blanding av revisjoner. Selv om du er den eneste personen som bruker depotet vil du fortsatt se dette fenomenet. For å utforske blandingen din av blandede revisjoner kan du bruke kommandoen svn status --verbose (se svn status for mer informasjon).

Ofte er nye brukere ikke klar over at arbeidskopiene deres inneholder miksede revisjoner. Dette kan være forvirrende, fordi mange klientkommandoer er sensitiv ovenfor arbeidsrevisjonen til elementet som de utforsker. For eksempel, svn log-kommandoen blir brukt til å vise historien til ei fil eller en katalog (se svn log). Når brukeren kjører denne kommandoen på et objekt i arbeidskopien, forventer de å se hele historien til objektet. Men hvis objektets arbeidsrevisjon er ganske gammel (ofte fordi svn update ikke har vært kjørt på aldri så lenge), blir historien til den eldre versjonen av objektet vist.

Blandede revisjoner er nyttige

Forutsatt at prosjektet ditt er komplekst nok, vil du oppdage at det noen ganger er fint å kunne tilbakedatere deler av arbeidskopien til en tidligere revisjon; du vil lære hvordan du gjør dette i Kapittel 2, Grunnleggende bruk. Kanskje vil du prøve en tidligere versjon av en delmodul som ligger i en underkatalog lagret i en underkatalog, eller kanskje du vil finne ut når en feil først oppsto i en spesiell fil. Dette er tidsmaskin-aspektet i et versjonskontrollsystem – funksjonaliteten som lar deg flytte alle deler av arbeidskopien din framover og bakover i historien.

Blandede revisjoner har begrensninger

Hvordan du enn gjør bruk av blandede revisjoner i arbeidskopien din, er det begrensninger i denne fleksibiliteten.

For det første kan du ikke legge inn sletting av ei fil eller en katalog som ikke er fullstendig oppdatert. Hvis en nyere versjon av elementet eksisterer i depotet, vil forsøket ditt på å slette bli avslått, for å forhindre deg å feilaktig ødelegge forandringer som du enda ikke har sett.

For det andre kan du ikke legge inn en metadata-forandring til en katalog hvis den ikke er fullstendig oppdatert. Du vil få lære om å legge til egenskaper til elementer i Kapittel 3, Avanserte emner. En katalogs arbeidsrevisjon definerer et spesifikt sett med poster og egenskaper, og en innlegging av forandringer i en egenskap for en utdatert katalog kan ødelegge egenskaper som du enda ikke har sett.

Oppsummering

Vi har dekket flere fundamentale konsepter for Subversion i dette kapitlet:

  • Vi har introdusert begrepene om et sentralt depot, arbeidskopien til klienten, og rekken av revisjonstrær i depotet.

  • Vi har sett noen enkle eksempler på hvordan to arbeidskolleger kan bruke Subversion til å publisere og motta forandringer til og fra hverandre, ved å bruke kopier-rediger-flett-modellen.

  • Vi har snakket litt om måten Subversion følger og behandler informasjon i en arbeidskopi.

Så langt skal du ha en god oversikt om hvordan Subversion arbeider generelt sett. Bevæpnet med kunnskap er du nå klar til å bevege deg inn i neste kapittel, som er en detaljert gjennomgang av Subversions kommandoer og funksjoner.

Kapittel 2. Grunnleggende bruk

Nå vil vi gå inn i detaljene omkring bruken av Subversion. Når du har nådd slutten av dette kapittelet, vil du være i stand til å utføre omtrent alle de oppgavene du trenger for å bruke Subversion i en vanlig dags arbeid. Du starter med en innledende uthenting av koden din, og går gjennom å gjøre forandringer og studere disse forandringene. Du vil også få se hvordan du legger inn forandringer laget av andre inn i arbeidskopien din, studere dem, og jobbe deg gjennom eventuelle konflikter som måtte oppstå.

Merk at dette kapittelet ikke er ment å være en fullstendig liste over Subversions kommandoer – det er heller en uformell introduksjon til de mest vanlige Subversionoppgavene du vil komme ut for. Dette kapittelet forutsetter at du har lest og forstått Kapittel 1, Grunnleggende konsepter og er kjent med den generelle modellen til Subversion. For en komplett referanse over alle kommandoene, se Kapittel 9, Subversion Complete Reference.

Hjelp!

Før du leser videre, her er den viktigste kommandoen du noen gang vil trenge når du bruker Subversion: svn help. Kommandolinjeklienten til Subversion er selvdokumenterende – til enhver tid vil en rask svn help <delkommando> beskrive syntaksen, valg, og oppførselen til delkommando.

Importering

Du bruker svn import for å importere et nytt prosjekt inn i et Subversiondepot. Selv om dette sannsynligvis er det aller første du vil gjøre når du setter opp Subversionserveren din, er det ikke noe som skjer veldig ofte. For en detaljert beskrivelse av import, se svn import senere i dette kapitlet.

Tidsreiser med Subversion

As discussed in “Revisjoner”, a revision is a snapshot of the repository at a particular moment in time. But the thing that makes Subversion—or any other version control system—useful is not that it keeps all the versions of your files and directories over time. It's that you can actually do something with those older versions! And to do this sort of time travelling, you need a mechanism for identifying revision snapshots.

Revision numbers in Subversion are pretty straightforward—just monotonically increasing integers. When you create a new Subversion repository, it begins its life at revision 0 and each successive commit increases the revision number by one. Subversion doesn't try to hide these numbers—they are a part of the interface you have into the history of your versioned data. For example, after you perform a commit, the Subversion client informs you of the new revision number:

$ svn commit --message "Ordnet antall osteskiver."
Sender        sandwich.txt
Sender fildata .
La inn revisjon 3.

Hvis du på et punkt i fremtiden vil referere til den revisjonen (vi vil se hvordan og hvorfor vi kanskje skulle ønske å gjøre det senere i dette kapitlet), kan du referere til den som 3.

The svn command-line client provides a pair of options for specifying the revisions you wish to operate on. The most common of these is the --revision (-r), which accepts as a parameter either a single revision specifier (-r REV), or a pair of them separated by a colon (-r REV1:REV2). This latter format is used to describe a revision range, useful for commands that compare two revision snapshots or operate on every revision between two specified extremes, inclusively.

Subversion 1.4 introduced a second option for specifying revision ranges, the --change (-c) option. This is basically just a shortcut for specifying a range of revisions whose boundaries are sequential integers. In other words, using -c REV is the same thing as using -r REV-1:REV. And you can trivially reverse the implied range, too, by putting a dash in front of the revision number, as in -c -REV.

Innledende uthenting

Mesteparten av tiden vil du starte bruken av et Subversiondepot ved å utføre en uthenting av prosjektet ditt. Ved å hente ut en revisjon fra et depot lages det en kopi av den lokalt på maskinen. Denne kopien inneholder HEAD (siste revisjon) av Subversiondepotet som du spesifiserer på kommandolinja:

$ svn checkout http://svn.collab.net/repos/svn/trunk
A  trunk/subversion.dsw
A  trunk/svn_check.dsp
A  trunk/COMMITTERS
A  trunk/configure.in
A  trunk/IDEAS
…
Sjekket ut revisjon 2499.

Selv om eksempelet ovenfor henter ut trunk-katalogen, kan du like lettvint hente ut en hvilken som helst dyp underkatalog fra et depot ved å spesifisere underkatalogen i adressen:

$ svn checkout http://svn.collab.net/repos/svn/trunk/doc/book/tools
A  tools/readme-dblite.html
A  tools/fo-stylesheet.xsl
A  tools/svnbook.el
A  tools/dtd
A  tools/dtd/dblite.dtd
…
Sjekket ut revisjon 2499.

Siden Subversion bruker en kopier-rediger-flett-modell istedenfor lås-rediger-lås opp (se Kapittel 1, Grunnleggende konsepter), er du allerede i stand til å gjøre forandringer i arbeidskopien din. Den er som enhver annen samling av filer og kataloger på systemet. Du kan redigere og forandre dem, flytte dem rundt, du kan til og med slette hele arbeidskopien og ikke tenke mer på den.

[Notat]Notat

Selv om arbeidskopien er som enhver annen samling av filer og kataloger på systemet, må du la Subversion få vite om du er på vei til å rearrangere noe i arbeidskopien. Hvis du vil kopiere eller flytte et element i en arbeidskopi, skal du bruke svn copy eller svn move istedenfor kopierings- og flyttekommandoene i operativsystemet. Vi vil snakke mer om dem senere i dette kapitlet.

Såfremt du ikke er klar til å legge inn en ny fil eller katalog, eller forandringer til eksisterende, er det ikke nødvendig å fortelle Subversionserveren at du har gjort noe.

Selv om du så absolutt kan hente ut en arbeidskopi med URLen til depotet som det eneste argumentet, kan du også spesifisere en katalog etter depot-URLen. Dette plasserer arbeidskopien din i den nye katalogen som du gir navn til. For eksempel:

$ svn checkout http://svn.collab.net/repos/svn/trunk subv
A  subv/subversion.dsw
A  subv/svn_check.dsp
A  subv/COMMITTERS
A  subv/configure.in
A  subv/IDEAS
…
Sjekket ut revisjon 2499.

Dette vil plassere arbeidskopien i en katalog kalt subv istedenfor en katalog kalt trunk som vi gjorde tidligere.

Grunnleggende arbeidssyklus

Subversion har mange funksjoner, valg og avanserte muligheter, men på en dag-til-dag-basis er oddsene store for at du bare vil bruke et fåtall av dem. I denne seksjonen vil vi gå gjennom de vanligste tingene som du vil komme ut for med Subversion i løpet av en dags arbeid.

En typisk arbeidssyklus ser ut som dette:

  • Oppdater arbeidskopien din

    • svn update

  • Gjør forandringer

    • svn add

    • svn delete

    • svn copy

    • svn move

  • Se på forandringene dine

    • svn status

    • svn diff

    • svn revert

  • Flett andres forandringer inn i arbeidskopien din

    • svn update

    • svn resolved

  • Legg inn forandringene dine

    • svn commit

Oppdater arbeidskopien din

Når du arbeider på et prosjekt med et team, vil du oppdatere arbeidskopien din med alle forandringer gjort av andre utviklere siden den forrige oppdateringen av prosjektet. Bruk svn update for å få arbeidskopien i synk med den siste revisjonen i depotet.

$ svn update
U  foo.c
U  bar.c
Oppdatert til revisjon 2.

I dette tilfellet har noen andre lagt inn forandringer til både foo.c og bar.c siden forrige gang du oppdaterte, og Subversion har oppdatert arbeidskopien din til å inneholde disse forandringene.

La oss se på utdataene fra svn update litt til. Når serveren sender forandringer til arbeidskopien, blir en bokstavkode vist ved siden av hvert element for å la deg vite hva Subversion gjorde for å oppdatere arbeidskopien:

U foo

Fila foo ble oppdatert (Updated) og mottok forandringer fra serveren.

A foo

Fila eller katalogen foo ble lagt til (Added) i arbeidskopien din.

D foo

Fila eller katalogen foo ble slettet (Deleted) fra arbeidskopien.

R foo

Fila eller katalogen foo ble erstattet (Replaced) i arbeidskopien; det vil si, foo ble slettet og et nytt element med det samme navnet ble lagt til. Selv om de har det samme navnet, anser depotet dem for å være forskjellige objekter med hver sin historie.

G foo

Fila foo mottok nye forandringer fra depotet, mens den lokale kopien av fila inneholdt forandringer gjort av deg. Enten blandet ikke forandringene seg med hverandre, eller de var nøyaktig de samme som dine lokale forandringer, så Subversion klarte å flette (merGe) depotets forandringer uten noen problemer.

C foo

Fila foo mottok forandringer som førte til konflikt (Conflict) med dine egne. Forandringene fra serveren overlapper direkte med dine egne forandringer i fila. Men det er ingen grunn til panikk. Denne overlappingen må bli løst av et menneske (deg); vi diskuterer denne situasjonen senere i dette kapittelet.

Gjør forandringer i arbeidskopien

Nå kan du gå i gang med arbeidet og gjøre forandringer i arbeidskopien. Det er vanligvis mer praktisk å bestemme seg for en spesiell forandring (eller et sett forandringer) som skal gjøres, som å lage en ny funksjonalitet, ordne en feil osv. Subversionkommandoene som du vil bruke her er svn add, svn delete, svn copy og svn move. Hvis du imidlertid bare redigerer filer som allerede finnes i Subversion, trenger du kanskje ikke å bruke noen av disse kommandoene før du legger dem inn. Forandringer som du kan gjøre med arbeidskopien:

Filforandringer

Dette er den enkleste typen forandring. Du trenger ikke å fortelle Subversion at du har tenkt å forandre ei fil; bare sett i gang med forandringene. Subversion vil bli i stand til å automatisk finne ut av hvilke filer som er blitt forandret.

Forandringer i trestrukturen

Du kan spørre Subversion om å merke filer og kataloger for oppførte slettinger, tillegginger, kopieringer eller flytting. Selv om disse forandringene tar plass øyeblikkelig i arbeidskopien din, vil ingen tillegginger eller slettinger skje i depotet før du legger dem inn.

For å gjøre forandringer i filer, bruk teksteditoren din, tekstbehandlingsprogrammet, grafikkprogrammet, eller hvilket som helst verktøy du vanligvis bruker. Subversion behandler binærfiler like lett som tekstfiler – og like effektivt.

Her er en oversikt over de fire delkommandoene i Subversion som du vil bruke oftest for å gjøre forandringer i trestrukturen (vi vil dekke svn import og svn mkdir senere).

[Advarsel]Advarsel

Selv om du kan redigere filene dine med hvilket verktøy du vil, bør du ikke forandre strukturen i arbeidskopien uten å la Subversion vite hva du gjør. Bruk kommandoene svn copy, svn delete og svn move for å forandre strukturen på arbeidskopien, og bruk svn add-kommandoen for å legge inn nye filer og kataloger under versjonskontroll.

svn add foo

Klargjør fila, katalogen eller den symbolske lenken foo for å bli lagt til i depotet. Når du legger inn filene neste gang, vil foo bli et barn av foreldrekatalogen. Legg merke til at hvis foo er en katalog, vil alt under foo også bli klargjort for tillegging. Hvis du bare vil klargjøre bare selve foo, legg til valget --non-recursive (-N).

svn delete foo

Klargjør fila, katalogen eller den symbolske lenken foo for sletting fra depotet. Hvis foo er ei fil eller en lenke, blir den slettet øyeblikkelig fra arbeidskopien. Hvis foo er en katalog, blir den ikke slettet, men klargjort for sletting. Når du legger inn forandringene, vil foo bli slettet fra arbeidskopien og depotet.[3]

svn copy foo bar

Opprett et nytt element bar som en duplikat av foo. bar er automatisk klargjort for tillegging. Når bar blir lagt til depotet under neste innlegging, blir kopieringshistorien lagret (som om den kommer originalt fra foo). svn copy lager ikke mellomliggende kataloger.

svn move foo bar

Denne kommandoen er nøyaktig den samme som å kjøre svn copy foo bar; svn delete foo. Det vil si, bar er klargjort for tillegging som en kopi av foo, og foo blir klargjort for fjerning. svn move lager ikke mellomliggende kataloger.

Studer forandringene dine

Når du er ferdig med å gjøre forandringer, må du legge dem inn i depotet, men før du gjør det, er det vanligvis en god idé å ta en kikk på nøyaktig hva du har forandret. Ved å studere forandringene dine før du legger dem inn, kan du lage en mer nøyaktig loggmelding. Du kan også oppdage om du har forandret ei fil ved en ulykke, og dette gir deg en sjanse til å omgjøre disse forandringene før du legger dem inn. I tillegg er dette en god mulighet til å se over og skrote forandringer før du publiserer dem. Du kan se nøyaktig hvilke forandringer du har gjort ved å bruke svn status, svn diff og svn revert. Du vil vanligvis bruke de første to kommandoene til å finne ut hvilke filer som har forandret seg i arbeidskopien din, og deretter kanskje bruke den tredje for å omgjøre noen (eller alle) disse forandringene.

Subversion er blitt optimalisert for å hjelpe deg med denne oppgaven, og er i stand til å gjøre mange ting uten å kommunisere med depotet. Nærmere forklart, arbeidskopien inneholder en hemmelig urørt kopi av hver versjonskontrollert fil, og disse kopiene ligger i .svn-området. På grunn av dette kan Subversion raskt vise deg hvordan arbeidsfilene dine har forandret seg, og til og med tillate deg å omgjøre forandringene dine uten å kontakte depotet.

svn status

Du vil muligens bruke kommandoen svn status mer enn noen annen Subversionkommando.

Hvis du kjører svn status på toppen av arbeidskopien uten å angi argumenter, vil programmet detektere alle fil- og katalogforandringer som du har gjort. Nedenfor er eksempler på de forskjellige statuskodene som svn status kan returnere. (Legg merke til at teksten etter # i det følgende eksempelet ikke skrives ut av svn status-kommandoen.

  L     en_katalog          # svn etterlot en lås i .svn-området for 
                            # en_katalog
M       bar.c               # innholdet i bar.c har lokale forandringer
 M      baz.c               # baz.c har egenskapsforandringer, men ingen 
                            # forandring i innholdet
X       3rd_party           # katalogen er del av en 
                            # «externals»-definering
?       foo.o               # svn kjenner ikke til foo.o
!       some_dir            # svn kontrollerer denne, men den mangler 
                            # eller er ikke komplett
~       qux                 # versjonert som fil/katalog/lenke, men 
                            # elementtypen er forandret
I       .screenrc           # svn kontrollerer ikke denne, og er satt 
                            # opp til å ignorere den
A  +    moved_dir           # lagt til med historien til der den kom fra
M  +    moved_dir/README    # lagt til med historie og inneholder lokale 
                            # forandringer
D       stuff/fish.c        # fila er klargjort for sletting
A       stuff/loot/bloo.h   # fila er klargjort for tillegging
C       stuff/loot/lump.c   # fila har tekstmessige konflikter fra en 
                            # oppdatering
 C      stuff/loot/glub.c   # fila har konflikt i egenskapene fra en 
                            # oppdatering
R       xyz.c               # fila er klargjort for erstatning
    S   stuff/squawk        # fila eller katalogen er byttet til en 
                            # annen plassering i depotet ved hjelp av 
                            # svn switch-kommandoen
     K  dog.jpg             # fila er låst lokalt; låsnøkkel finnes
     O  cat.jpg             # fila er låst i depotet av en annen bruker
     B  bird.jpg            # fila er låst lokalt, men låsen er blitt 
                            # brutt
     T  fish.jpg            # fila er låst lokalt, men låsen er blitt 
                            # stjålet

I dette utdataformatet skriver svn status fem kolonner med tegn, fulgt av flere blanke tegn, etterfulgt av et fil- eller katalognavn. Den første kolonnen forteller statusen til ei fil eller en katalog og/eller dens innhold. Kodene som kan skrives her er:

A element

Fila, katalogen eller den symbolske lenken element er blitt klargjort for tillegging til depotet.

C element

Fila element er i en tilstand av konflikt. Det betyr at forandringer mottatt fra serveren under en oppdatering overlapper med lokale forandringer som du har i arbeidskopien din. Du må løse denne konflikten før du legger inn dine forandringer i depotet.

D element

Fila, katalogen eller den symbolske lenken element er blitt klargjort for sletting fra depotet.

M element

Innholdet av fila element er blitt forandret.

R element

Fila, katalogen, eller den symbolske lenken element er blitt klargjort for å erstatte element i depotet. Dette betyr at objektet først blir slettet, deretter blir et annet element lagt til, alt innenfor en enkelt revisjon.

X element

Katalogen element er uversjonert, men er relatert til en ekstern definisjon i Subversion. For å finne ut mer om externals-defineringer, se “Externals Definitions”.

? element

Fila, katalogen eller den symbolske lenken element er ikke under versjonskontroll. Du kan bli kvitt spørsmålstegnene ved å enten angi --quiet (-q)-valget til svn status, eller sette svn:ignore-egenskapen på foreldrekatalogen. For mer informasjon om ignorerte filer, se “Ignoring Unversioned Items”.

! element

Fila, katalogen eller den symbolske lenken element er under versjonskontroll men mangler eller er ukomplett på en eller annen måte. Elementet kan mangle hvis det er fjernet ved bruk av en kommando utenfor Subversions kontroll. I tilfellet med en katalog, kan den være ukomplett hvis du har avbrutt en uthenting eller oppdatering. En rask svn update vil hente fila eller katalogen på nytt, eller en svn revert vil legge tilbake en manglende fil.

~ element

Fila, katalogen eller den symbolske lenken element er lagret i depotet som en type objekt, men det som faktisk er i arbeidskopien er en annen type. For eksempel kan Subversion ha ei fil i katalogen, men du fjernet fila og opprettet en katalog på samme plassen uten å bruke kommandoen svn delete eller svn add.

I element

Fila, katalogen eller den symbolske lenken element er ikke under versjonskontroll, og Subversion er satt opp til å ignorere den under operasjonene svn add, svn import og svn status. For mer informasjon om ignorerte filer, se “Ignoring Unversioned Items”. Merk at dette symbolet bare dukker opp hvis du spesifiserer valget --no-ignore til svn status – ellers ville fila bli ignorert og ikke listet i det hele tatt!

Den andre kolonnen forteller statusen på egenskapene til ei fil eller katalog (se “Egenskaper” for mer informasjon om egenskaper). Hvis en M viser seg i den andre kolonnen, er egenskapene blitt modifisert. Hvis en C kommer til syne i den kolonnen, er egenskapene for fila i en konflikt som må løses før forandringene kan legges inn i depotet. Ellers vil et blankt tegn bli skrevet.

Den tredje kolonnen vil bare vise blanktegn eller en L som betyr at Subversion har låst katalogens .svn-arbeidsområde. Du vil se en L hvis du kjører svn status i en katalog hvor en svn commit er i gang – kanskje mens du redigerer loggmeldingen. Hvis Subversion ikke kjører, ble Subversion sannsynligvis avbrutt og låsene må frigjøres ved å kjøre svn cleanup (mer om det senere i dette kapitlet).

Den fjerde kolonnen vil bare vise blanktegn eller en + som betyr at fila eller katalogen er klargjort for tillegging eller er modifisert med en historie lagt til i tillegg. Dette skjer vanligvis når du bruker svn move eller svn copy på ei fil eller katalog. Hvis du ser A  +, betyr det at elementet er klargjort for tillegging med historie. Det kan være ei fil eller roten på en kopiert katalog. + betyr at elementet er en del av et katalogtre klargjort for tillegging med historie, det vil si at en forelder ble kopiert, og den følger bare med på lasset. M  + betyr at elementet er en del av et katalogtre klargjort for tillegging med historie, og det har lokale forandringer. Når du legger det inn, vil først forelderen bli lagt til med historie (kopiert), noe som betyr at denne fila automatisk vil eksistere i kopien. Deretter blir de lokale forandringene lagt inn i kopien.

Den femte kolonnen vil bare vise blanktegn eller en S. Dette viser at fila eller katalogen er blitt byttet om fra stien som resten av arbeidskopien bruker (ved bruk av svn switch) til en gren.

Den sjette kolonnen viser informasjon om låser, som er nærmere forklart i “Locking”. (Dette er ikke de samme låsene som de som vises som en L i den tredje kolonnen; se Three meanings of lock.)

Hvis du gir en spesifikk sti til svn status, gir den deg informasjon om dette elementet alene:

$ svn status stuff/fish.c
D      stuff/fish.c

svn status har også valget --verbose (-v), som vil vise deg statusen til hvert eneste element i arbeidskopien, selv om det ikke er blitt forandret:

$ svn status --verbose
M               44        23    sally     README
                44        30    sally     INSTALL
M               44        20    harry     bar.c
                44        18    ira       stuff
                44        35    harry     stuff/trout.c
D               44        19    ira       stuff/fish.c
                44        21    sally     stuff/things
A                0         ?     ?        stuff/things/bloo.h
                44        36    harry     stuff/things/gloo.c

Dette er den lange formen av utdata fra svn status. Den første kolonnen forblir den samme, men den andre kolonnen viser arbeidsrevisjonen til elementet. Den tredje og fjerde kolonnen viser revisjonen elementet sist ble forandret i, og hvem som gjorde det.

Ingen av kjøringene av svn status ovenfor kontakter depotet, de virker bare lokalt ved å sammenligne metadataene i .svn-katalogen med arbeidskopien. Til slutt er det --show-updates (-u)-valget, som kontakter depotet og legger til informasjon om ting som er utdatert:

$ svn status --show-updates --verbose
M      *        44        23    sally     README
M               44        20    harry     bar.c
       *        44        35    harry     stuff/trout.c
D               44        19    ira       stuff/fish.c
A                0         ?     ?        stuff/things/bloo.h
Status mot revisjon:   46

Legg merke til de to asteriskene: Hvis du skulle kjøre svn update på dette tidspunktet, ville du motta forandringer til README og trout.c. Dette gir deg nyttig informasjon – du må oppdatere og få serverforandringene for README før du legger inn filene, ellers vil depotet avslå innleggingen fordi den ikke er oppdatert. (Mer om dette temaet senere.)

svn diff

En annen måte å undersøke forandringene dine er med kommandoen svn diff. Du kan finne ut nøyaktig hvordan du har forandret på ting ved å kjøre svn diff uten argumenter, noe som lister ut filforandringer i unified diff-format:[4]

$ svn diff
Index: bar.c
===================================================================
--- bar.c	(revisjon 3)
+++ bar.c	(arbeidskopi)
@@ -1,7 +1,12 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <stdio.h>

 int main(void) {
-  printf("Sekstifire skiver med amerikansk ost...\n");
+  printf("Sekstifem skiver med amerikansk ost...\n");
 return 0;
 }

Index: README
===================================================================
--- README	(revisjon 3)
+++ README	(arbeidskopi)
@@ -193,3 +193,4 @@ 
+Husk: Plukk opp skittentøyet.

Index: stuff/fish.c
===================================================================
--- stuff/fish.c	(revisjon 1)
+++ stuff/fish.c	(arbeidskopi)
-Velkommen til fila som er kjent som «fish».
-Det vil bli litt fiskeinfo her etterhvert.

Index: stuff/things/bloo.h
===================================================================
--- stuff/things/bloo.h	(revisjon 8)
+++ stuff/things/bloo.h	(arbeidskopi)
+Her er en ny fil for å fortelle
+ting om bloo.

Kommandoen svn diff produserer disse utdataene ved å sammenligne dine arbeidsfiler mot de lagrede urørte kopiene i .svn-området. Filer klargjort for tillegging blir vist som om all teksten er lagt til, og filer klargjort for sletting vises som om all teksten er slettet.

Utdataene blir vist i unified diff-format. Det vil si at slettede linjer vises med en - i begynnelsen av linjen, og linjer lagt til har en + i begynnelsen. svn diff skriver også filnavn og informasjon om filposisjon nyttig for programmet patch, så du kan generere patcher ved å omdirigere utdataene fra diff til ei fil:

$ svn diff > patchfil

Du kan for eksempel sende denne patchfila til en annen utvikler så han kan kontrollere eller teste den før den legges inn i depotet.

svn revert

Tenk deg nå at du ser resultatet av diffen ovenfor, og oppdager at forandringene dine til README er en feil; kanskje du la denne teksten inn i feil fil ved en ulykke.

Dette er en perfekt mulighet til å bruke kommandoen svn revert.

$ svn revert README
Tilbakestilte «README»

Subversion reverserte fila til sin før-modifiserte tilstand ved å overskrive den med den lagrede urørte kopien fra .svn-området. Men legg også merke til at svn revert kan omgjøre alle klargjorte operasjoner – for eksempel kan du bestemme deg for at du likevel ikke vil legge til en ny fil:

$ svn status foo
?      foo

$ svn add foo
A         foo

$ svn revert foo
Tilbakestilte «foo»

$ svn status foo
?      foo
[Notat]Notat

svn revert ELEMENT har nøyaktig den samme effekten som om du sletter ELEMENT fra arbeidskopien din og deretter kjører svn update -r BASE ELEMENT. Imidlertid, hvis du reverserer ei fil har svn revert en forskjell som er verdt å legge merke til – den trenger ikke å kommunisere med depotet for å legge tilbake fila di.

Eller kanskje du fjernet ei fil fra versjonskontroll ved en ulykke:

$ svn status README 
       README

$ svn delete README 
D         README

$ svn revert README
Tilbakestilte «README»

$ svn status README
       README

Løse konflikter (Flette inn andres forandringer)

Vi har allerede sett hvordan svn status -u kan forutsi konflikter. Tenk deg at du kjører svn update og noen interessante ting skjer:

$ svn update
U  INSTALL
G  README
C  bar.c
Oppdatert til revisjon 46.

Kodene U og G gir ingen grunn til å foreta seg noe; disse filene absorberte forandringene fra depotet på en grei måte. Filene merket med U inneholdt ingen lokale forandringer, men ble oppdatert (Updated) med forandringer fra depotet. G-en står for merGed (flettet), noe som betyr at fila hadde lokale forandringer til å begynne med, men forandringene som kom fra depotet overlappet ikke med de lokale forandringene.

Men C-en står for konflikt. Dette betyr at forandringene fra serveren overlappet med dine egne, og nå må du velge mellom dem manuelt.

Når en konflikt oppstår, skjer vanligvis tre ting som hjelper deg med å legge merke til og løse denne konflikten:

  • Subversion skriver en C under oppdateringen, og husker at fila er i en konflikttilstand.

  • Hvis Subversion anser fila å være av en flettbar type, plasserer den konfliktmerker – spesielle strenger med tekst som skiller sidene av konflikten – inn i fila for å vise de overlappende områdene visuelt. (Subversion bruker svn:mime-type-egenskapen for å bestemme om ei fil er mulig å flette ved hjelp av kontekst- og linjebasert fletting. Se “File Content Type” for å lære mer.)

  • For hver fil som har en konflikt plasserer Subversion opp til tre ekstra filer i arbeidskopien din:

    filnavn.mine

    Dette er din fil som den var da den eksisterte i arbeidskopien din før du oppdaterte arbeidskopien – det vil si uten konfliktmerker. Denne fila har dine seneste forandringer og ingenting annet. (Hvis Subversion avgjør at fila ikke er flettbar, blir ikke .mine-fila opprettet, siden den ville vært identisk med arbeidsfila.)

    filnavn.rGAMMELREV

    Dette er den fila som var BASE-revisjonen før du oppdaterte arbeidskopien. Det vil si den fila som du hentet ut før du gjorde dine seneste redigeringer.

    filnavn.rNYREV

    Dette er den fila som Subversionklienten nettopp mottok fra serveren når du oppdaterte arbeidskopien. Denne fila samsvarer med HEAD-revisjonen av depotet.

    Her er GAMMELREV revisjonsnummeret til fila i ditt .svn-område og NYREV er revisjonsnummeret til HEAD i depotet.

For eksempel, Sally gjør forandringer til fila sandwich.txt i depotet. Harry har akkurat forandret fila i arbeidskopien sin og har lagt den inn. Sally oppdaterer sin arbeidskopi før hun legger den inn og får en konflikt:

$ svn update
C  sandwich.txt
Oppdatert til revisjon 2.
$ ls -1
sandwich.txt
sandwich.txt.mine
sandwich.txt.r1
sandwich.txt.r2

På dette tidspunktet vil Subversion ikke tillate deg å legge inn fila sandwich.txt før de tre midlertidige filene er fjernet.

$ svn commit --message "Legg til noen flere ting"
svn: Innsending feilet (detaljer følger):
svn: Avbryter innsending: «/home/sally/svn-work/sandwich.txt» er fortsatt i konflikt

Hvis du får en konflikt, må du gjøre en av tre ting:

  • Flette teksten med konflikt for hånd (ved å studere og redigere konfliktmerkene i fila).

  • Kopiere en av de midlertidige filene over arbeidsfila di.

  • Kjøre svn revert <filnavn> for å skrote alle dine lokale forandringer.

Når du har løst konflikten, må du la Subversion få vite dette ved å kjøre svn resolved. Dette fjerner de tre midlertidige filene og Subversion anser ikke lenger fila for å være i konflikt.[5]

$ svn resolved sandwich.txt
Konflikten i «sandwich.txt» er løst

Løse konflikter for hånd

Å flette konflikter for hånd kan være ganske skremmende den første gangen du prøver det, men med litt øvelse kan det bli like lett som å ramle av en sykkel.

Her er et eksempel. På grunn av dårlig kommunikasjon redigerer både du og Sally, din kollega, fila sandwich.txt samtidig. Sally legger inn sine forandringer, og når du oppdaterer arbeidskopien din får du en konflikt og vi må redigere sandwich.txt for å løse konfliktene. Først, la oss ta en kikk på fila:

$ cat sandwich.txt
Top piece of bread
Mayonnaise
Lettuce
Tomato
Provolone
<<<<<<< .mine
Salami
Mortadella
Prosciutto
=======
Sauerkraut
Grilled Chicken
>>>>>>> .r2
Creole Mustard
Bottom piece of bread

Strengene med mindre enn-tegn, likhetstegn og større enn-tegn er konfliktmerker, og er ikke del av de aktuelle dataene i konflikt. Du vil vanligvis forsikre deg om at de er fjernet fra fila før din neste innlegging. Teksten mellom de to første settene med merker er satt sammen av de forandringene du gjorde i konfliktområdet:

<<<<<<< .mine
Salami
Mortadella
Prosciutto
=======

Teksten mellom det andre og tredje settet av konfliktmerker er teksten fra Sallys innlegging:

=======
Sauerkraut
Grilled Chicken
>>>>>>> .r2

Vanligvis vil du ikke ønske å bare slette konfliktmerkene og Sallys forandringer – hun kommer til å bli voldsomt forbauset når smørbrødet ankommer og det ikke er det hun ville ha. Så det er nå du tar opp telefonen eller går til andre enden av kontoret og forklarer til Sally at du får ikke sauerkraut fra en italiensk ¤deli.[6] Når dere er blitt enige om forandringene du vil legge inn, rediger fila din og fjern konfliktmerkene.

Top piece of bread
Mayonnaise
Lettuce
Tomato
Provolone
Salami
Mortadella
Prosciutto
Creole Mustard
Bottom piece of bread

Nå kan du kjøre svn resolved, og du er klar til å legge inn forandringene dine:

$ svn resolved sandwich.txt
$ svn commit -m "Gå i gang med å bruke mitt smørbrød, bort med Sallys redigeringer."

Legg merke til at svn resolved, ulikt mesteparten av de andre kommandoene vi holder på med i dette kapittelet, trenger et argument. I alle tilfeller må du være forsiktig og bare kjøre svn resolved når du er sikker på at du har ordnet konflikten i fila – når de midlertidige filene er fjernet, vil Subversion la deg legge inn fila selv om den fortsatt inneholder konfliktmerker.

Hvis du blir forvirret mens du redigerer fila med konflikt, kan du alltids konsultere de tre filene som Subversion lagde for deg i arbeidskopien din – inkludert fila di sånn som den var før du oppdaterte. Du kan til og med bruke et tredjeparts interaktivt fletteverktøy for å studere de tre filene.

Kopiere ei fil over arbeidsfila din

Hvis du får en konflikt og bestemmer deg for å forkaste endringene dine, trenger du bare å kopiere ei av de midlertidige filene laget av Subversion over fila i arbeidskopien din:

$ svn update
C  sandwich.txt
Oppdatert til revisjon 2.
$ ls sandwich.*
sandwich.txt  sandwich.txt.mine  sandwich.txt.r2  sandwich.txt.r1
$ cp sandwich.txt.r2 sandwich.txt
$ svn resolved sandwich.txt

Bruke svn revert

Hvis du får en konflikt og under undersøkelsen bestemmer deg for å forkaste endringene dine og starte på nytt, bare reverser forandringene dine:

$ svn revert sandwich.txt
Tilbakestilte «sandwich.txt»
$ ls sandwich.*
sandwich.txt

Legg merke til at når du reverserer ei fil i konflikt, trenger du ikke å kjøre svn resolved.

Legg inn forandringene dine

Endelig! Du er ferdig med forandringene dine, du har flettet inn alle forandringene fra serveren, og du er klar til å legge inn forandringene til depotet.

Kommandoen svn commit sender alle dine forandringer til depotet. Når du legger inn en forandring, må du skrive en loggmelding som beskriver forandringen. Loggmeldingen vil bli lagt ved den nye revisjonen som du lager. Hvis loggmeldingen er kort, vil du kanskje legge den inn fra kommandonlinjen ved å bruke --message (eller -m)-valget:

$ svn commit --message "Ordnet antall osteskiver."
Sender        sandwich.txt
Sender fildata .
La inn revisjon 3.

Hvis du derimot har laget loggmeldingen mens du arbeidet, vil du kanskje be Subversion om å hente meldingen fra ei fil ved å angi filnavnet med --file-valget:

$ svn commit --file logmsg 
Sender        sandwich.txt
Sender fildata .
La inn revisjon 4.

Hvis du lar være å angi --message- eller --file-valget, vil Subversion starte favoritteditoren din automatisk (se seksjonen om editor-cmd i “Konfigurasjon”) så du kan skrive en loggmelding.

[Tips]Tips

Hvis du skriver en loggmelding i tekstbehandleren og bestemmer deg for å avbryte innleggingen, kan du bare avbryte uten å lagre endringene. Hvis du allerede har lagret innleggingsmeldingen, kan du slette teksten og lagre på nytt.

$ svn commit
Venter på Emacs...Ferdig

Loggmeldingen er uforandret eller ikke spesifisert
Avbryt (a), fortsett (c), rediger (e)
a
$

Depotet vet ikke og bryr seg ikke om forandringene dine gir noen mening som helhet; det sjekker bare for å være sikker på at ingen andre har forandret noen av de samme filene som du gjorde når du ikke fulgte med. Hvis noen har gjort det, vil hele innleggingen feile med en melding om at en eller flere av filene dine er utdaterte:

$ svn commit --message "La til en ny regel"
Sender        rules.txt
svn: Innsending feilet (detaljer følger):
svn: Utdatert: «rules.txt» i transaksjon «g»

På dette punktet må du kjøre svn update, ta deg av eventuelle flettinger eller konflikter som oppstår og prøve en ny innlegging.

Dette dekker den grunnleggende arbeidssyklusen for å bruke Subversion. Det er mange andre funksjoner i Subversion som du kan bruke til å vedlikeholde depotet og arbeidskopien, men du kan klare deg ganske greit ved å bare bruke de kommandoene som vi har diskutert så langt i kapittelet.

Studere historien

Som vi nevnte tidligere, er depotet som en tidsmaskin. Det lagrer alle forandringene som er lagt inn, og tillater deg å utforske denne historien ved å studere tidligere versjoner av filer og kataloger så vel som metadataene som tilhører dem. Med en enkel Subversionkommando kan du hente ut depotet (eller hente tilbake en eksisterende arbeidskopi) nøyaktig som den var på en vilkårlig dato eller revisjon i fortiden. Men noen ganger vil du bare kikke inn i fortiden istedenfor å reise til fortiden.

Det er flere kommandoer som kan gi deg historiske data fra depotet:

svn log

Viser deg bred informasjon: Loggmeldinger med dato- og forfatterinformasjon for revisjonene og hvilke stier som forandret seg i hver revisjon.

svn diff

Viser deg de spesifikke detaljene om hvordan ei fil forandret seg over tid.

svn cat

Denne blir brukt til å hente en vilkårlig fil som den var da den eksisterte i en spesiell revisjon og vise den på skjermen.

svn list

List filene i katalogen for en vilkårlig revisjon.

svn log

For å finne informasjon om historien til ei fil eller katalog, bruk kommandoen svn log. svn log vil gi deg en oversikt over hvem som gjorde forandringer i ei fil eller en katalog, i hvilken revisjon den forandret seg, tid og dato for denne revisjonen, og, hvis den ble skrevet, loggmeldingen som hører til innleggingen.

$ svn log
------------------------------------------------------------------------
r3 | sally | man, 15 jul 2002 18:03:46 -0500 | 1 line

La til include-linjer og ordnet antall osteskiver.
------------------------------------------------------------------------
r2 | harry | man, 15 jul 2002 17:47:57 -0500 | 1 line

La til main()-metoder.
------------------------------------------------------------------------
r1 | sally | man, 15 jul 2002 17:40:08 -0500 | 1 line

Innledende import
------------------------------------------------------------------------

Legg merke til at loggmeldinger listes ut i omvendt kronologisk rekkefølge som standard. Hvis du ønsker å se et annet område av revisjoner i en spesiell rekkefølge, eller bare en enkelt revisjon, bruk --revision (-r)-valget:

$ svn log --revision 5:19    # viser loggene 5 til 19 i kronologisk 
                             # rekkefølge

$ svn log -r 19:5            # viser loggene 5 til 19 i omvendt 
                             # rekkefølge

$ svn log -r 8               # viser loggen for revisjon 8

Du kan også undersøke logghistorien for ei enkelt fil eller katalog. For eksempel:

$ svn log foo.c
…
$ svn log http://foo.com/svn/trunk/code/foo.c
…

Dette vil vise loggmeldinger bare for de revisjonene der arbeidsfila (eller URLen) forandret seg.

Hvis du vil ha enda mer informasjon om ei fil eller en katalog, tar svn log også et --verbose (-v)-valg. Fordi Subversion tillater deg å flytte og kopiere filer og kataloger, er det viktig å ha muligheten til å følge stiforandringer i filsystemet, så i verbose-modus vil svn log inkludere en liste over forandrede stier for en revision i listeformatet:

$ svn log -r 8 -v
------------------------------------------------------------------------
r8 | sally | 2002-07-14 08:15:29 -0500 | 1 line
Changed paths:
M /trunk/code/foo.c
M /trunk/code/bar.h
A /trunk/code/doc/README

Frozzled the sub-space winch.

------------------------------------------------------------------------

svn log tar også et --quiet-parameter (-q) som lar være å skrive ut kroppen på loggmeldinga. Når det kombineres med --verbose lister det kun navnet på filene som har forandret seg.

svn diff

Vi har allerede sett svn diff før – den viser filforskjeller i unified diff-format; den ble brukt til å vise de lokale forandringene i en arbeidskopi før de ble lagt inn i depotet.

Faktisk skal det vise seg at det er tre distinkte bruksmåter for svn diff:

  • Undersøke lokale forandringer

  • Sammenligne arbeidskopien din med depotet

  • Sammenligne depot med depot

Undersøke lokale forandringer

Som vi har sett, vil det å utføre svn diff uten noen valg sammenligne arbeidsfilene dine med de lagrede urørte kopiene i .svn-området:

$ svn diff
Index: rules.txt
===================================================================
--- rules.txt	(revisjon 3)
+++ rules.txt	(arbeidskopi)
@@ -1,4 +1,5 @@
 Vær snill med andre
 Frihet = ansvar
 Alt med måte
-Tygg med munnen åpen
+Tygg med munnen lukket
+Hør etter når andre prater
$

Sammenligne arbeidskopi med depot

Hvis et enkelt nummer blir gitt til --revision (-r)-valget, vil arbeidskopien bli sammenlignet med den spesifiserte revisjonen i depotet.

$ svn diff --revision 3 rules.txt 
Index: rules.txt
===================================================================
--- rules.txt	(revisjon 3)
+++ rules.txt	(arbeidskopi)
@@ -1,4 +1,5 @@
 Vær snill med andre
 Frihet = ansvar
 Alt med måte
-Tygg med munnen åpen
+Tygg med munnen lukket
+Hør etter når andre prater
$

Sammenligne depot med depot

Hvis to revisjonsnumre, separert med kolon, blir gitt til --revision (-r), blir disse to revisjonene sammenlignet direkte.

$ svn diff --revision 2:3 rules.txt 
Index: rules.txt
===================================================================
--- rules.txt	(revisjon 2)
+++ rules.txt	(revisjon 3)
@@ -1,4 +1,4 @@
 Vær snill med andre
-Frihet = sjokoladeis
+Frihet = ansvar
 Alt med måte
 Tygg med munnen åpen
$

Ikke bare kan du bruke svn diff til å sammenligne filer i arbeidskopien din mot depotet, men hvis du oppgir en URL kan du undersøke forskjellene mellom elementer i depotet uten å en gang ha en arbeidskopi. Dette er spesielt nyttig hvis du ønsker å inspisere forandringer i ei fil når du ikke har en arbeidskopi på den lokale maskinen din:

$ svn diff --revision 4:5 http://svn.red-bean.com/repos/example/trunk/text/rules.txt
…
$

svn cat

Hvis du vil undersøke en tidligere versjon av ei fil og ikke nødvendigvis forskjellene mellom to filer, kan du bruke svn cat:

$ svn cat --revision 2 rules.txt 
Vær snill med andre
Frihet = sjokoladeis
Alt med måte
Tygg med munnen åpen
$

Du kan også omdirigere utdataene direkte til ei fil:

$ svn cat --revision 2 rules.txt > rules.txt.v2
$

Du lurer sikkert på hvorfor vi rett og slett ikke bare bruker svn update --revision for å oppdatere fila til den eldre revisjonen. Det er et par grunner til at vi kanskje foretrekker å bruke svn cat.

For det første kan det hende at du ønsker å se på forskjellene mellom to revisjoner av ei fil ved å bruke et eksternt diffprogram (kanskje et grafisk et, eller kanskje fila di er i et format som gjør at unified diff-formatet ikke strekker til). I dette tilfellet må du hente en kopi av den gamle revisjonen, omdirigere den til ei fil, og angi både den og fila i arbeidskopien til det eksterne diffprogrammet.

For det andre er det noen ganger rett og slett lettere å se på en eldre versjon av en fil i sin helhet i stedet for bare å se på forskjellene mellom den og en annen revisjon.

svn list

svn list-kommandoen viser deg hvilke filer som er i en depotkatalog uten å hente filene til din lokale maskin:

$ svn list http://svn.collab.net/repos/svn
README
branches/
clients/
tags/
trunk/

Hvis du vil ha en mer detaljert liste, angi --verbose (-v)-flagget for å få en liste som dette:

$ svn list --verbose http://svn.collab.net/repos/svn
   2755 harry          1331 Jul 28 02:07 README
   2773 sally               Jul 29 15:07 branches/
   2769 sally               Jul 29 12:07 clients/
   2698 harry               Jul 24 18:07 tags/
   2785 sally               Jul 29 19:07 trunk/

Kolonnene viser deg revisjonen fila eller katalogen sist ble modifisert, brukeren som gjorde det, størrelsen hvis det er ei fil, datoen den sist ble forandret, og elementets navn.

Et siste ord om historie

I tillegg til alle de ovennevnte kommandoene, kan du bruke svn update og svn checkout med --revision-valget for å ta en hel arbeidskopi tilbake i tid[7]:

$ svn checkout --revision 1729 # Henter ut en ny arbeidskopi fra r1729
…
$ svn update --revision 1729 # Oppdaterer en eksisterende arbeidskopi 
                             # til r1729
…

Andre nyttige kommandoer

Selv om de ikke blir så ofte brukt som kommandoene tidligere nevnt i dette kapitlet, vil du innimellom trenge disse kommandoene.

svn cleanup

Når Subversion modifiserer arbeidskopien din (eller noe som helst i .svn), prøver programmet å gjøre det på en så trygg måte som mulig. Før arbeidskopien blir forandret, skriver Subversion det som skal utføres til en loggfil. Deretter kjører programmet kommandoene i loggfila for å utføre forandringen det blir bedt om mens det setter opp en lås på den relevante delen av arbeidskopien mens det arbeider – dette er for å hindre andre Subversionklienter fra å aksessere arbeidskopien midt under forandringer. Til slutt fjerner Subversion loggfila. Arkitekturmessig er dette likt et journalfilsystem. Hvis en Subversionoperasjon blir avbrutt (hvis prosessen blir drept eller maskinen krasjer, for eksempel), blir loggfila liggende på disken. Ved å utføre kommandoene i loggfila en gang til kan Subversion fullføre den tidligere påbegynte operasjonen, og arbeidskopien din kan sette seg tilbake til en fullverdig tilstand.

Og dette er nøyaktig hva svn cleanup gjør: Den leter gjennom arbeidskopien og kjører alle etterlatte logger mens den fjerner låser i arbeidskopien under prosessen. Hvis Subversion noen ganger forteller deg at en del av arbeidskopien er låst (locked), er dette kommandoen du bør kjøre. I tillegg vil svn status vise en L ved siden av låste elementer:

$ svn status
  L    somedir
M      somedir/foo.c 

$ svn cleanup
$ svn status
M      somedir/foo.c

Du må ikke forveksle disse arbeidskopilåsene med de vanlige låsene som Subversionbrukere oppretter når de bruker lås-modifiser-lås opp-versjonskontrollmodellen; se Three meanings of lock for forklaring på dette.

svn import

svn import-kommandoen er en rask måte å kopiere et uversjonert filtre inn i et depot og lage mellomliggende kataloger der det er nødvendig.

$ svnadmin create /usr/local/svn/nyttdepot
$ svn import mitt_tre file:///usr/local/svn/nyttdepot/et/prosjekt \
             -m "Innledende import"
Legger til         mitt_tre/foo.c
Legger til         mitt_tre/bar.c
Legger til         mitt_tre/subdir
Legger til         mitt_tre/subdir/quux.h

La inn revisjon 1.

Det forrige eksempelet kopierte innholdet av katalogen mitt_tre under katalogen etellerannet/prosjekt i depotet:

$ svn list file:///usr/local/svn/nyttdepot/etellerannet/prosjekt
bar.c
foo.c
subdir/

Legg merke til at etter importen er fullført, blir det originale treet ikke konvertert til en arbeidskopi. For å starte arbeidet, trenger du fortsatt å kjøre svn checkout for å få en fersk arbeidskopi av treet.

Oppsummering

Nå har vi dekket mesteparten av klientkommandoene i Subversion. Unntak som vi kan legge merke til er de som har med forgreninger og fletting å gjøre (se Kapittel 4, Forgrening og fletting) og egenskaper (se “Egenskaper”). Det kan være du ønsker å bruke litt tid på å skumme gjennom Kapittel 9, Subversion Complete Reference for å få en idé om de mange forskjellige kommandoene Subversion har – og hvordan du kan bruke dem til å gjøre arbeidet ditt enklere.




[3] Selvfølgelig, ingenting blir noensinne totalt slettet fra depotet – bare fra HEAD i depotet. Du kan få alt tilbake ved å hente ut (eller oppdatere arbeidskopien til) en tidligere revisjon i forhold til den som ble slettet.

[4] Subversion bruker sine egne interne diffrutiner, som produserer diff-format som standard. Hvis du vil ha utdataene fra diff i et annet format, spesifiser et eksternt diffprogram ved å bruke --diff-cmd og legg til alle flagg du vil trenge ved å bruke --extensions-bryteren. For eksempel, for å se lokale forskjeller i fila foo.c i context format mens forandringer i blanktegn blir ignorert, kan du kjøre svn diff --diff-cmd /usr/bin/diff --extensions '-bc' foo.c.

[5] Du kan alltids fjerne de midlertidige filene selv, men gidder du egentlig det når Subversion kan gjøre det for deg? Det var det vi trodde.

[6] Og hvis du spør dem om det, kan det hende de bærer deg ut av byen på en planke.

[7] Ser du? Vi sa jo at Subversion er en tidsmaskin.

Kapittel 3. Avanserte emner

Hvis du har lest denne boka kapittel for kapittel, fra start til slutt, skal du nå ha samlet opp nok kunnskap til å kunne bruke Subversionklienten til å utføre de vanligste operasjonene innen versjonskontroll. Du forstår hvordan du henter ut en arbeidskopi fra et Subversiondepot. Du er komfortabel med å legge inn og hente ut forandringer ved å bruke kommandoene svn commit og svn update. Du har til og med kanskje utviklet en refleks som gjør at du kjører svn status nærmest ubevisst. Hva oppgaven enn er, er du klar til å bruke Subversion i et typisk arbeidsmiljø.

Men funksjonaliteten til Subversion stopper ikke ved vanlige versjonskontrolloperasjoner. Den har annen funksjonalitet som går forbi det å bare sende fil- og katalogforandringer til og fra et sentralt depot.

Dette kapittelet setter fokus på litt av funksjonaliteten til Subversion som, selv om den er viktig, ikke er del av den typiske brukerens daglige rutine. Det antas at du er kjent med de grunnleggende mulighetene Subversion har for versjonering av filer og kataloger. Hvis du ikke er det, vil du kanskje lese Kapittel 1, Grunnleggende konsepter og Kapittel 2, Grunnleggende bruk. Når du mestrer disse grunnleggende tingene og har fordøyd dette kapittelet, vil du være en Subversionmuskelbruker!

Revision Specifiers

As you saw in “Tidsreiser med Subversion”, revision numbers in Subversion are pretty straightforward—integers that keep getting larger as you commit more changes to your versioned data. Still, it doesn't take long before you can no longer remember exactly what happened in each and every revision. Fortunately, the typical Subversion workflow doesn't often demand that you supply arbitrary revisions to the Subversion operations you perform. For operations that do require a revision specifier, you generally supply a revision number that you saw in a commit email, in the output of some other Subversion operation, or in some other context that would yield meaning to that particular number.

But occasionally, you need to pinpoint a moment in time for which you don't already have a revision number memorized or handy. So besides the integer revision numbers, svn allows as input some additional forms of revision specifiers—revision keywords, and revision dates.

[Notat]Notat

The various forms of Subversion revision specifiers can be mixed and matched when used to specify revision ranges. For example, you can use -r REV1:REV2 where REV1 is a revision keyword and REV2 is a revision number, or where REV1 is a date and REV2 is a revision keyword, and so on. The individual revision specifiers are independently evaluated, so you can put whatever you want on the opposite sides of that colon.

Nøkkelord for revisjoner

Subversionklienten forstår noen revisjonsnøkkelord. Disse nøkkelordene kan bli brukt istedenfor heltallsargumenter til --revision-valget, og blir oversatt til spesifikke revisjonsnumre av Subversion:

HEAD

Den seneste (eller yngste) revisjonen i depotet.

BASE

Revisjonsnummeret til et element i en arbeidskopi. Hvis elementet inneholder lokale forandringer, refererer BASE-versjonen til det som elementet ser ut som når disse forandringene ikke er til stede.

COMMITTED

Den seneste revisjonen før eller lik BASE, der et element ble forandret.

PREV

Revisjonen like før den siste revisjonen der et element ble forandret. Teknisk sett koker dette ned til COMMITTED-1.

As can be derived from their descriptions, the PREV, BASE, and COMMITTED revision keywords are used only when referring to a working copy path—they don't apply to repository URLs. HEAD, on the other hand, can be used in conjuction with both of these path types.

Her er noen eksempler på revisjonsnøkkelord i aksjon:

$ svn diff -r PREV:COMMITTED foo.c
# viser den siste forandringen lagt inn i foo.c

$ svn log -r HEAD
# viser loggmelding for den seneste innleggingen i depotet

$ svn diff -r HEAD
# sammenligner arbeidskopien din (med alle lokale forandringer) med den 
# seneste versjonen av det treet i depotet

$ svn diff -r BASE:HEAD foo.c
# sammenligner den umodifiserte versjonen av foo.c mot den seneste 
# versjonen av foo.c i depotet

$ svn log -r BASE:HEAD
# viser alle loggmeldinger for den nåværende versjonerte katalogen siden 
# du sist oppdaterte

$ svn update -r PREV foo.c
# omgjør den nyeste forandringen i foo.c og minsker arbeidsrevisjonen 
# for foo.c

$ svn diff -r BASE:14 foo.c
# sammenligner den umodifiserte versjonen av foo.c med det foo.c var i 
# revisjon 14

Revisjonsdatoer

Revision numbers reveal nothing about the world outside the version control system, but sometimes you need to correlate a moment in real time with a moment in version history. To facilitate this, the --revision option can also accept as input date specifiers wrapped in curly braces ({ and }). Subversion accepts the standard ISO-8601 date and time formats, plus a few others. Here are some examples. (Remember to use quotes around any date that contains spaces.)

$ svn checkout -r {2006-02-17}
$ svn checkout -r {15:30}
$ svn checkout -r {15:30:00.200000}
$ svn checkout -r {"2006-02-17 15:30"}
$ svn checkout -r {"2006-02-17 15:30 +0230"}
$ svn checkout -r {2006-02-17T15:30}
$ svn checkout -r {2006-02-17T15:30Z}
$ svn checkout -r {2006-02-17T15:30-04:00}
$ svn checkout -r {20060217T1530}
$ svn checkout -r {20060217T1530Z}
$ svn checkout -r {20060217T1530-0500}
…

When you specify a date, Subversion resolves that date to the most recent revision of the repository as of that date, and then continues to operate against that resolved revision number:

$ svn log -r {2006-11-28}
------------------------------------------------------------------------
r12 | ira | 2006-11-27 12:31:51 -0600 (man, 27 nov 2006) | 6 lines
…

Du kan også bruke et område av datoer. Subversion vil finne alle revisjoner mellom to datoer, inkludert:

$ svn log -r {2006-11-20}:{2006-11-29}
…

Som vi har påpekt, kan du også blande datoer og revisjoner:

$ svn log --revision {2002-11-20}:4040
[Advarsel]Advarsel

Siden tidspunktet på en revisjon er lagret som en uversjonert, redigerbar egenskap for revisjonen (se “Egenskaper”, kan revisjonsegenskaper bli forandret til å representere en kronologi som ikke stemmer, eller kan til og med bli fjernet helt. Dette vil rote til den interne dato-til-revisjon-konverteringen som Subversion utfører.

Egenskaper

Vi har allerede dekket i detalj hvordan Subversion lagrer og henter diverse versjoner av filer og kataloger i depotet. Hele kapitler er viet til disse mest fundamentale delene av funksjonalitet som verktøyet har. Og hvis versjoneringsmulighetene stoppet der, ville Subversion fortsatt være komplett sett fra et versjonskontrollsynspunkt.

Men det stopper ikke der.

I tillegg til å versjonere kataloger og filer, har Subversion grensesnitt for å legge til, forandre og fjerne versjonerte metadata på alle versjonerte kataloger og filer. Vi refererer til disse metadataene som egenskaper (engelsk: properties), og du kan tenke på dem som en tabell med to kolonner som forbinder egenskapsnavn med vilkårlige verdier som ligger sammen med hvert element i arbeidskopien din. Generelt sett kan navnene og verdiene til egenskapene være hva du vil at de skal være, med den begrensningen at navnene må være lesbar for mennesker. Og det beste med disse egenskapene er at de også er versjonerte, akkurat som det tekstbaserte innholdet i filene dine. Du kan forandre, legge inn og reversere egenskapsforandringer like lett som å legge inn forandringer i innhold. Og sending og henting av egenskapsforandringer blir en del av dine vanlige innleggingsoperasjoner – du trenger ikke å forandre på rutinene for å få det til.

Egenskaper finnes også andre steder i Subversion. Akkurat som filer og kataloger kan ha vilkårlige egenskapsnavn og verdier vedlagt, kan hver revisjon som helhet ha vilkårlige egenskaper lagt ved. De samme begrensningene gjelder også her – navnene må være lesbare for mennesker, men verdiene kan være binære og alt hva du vil. Hovedforskjellen er at revisjonsegenskaper ikke er versjonerte. Med andre ord, hvis du forandrer verdien på, eller sletter, en revisjonsegenskap, er det ingen funksjonalitet i Subversion for å sette den tilbake til den forrige verdien.

Subversion har ingen spesiell policy angående bruken av egenskaper. Alt Subversion ber om er at du ikke bruker egenskapsnavn som begynner med forstavelsen svn:. Det er det navnerommet som er reservert for egen bruk. Og Subversion bruker faktisk egenskaper, både av den versjonerte og uversjonerte typen. Enkelte versjonerte egenskaper har spesiell betydning eller effekt når de brukes på filer og kataloger, eller lagrer spesiell informasjon om revisjonene de finnes i. Enkelte revisjonsegenskaper legges automatisk til revisjoner av innleggingsprosessen, og inneholder informasjon om revisjonen. Mesteparten av disse egenskapene er nevnt andre steder andre steder i dette eller andre kapitler som del av de mer generelle emnene de hører til. For en fyldig liste over Subversions forhåndsdefinerte egenskaper, se Subversion-defined properties.

I denne seksjonen vil vi studere nyttigheten – både for Subversionbrukere og Subversion selv – av støtte for egenskaper. Du vil lære om de egenskapsrelaterte svn-delkommandoene og hvordan forandring av egenskaper påvirker den normale arbeidsflyten i Subversion. Forhåpentligvis vil du bli overbevist om at Subversionegenskaper kan forbedre bruken din av versjonskontroll.

Hvorfor bruke egenskaper?

Akkurat som Subversion bruker egenskaper for å lagre ekstra informasjon om filer, kataloger og revisjoner som den inneholder, kan du også få god bruk for egenskaper. Noen deler av prosessene rundt bruken din av Subversion, eller kanskje tilleggsprogrammer til Subversion som du bruker, kan få nytte av å ha en plass nær dine versjonerte data der du kan legge spesialsydde metadata om disse dataene.

Tenk deg at du vil sette opp en hjemmeside som inneholder mange digitale bilder, og viser dem med tittel og tidspunkt. Fotosamlingen forandrer seg i ett sett, så du vil helst automatisere så mye som mulig. Disse bildene kan være ganske store, så du vil i likhet med andre hjemmesider av denne typen vise miniatyrbilder til de besøkende.

Nå kan du saktens oppnå denne effekten ved å bruke tradisjonelle filer. Det vil si at du kan ha bildet bilde123.jpg og en bilde123-mini.jpg side ved side i en katalog. Eller hvis du vil bruke det samme filnavnet, kan du ha miniatyrbildene i en annen katalog, for eksempel mini/bilde123.jpg. Du kan også lagre titlene og tidspunktene på en lignende måte, separert fra den originale bildefila. Men problemet her er at samlingen din av filer vokser noe voldsomt for hvert nytt bilde som blir lagt til hjemmesida.

Så kan du se for deg den samme hjemmesida lagt opp på en måte som bruker Subversions filegenskaper. Tenk deg å ha en enkelt bildefil, bilde123.jpg, med egenskaper på denne fila som er kalt tittel, tidspunkt og miniatyr. Nå ser arbeidskopien din mye mer oversiktlig ut – faktisk ser det med en vanlig nettleser ut som det bare er bildefiler i den. Men de automatiserte skriptene dine vet bedre. De vet at de kan bruke svn (eller enda bedre, de kan bruke språkbindingene i Subversion – se “Using Languages Other than C and C++”) for å hente ut den ekstra informasjonen som hjemmesida trenger for å vise bildet uten å måtte lese en indeksfil eller trikse med filstier.

Spesialsydde revisjonsegenskaper blir også ofte brukt. En vanlig bruksmåte er en egenskap der verdien inneholder en ID fra en feildatabase som revisjonen er assosiert med, kanskje fordi forandringen i den revisjonen ordner en feil som er logget i feildatabasen med den ID-en. Andre bruksmåter kan være å legge ved mer brukervennlige navn i revisjonen – det kan være vanskelig å huske at revisjon 1935 var en gjennomtestet revisjon. Men hvis det er, la oss si, en testresultat-egenskap på den revisjonen med en verdi som Alt OK, er det god informasjon å ha.

Manipulering av egenskaper

svn-kommandoen har flere måter å legge til og modifisere fil- og katalogegenskaper. For egenskaper med korte egenskaper som er leselig for folk flest, er kanskje den enkleste måten å legge til en ny egenskap å spesifisere navnet på egenskapen med verdien dens på kommandolinja med propset-delkommandoen.

$ svn propset copyright '(c) 2006 Red-Bean Software' calc/button.c
Egenskapen «copyright» satt på «calc/button.c»
$

Men vi har fremhevet fleksibiliteten som Subversion har for egenskapsverdier. Og hvis du har en tekstbasert, eller til og med binær egenskapsverdi som går over flere linjer, vil du sannsynligvis ikke oppgi denne verdien på kommandolinja. Derfor kan propset-delkommandoen bruke valget --file (-F) for å spesifisere navnet på en fil som inneholder den nye verdien til egenskapen.

$ svn propset license -F /sti/til/LISENS calc/button.c
Egenskapen «license» satt på «calc/button.c»
$

Det er noen restriksjoner på navnene du kan bruke på egenskaper. Et egenskapsnavn må starte med en bokstav, kolon (:) eller understrek (_). Etter dette kan du også bruke siffer, bindestrek (-) og punktum (.).[8]

I tillegg til propset-kommandoen, har svn-programmet kommandoen propedit. Denne kommandoen bruker tekstbehandleren som er spesifisert i konfigurasjonen (se “Konfigurasjon”) for å legge til eller modifisere egenskaper. Når du kjører kommandoen, kjører svn tekstbehandleren mot en midlertidig fil som inneholder den nåværende verdien til egenskapen (eller starter uten tekst hvis du legger til en ny egenskap). Deretter forandrer du på verdien i tekstbehandleren til den er lik den nye verdien du vil lagre i egenskapen, lagrer den midlertidige fila og avslutter tekstbehandleren. Hvis Subversion finner ut at du faktisk har forandret den nåværende egenskapsverdien, vil den godta det som den nye verdien til egenskapen. Hvis du avslutter tekstbehandleren uten å gjøre noen forandringer, vil det ikke bli gjort noen forandringer i egenskapen.

$ svn propedit copyright calc/button.c
### tekstbehandleren avsluttes uten at noe er forandret
Ingen endring for egenskap «copyright» på «calc/button.c»
$

Vi skal legge merke til at i likhet med andre svn-kommandoer kan de som har med egenskaper å gjøre utføre handlinger på flere stier på en gang. Dette lar deg forandre egenskaper på hele sett av filer med en enkelt kommando. For eksempel kunne vi ha gjort dette:

$ svn propset copyright '(c) 2006 Red-Bean Software' calc/*
Egenskapen «copyright» satt på «calc/Makefile»
Egenskapen «copyright» satt på «calc/button.c»
Egenskapen «copyright» satt på «calc/integer.c»
…
$

Alt dette med å legge til og redigere egenskaper hadde egentlig ikke vært særlig nyttig hvis du ikke hadde hatt en måte å få tak i den lagrede egenskapsverdien. Til dette har svn-programmet to delkommandoer for å vise navnene og verdiene til egenskaper som er lagret i filer og kataloger. Kommandoen svn proplist vil liste ut navnene på egenskapene som eksisterer i en sti. Når du vet navnene til egenskapene på noden, kan du be om verdiene individuelt ved å bruke svn propget. Denne kommandoen vil, når den får en sti (eller sett av stier) og et egenskapsnavn, skrive verdien av egenskapen til standard ut-strømmen.

$ svn proplist calc/button.c
Egenskaper for «calc/button.c»:
  copyright
  license
$ svn propget copyright calc/button.c
(c) 2006 Red-Bean Software

Det er til og med en variant av proplist-kommandoen som vil liste både navnet og verdien til alle egenskapene. Bare legg til valget --verbose (-v).

$ svn proplist --verbose calc/button.c
Egenskaper for «calc/button.c»:
  copyright : (c) 2006 Red-Bean Software
  license : ================================================================
Copyright (c) 2006 Red-Bean Software.  All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions 
are met:

1. Redistributions of source code must retain the above copyright
notice, this list of conditions, and the recipe for Fitz's famous
red-beans-and-rice.
…

Den siste delkommandoen relatert til egenskaper er propdel. Siden Subversion lar deg lagre egenskaper med tomme verdier, kan du ikke fjerne en egenskap helt ved å bruke propedit eller propset. For eksempel, denne kommandoen vil ikke gjøre det du ønsker:

$ svn propset license '' calc/button.c
Egenskapen «license» satt på «calc/button.c»
$ svn proplist --verbose calc/button.c
Egenskaper for «calc/button.c»:
  copyright : (c) 2006 Red-Bean Software
  license : 
$

Du må bruke propdel-delkommandoen for å fjerne egenskaper helt. Syntaksen er lik de andre egenskapskommandoene:

$ svn propdel license calc/button.c
Egenskapen «license» slettet fra «calc/button.c».
$ svn proplist --verbose calc/button.c
Egenskaper for 'calc/button.c':
  copyright : (c) 2006 Red-Bean Software
$

Husker du de uversjonerte revisjonsegenskapene? Du kan modifisere disse også ved hjelp av de samme delkommandoene for svn som vi nettopp beskrev. Bare legg til --revprop-valget på kommandolinja og spesifiser revisjonen for den egenskapen du vil forandre. Siden revisjoner er globale, trenger du ikke å spesifisere en målsti sammen med disse egenskapsrelaterte kommandoene så lenge du er i en arbeidskopi fra depotet som har revisjonsegenskapen du vil forandre. Ellers kan du oppgi URLen for en hvilken som helst sti i depotet det gjelder (inkludert depotets rotadresse). Du vil for eksempel erstatte loggmeldingen for en eksisterende revisjon.[9] Hvis den nåværende katalogen er en del av en arbeidskopi fra depotet ditt, kan du ganske enkelt kjøre kommandoen svn propset uten å spesifisere en målsti:

$ svn propset svn:log '* button.c: Fjerna en kompilatoradvarsel.' -r11 --revprop
Egenskapen «svn:log» satt på depotrevisjon «11»
$

Men selv om du ikke har hentet ut en arbeidskopi fra depotet, kan du fortsatt forandre egenskapen ved å oppgi URLen til depotroten:

$ svn propset svn:log '* button.c: Fjerna en kompilatoradvarsel.' -r11 --revprop \
              http://svn.example.com/depot/prosjekt
Egenskapen «svn:log» satt på depotrevisjon «11»
$

Legg merke til at muligheten til å forandre disse uversjonerte egenskapene må settes spesielt av depotadministratoren (se “Påhakningsskript”). Siden egenskapene ikke er versjonerte, risikerer du å miste informasjon hvis du ikke er forsiktig når du redigerer. Depotadministratoren kan sette opp metoder for å beskytte mot datatap som dette, og standardoppsettet forbyr forandringer i revisjonsegenskaper.

[Tips]Tips

Brukere bør, der det er mulig, bruke svn propedit istedenfor svn propset. Selv om sluttresultatet er identisk, vil førstnevnte la dem se den nåværende verdien av egenskapen som de er i ferd med å forandre, noe som hjelper dem å kontrollere at de faktisk gjør den endringen som de tror de gjør. Dette gjelder spesielt for modifisering av uversjonerte revisjonsegenskaper. I tillegg er det betraktelig enklere å redigere egenskaper som strekker seg over flere linjer i en tekstbehandler enn på kommandolinja.

Egenskaper og arbeidsflyten i Subversion

Nå som du er kjent med alle svn-kommandoene som er relatert til egenskaper, la oss se hvordan forandringer i egenskaper påvirker den vanlige arbeidsflyten i Subversion. Som vi nevnte tidligere, er fil- og katalogegenskaper versjonerte, akkurat som innholdet i filene dine. Dette betyr at Subversion har de samme mulighetene for fletting – med dertil potensielle konflikter – av andres forandringer inn i dine egne.

Og i likhet med filinnhold, er forandringene dine i egenskapene lokale modifiseringer som kun blir gjort permanente når du legger dem inn i depotet med svn commit. Egenskapsforandringene kan lett omgjøres – kommandoen svn revert vil sette filene og katalogene dine tilbake til den uredigerte tilstanden – innhold, egenskaper, alt. Du kan også få interessant informasjon om tilstanden til fil- og katalogegenskapene ved å bruke kommandoene svn status og svn diff.

$ svn status calc/button.c
 M     calc/button.c
$ svn diff calc/button.c
Egenskapsforandringer på: calc/button.c
___________________________________________________________________
Navn: copyright
   + (c) 2006 Red-Bean Software

$

Legg merke til hvordan status-delkommandoen viser M i den andre kolonnen istedenfor den første. Det er fordi vi har forandret egenskapene på calc/button.c, men ikke forandret tekstinnholdet. Hadde vi forandret begge to, ville det også vært en M i den første kolonnen (se svn status).

Du har kanskje lagt merke til den smårare måten Subversion viser forskjeller i egenskaper på. Du kan fortsatt kjøre svn diff og omdirigere resultatet for å lage en gyldig patchfil. patch-programmet vil imidlertid ignorere patcher for egenskaper – alle data som det ikke forstår vil bli ignorert. Dette betyr dessverre at for å patche egenskaper med en fil laget av svn diff, må forandringer i egenskaper legges til for hånd.

Automatic Property Setting

Properties are a powerful feature of Subversion, acting as key components of many Subversion features discussed elsewhere in this and other chapters—textual diff and merge support, keyword substitution, newline translation, etc. But to get the full benefit of properties, they must be set on the right files and directories. Unfortunately, that can be a step easily forgotten in the routine of things, especially since failing to set a property doesn't usually result in an obvious error condition (at least compared to, say, failing to add a file to version control). To help your properties get applied to the places that need them, Subversion provides a couple of simple but useful features.

Whenever you introduce a file to version control using the svn add or svn import commands, Subversion tries to assist by setting some common file properties automatically. First, on operating systems whose filesystems support an execute permission bit, Subversion will automatically set the svn:executable property on newly added or imported files whose execute bit is enabled. (See “File Executability” for more about this property.) Secondly, it runs a very basic heuristic to determine if that file contains human-readable content. If not, Subversion will automatically set the svn:mime-type property on that file to application/octet-stream (the generic this is a collection of bytes MIME type). Of course, if Subversion guesses incorrectly, or if you wish to set the svn:mime-type property to something more precise—perhaps image/png or application/x-shockwave-flash—you can always remove or edit that property. (For more on Subversion's use of MIME types, see “File Content Type”.)

Subversion also provides, via its runtime configuration system (see “Konfigurasjonsområdet for bruk under kjøring”), a more flexible automatic property setting feature which allows you to create mappings of filename patterns to property names and values. Once again, these mappings affect adds and imports, and not only can override the default MIME type decision made by Subversion during those operations, but can also set additional Subversion or custom properties, too. For example, you might create a mapping that says that any time you add JPEG files—ones that match the pattern *.jpg—Subversion should automatically set the svn:mime-type property on those files to image/jpeg. Or perhaps any files that match *.cpp should have svn:eol-style set to native, and svn:keywords set to Id. Automatic property support is perhaps the handiest property related tool in the Subversion toolbox. See “Konfigurasjon” for more about configuring that support.

File Portability

Fortunately for Subversion users who routinely find themselves on different computers with different operating systems, Subversion's command-line program behaves almost identically on all those systems. If you know how to wield svn on one platform, you know how to wield it everywhere.

However, the same is not always true of other general classes of software, or of the actual files you keep in Subversion. For example, on a Windows machine, the definition of a text file would be similar to that used on a Linux box, but with a key difference—the character sequences used to mark the ends of the lines of those files. There are other differences, too. Unix platforms have (and Subversion supports) symbolic links; Windows does not. Unix platforms use filesystem permission to determine executability; Windows uses filename extensions.

Because Subversion is in no position to unite the whole world in common definitions and implementations of all of these things, the best it can do is to try to help make your life simpler when you need to work with your versioned files and directories on multiple computers and operating systems. This section describes some of the ways Subversion does this.

File Content Type

Subversion joins the ranks of the many applications which recognize and make use of Multipurpose Internet Mail Extensions (MIME) content types. Besides being a general-purpose storage location for a file's content type, the value of the svn:mime-type file property determines some behavioral characteristics of Subversion itself.

For example, one of the benefits that Subversion typically provides is contextual, line-based merging of changes received from the server during an update into your working file. But for files containing non-textual data, there is often no concept of a line. So, for versioned files whose svn:mime-type property is set to a non-textual MIME type (generally, something that doesn't begin with text/, though there are exceptions), Subversion does not attempt to perform contextual merges during updates. Instead, any time you have locally modified a binary working copy file that is also being updated, your file is renamed with a .orig extension, and then Subversion stores a new working copy file that contains the changes received during the update, but not your own local modifications, at the original filename. This behavior is really for the protection of the user against failed attempts at performing contextual merges on files that simply cannot be contextually merged.

Also, if the svn:mime-type property is set, then the Subversion Apache module will use its value to populate the Content-type: HTTP header when responding to GET requests. This gives your web browser a crucial clue about how to display a file when using it to peruse your Subversion repository's contents.

File Executability

On many operating systems, the ability to execute a file as a command is governed by the presence of an execute permission bit. This bit usually defaults to being disabled, and must be explicitly enabled by the user for each file that needs it. But it would be a monumental hassle to have to remember exactly which files in freshly checked-out working copy were supposed to have their executable bits toggled on, and then to have to do that toggling. So, Subversion provides the svn:executable property as a way to specify that the executable bit for the file on which that property is set should be enabled, and Subversion honors that request when populating working copies with such files.

This property has no effect on filesystems that have no concept of an executable permission bit, such as FAT32 and NTFS. [11] Also, although it has no defined values, Subversion will force its value to * when setting this property. Finally, this property is valid only on files, not on directories.

End-of-Line Character Sequences

Unless otherwise noted using a versioned file's svn:mime-type property, Subversion assumes the file contains human-readable data. Generally speaking, Subversion only uses this knowledge to determine if contextual difference reports for that file are possible. Otherwise, to Subversion, bytes are bytes.

This means that by default, Subversion doesn't pay any attention to the type of end-of-line (EOL) markers used in your files. Unfortunately, different operating systems have different conventions about which character sequences represent the end of a line of text in a file. For example, the usual line ending token used by software on the Windows platform is a pair of ASCII control characters—a carriage return (CR) followed by a line feed (LF). Unix software, however, just uses the LF character to denote the end of a line.

Not all of the various tools on these operating systems are prepared to understand files that contain line endings in a format that differs from the native line ending style of the operating system on which they are running. Common results are that Unix programs treat the CR character present in Windows files as a regular character (usually rendered as ^M), and that Windows programs combine all of the lines of a Unix file into one giant line because no carriage return-linefeed (or CRLF) character combination was found to denote the end of line.

This sensitivity to foreign EOL markers can become frustrating for folks who share a file across different operating systems. For example, consider a source code file, and developers that edit this file on both Windows and Unix systems. If all the developers always use tools which preserve the line ending style of the file, no problems occur.

But in practice, many common tools either fail to properly read a file with foreign EOL markers, or they convert the file's line endings to the native style when the file is saved. If the former is true for a developer, he has to use an external conversion utility (such as dos2unix or its companion, unix2dos) to prepare the file for editing. The latter case requires no extra preparation. But both cases result in a file that differs from the original quite literally on every line! Prior to committing his changes, the user has two choices. Either he can use a conversion utility to restore the modified file to the same line ending style that it was in before his edits were made. Or, he can simply commit the file—new EOL markers and all.

The result of scenarios like these include wasted time and unnecessary modifications to committed files. Wasted time is painful enough. But when commits change every line in a file, this complicates the job of determining which of those lines were changed in a non-trivial way. Where was that bug really fixed? On what line was a syntax error introduced?

The solution to this problem is the svn:eol-style property. When this property is set to a valid value, Subversion uses it to determine what special processing to perform on the file so that the file's line ending style isn't flip-flopping with every commit that comes from a different operating system. The valid values are:

native

This causes the file to contain the EOL markers that are native to the operating system on which Subversion was run. In other words, if a user on a Windows machine checks out a working copy that contains a file with an svn:eol-style property set to native, that file will contain CRLF EOL markers. A Unix user checking out a working copy which contains the same file will see LF EOL markers in his copy of the file.

Note that Subversion will actually store the file in the repository using normalized LF EOL markers regardless of the operating system. This is basically transparent to the user, though.

CRLF

This causes the file to contain CRLF sequences for EOL markers, regardless of the operating system in use.

LF

This causes the file to contain LF characters for EOL markers, regardless of the operating system in use.

CR

This causes the file to contain CR characters for EOL markers, regardless of the operating system in use. This line ending style is not very common. It was used on older Macintosh platforms (on which Subversion doesn't even run).

Ignoring Unversioned Items

In any given working copy there is a good chance that alongside all those versioned files and directories are other files and directories which are neither versioned nor intended to be. Text editors litter directories with backup files. Code compilation processes generate intermediate—or even final—files which you typically wouldn't bother to version. And users themselves drop various other files and directories wherever they see fit, often in version control working copies.

It's ludicrous to expect Subversion working copies to be somehow impervious to this kind of clutter and impurity. In fact, Subversion counts it as a feature that its working copies are just typical directories, just like unversioned trees. But these not-to-be-versioned files and directories can cause some annoyance for Subversion users. For example, because the svn add and svn import commands act recursively by default, and don't know which files in a given tree you do and don't wish to version, it's easy to accidentally add stuff to version control that you didn't mean to. And because svn status reports, by default, every item of interest in a working copy—including unversioned files and directories—its output can get quite noisy where many of these things exist.

So Subversion provides two ways for telling it which files you would prefer that it simply disregard. One of the ways involves the use of Subversion's runtime configuration system (see “Konfigurasjonsområdet for bruk under kjøring”), and therefore applies to all the Subversion operations which make use of that runtime configuration, generally those performed on a particular computer, or by a particular user of a computer. The other way makes use of Subversion's directory property support, is more tightly bound to the versioned tree itself, and therefore affects everyone who has a working copy of that tree. Both of the mechanisms use file patterns.

The Subversion runtime configuration system provides an option, global-ignores, whose value is a whitespace-delimited collection of file patterns (or globs). These patterns are applied to files which are candidates for addition to version control, as well as to unversioned files which the svn status command notices. If the filenames match one of the patterns, Subversion will basically act as if the file didn't exist at all. This is really useful for file patterns which are nearly universally of the variety that you don't want to version, such as editor backup files like Emacs' *~ and .*~ files.

When found on a versioned directory, the svn:ignore property is expected to contain a list of newline-delimited file patterns which Subversion should use to determine ignorable objects in that same directory. These patterns do not override those found in the global-ignores runtime configuration option, but are instead appended to that list. And it's worth noting again that, unlike the global-ignores option, the patterns found in the svn:eol-ignore property apply only to the directory on which that property is set, and not to any of its subdirectories. The svn:ignore property is a good way to tell Subversion to ignore files that are likely to be present in every user's working copy of that directory, such as compiler output or—to use an example more appropriate to this book—the HTML, PDF, or PostScript files generated as the result of a conversion of some source DocBook XML files to a more legible output format.

[Advarsel]Advarsel

Subversion's support for ignorable file patterns extends only to the one-time process of adding unversioned files and directories to version control. Once an object is under Subversion's control, the ignore pattern mechanisms no longer apply to it. In other words, don't expect Subversion to avoid committing changes you've made to a versioned file simply because that file's name matches an ignore pattern—Subversion always notices all of its versioned objects.

The global list of ignore patterns tends to be more a matter of personal taste, and tied more closely to a user's particular tool chain than to the details of any particular working copy's needs. So, the rest of this section will focus on the svn:ignore property and its uses.

Say you have the following output from svn status:

$ svn status calc
 M     calc/button.c
?      calc/calculator
?      calc/data.c
?      calc/debug_log
?      calc/debug_log.1
?      calc/debug_log.2.gz
?      calc/debug_log.3.gz

In this example, you have made some property modifications to button.c, but in your working copy you also have some unversioned files: the latest calculator program that you've compiled from your source code, a source file named data.c, and a set of debugging output log files. Now, you know that your build system always results in the calculator program being generated. [12] And you know that your test suite always leaves those debugging log files lying around. These facts are true for all working copies of this project, not just your own. And you know that you aren't interested in seeing those things every time you run svn status, and pretty sure that nobody else is interested in them either. So you use svn propedit svn:ignore calc to add some ignore patterns to the calc directory. For example, you might add this as the new value of the svn:ignore property:

calculator
debug_log*

After you've added this property, you will now have a local property modification on the calc directory. But notice what else is different about your svn status output:

$ svn status
 M     calc
 M     calc/button.c
?      calc/data.c

Now, all that cruft is missing from the output! Of course, your calculator compiled program and all those logfiles are still in your working copy. Subversion is simply not reminding you that they are present and unversioned. And now with all the uninteresting noise removed from the display, you are left with more interesting items—such as that source code file data.c that you probably forgot to add to version control.

Of course, this less-verbose report of your working copy status isn't the only one available. If you actually want to see the ignored files as part of the status report, you can pass the --no-ignore option to Subversion:

$ svn status --no-ignore
 M     calc
 M     calc/button.c
I      calc/calculator
?      calc/data.c
I      calc/debug_log
I      calc/debug_log.1
I      calc/debug_log.2.gz
I      calc/debug_log.3.gz

As mentioned earlier, the list of file patterns to ignore is also used by svn add and svn import. Both of these operations involve asking Subversion to begin managing some set of files and directories. Rather than force the user to pick and choose which files in a tree she wishes to start versioning, Subversion uses the ignore patterns—both the global and the per-directory lists—to determine which files should not be swept into the version control system as part of a larger recursive addition or import operation. And here again, you can use the --no-ignore option to tell Subversion ignore its ignores list and operate on all the files and directories present.

Keyword Substitution

Subversion has the ability to substitute keywords—pieces of useful, dynamic information about a versioned file—into the contents of the file itself. Keywords generally describe information about the last time the file was known to be modified. Because this information changes each time the file changes, and more importantly, just after the file changes, it is a hassle for any process except the version control system to keep the data completely up-to-date. Left to human authors, the information would inevitably grow stale.

For example, say you have a document in which you would like to display the last date on which it was modified. You could burden every author of that document to, just before committing their changes, also tweak the part of the document that describes when it was last changed. But sooner or later, someone would forget to do that. Instead simply ask Subversion to perform keyword substitution on the LastChangedDate keyword. You control where the keyword is inserted into your document by placing a keyword anchor at the desired location in the file. This anchor is just a string of text formatted as $KeywordName$.

All keywords are case-sensitive where they appear as anchors in files: you must use the correct capitalization in order for the keyword to be expanded. You should consider the value of the svn:keywords property to be case-sensitive too—certain keyword names will be recognized regardless of case, but this behavior is deprecated.

Subversion defines the list of keywords available for substitution. That list contains the following five keywords, some of which have aliases that you can also use:

Date

This keyword describes the last time the file was known to have been changed in the repository, and looks something like $Date: 2006-07-22 21:42:37 -0700 (Sat, 22 Jul 2006) $. It may also be specified as LastChangedDate.

Revision

This keyword describes the last known revision in which this file changed in the repository, and looks something like $Revision: 144 $. It may also be specified as LastChangedRevision or Rev.

Author

This keyword describes the last known user to change this file in the repository, and looks something like $Author: harry $. It may also be specified as LastChangedBy.

HeadURL

This keyword describes the full URL to the latest version of the file in the repository, and looks something like $HeadURL: http://svn.collab.net/repos/trunk/README $. It may be abbreviated as URL.

Id

This keyword is a compressed combination of the other keywords. Its substitution looks something like $Id: calc.c 148 2006-07-28 21:30:43Z sally $, and is interpreted to mean that the file calc.c was last changed in revision 148 on the evening of July 28, 2006 by the user sally.

Simply adding keyword anchor text to your file does nothing special. Subversion will never attempt to perform textual substitutions on your file contents unless explicitly asked to do so. After all, you might be writing a document [13] about how to use keywords, and you don't want Subversion to substitute your beautiful examples of un-substituted keyword anchors!

To tell Subversion whether or not to substitute keywords on a particular file, we again turn to the property-related subcommands. The svn:keywords property, when set on a versioned file, controls which keywords will be substituted on that file. The value is a space-delimited list of the keyword names or aliases found in the previous table.

For example, say you have a versioned file named weather.txt that looks like this:

Here is the latest report from the front lines.
$LastChangedDate$
$Rev$
Cumulus clouds are appearing more frequently as summer approaches.

With no svn:keywords property set on that file, Subversion will do nothing special. Now, let's enable substitution of the LastChangedDate keyword.

$ svn propset svn:keywords "Date Author" weather.txt
property 'svn:keywords' set on 'weather.txt'
$

Now you have made a local property modification on the weather.txt file. You will see no changes to the file's contents (unless you made some of your own prior to setting the property). Notice that the file contained a keyword anchor for the Rev keyword, yet we did not include that keyword in the property value we set. Subversion will happily ignore requests to substitute keywords that are not present in the file, and will not substitute keywords that are not present in the svn:keywords property value.

Immediately after you commit this property change, Subversion will update your working file with the new substitute text. Instead of seeing your keyword anchor $LastChangedDate$, you'll see its substituted result. That result also contains the name of the keyword, and continues to be bounded by the dollar sign ($) characters. And as we predicted, the Rev keyword was not substituted because we didn't ask for it to be.

Note also that we set the svn:keywords property to Date Author yet the keyword anchor used the alias $LastChangedDate$ and still expanded correctly.

Here is the latest report from the front lines.
$LastChangedDate: 2006-07-22 21:42:37 -0700 (Sat, 22 Jul 2006) $
$Rev$
Cumulus clouds are appearing more frequently as summer approaches.

If someone else now commits a change to weather.txt, your copy of that file will continue to display the same substituted keyword value as before—until you update your working copy. At that time the keywords in your weather.txt file will be re-substituted with information that reflects the most recent known commit to that file.

Subversion 1.2 introduced a new variant of the keyword syntax which brought additional, useful—though perhaps atypical—functionality. You can now tell Subversion to maintain a fixed length (in terms of the number of bytes consumed) for the substituted keyword. By using a double-colon (::) after the keyword name, followed by a number of space characters, you define that fixed width. When Subversion goes to substitute your keyword for the keyword and its value, it will essentially replace only those space characters, leaving the overall width of the keyword field unchanged. If the substituted value is shorter than the defined field width, there will be extra padding characters (spaces) at the end of the substituted field; if it is too long, it is truncated with a special hash (#) character just before the final dollar sign terminator.

For example, say you have a document in which you have some section of tabular data reflecting the document's Subversion keywords. Using the original Subversion keyword substitution syntax, your file might look something like:

$Rev$:     Revision of last commit
$Author$:  Author of last commit
$Date$:    Date of last commit

Now, that looks nice and tabular at the start of things. But when you then commit that file (with keyword substitution enabled, of course), you see:

$Rev: 12 $:     Revision of last commit
$Author: harry $:  Author of last commit
$Date: 2006-03-15 02:33:03 -0500 (Wed, 15 Mar 2006) $:    Date of last commit

The result is not so beautiful. And you might be tempted to then adjust the file after the substitution so that it again looks tabular. But that only holds as long as the keyword values are the same width. If the last committed revision rolls into a new place value (say, from 99 to 100), or if another person with a longer username commits the file, stuff gets all crooked again. However, if you are using Subversion 1.2 or better, you can use the new fixed-length keyword syntax, define some field widths that seem sane, and now your file might look like this:

$Rev::               $:  Revision of last commit
$Author::            $:  Author of last commit
$Date::              $:  Date of last commit

You commit this change to your file. This time, Subversion notices the new fixed-length keyword syntax, and maintains the width of the fields as defined by the padding you placed between the double-colon and the trailing dollar sign. After substitution, the width of the fields is completely unchanged—the short values for Rev and Author are padded with spaces, and the long Date field is truncated by a hash character:

$Rev:: 13            $:  Revision of last commit
$Author:: harry      $:  Author of last commit
$Date:: 2006-03-15 0#$:  Date of last commit

The use of fixed-length keywords is especially handy when performing substitutions into complex file formats that themselves use fixed-length fields for data, or for which the stored size of a given data field is overbearingly difficult to modify from outside the format's native application (such as for Microsoft Office documents).

[Advarsel]Advarsel

Be aware that because the width of a keyword field is measured in bytes, the potential for corruption of multi-byte values exists. For example, a username which contains some multi-byte UTF-8 characters might suffer truncation in the middle of the string of bytes which make up one of those characters. The result will be a mere truncation when viewed at the byte level, but will likely appear as a string with an incorrect or garbled final character when viewed as UTF-8 text. It is conceivable that certain applications, when asked to load the file, would notice the broken UTF-8 text and deem the entire file corrupt, refusing to operate on the file altogether.

Locking

Subversion's copy-modify-merge version control model lives and dies on its data merging algorithms, specifically on how well those algorithms perform when trying to resolve conflicts caused by multiple users modifying the same file concurrently. Subversion itself provides only one such algorithm, a three-way differencing algorithm which is smart enough to handle data at a granularity of a single line of text. Subversion also allows you to supplement its content merge processing with external differencing utilities (as described in “External diff3”), some of which may do an even better job, perhaps providing granularity of a word or a single character of text. But common among those algorithms is that they generally work only on text files. The landscape starts to look pretty grim when you start talking about content merges of non-textual file formats. And when you can't find a tool that can handle that type of merging, you begin to run into problems with the copy-modify-merge model.

Let's look at a real-life example of where this model runs aground. Harry and Sally are both graphic designers working on the same project, a bit of marketing collateral for an automobile mechanic. Central to the design of a particular poster is an image of a car in need of some body work, stored in a file using the PNG image format. The poster's layout is almost finished, and both Harry and Sally are pleased with the particular photo they chose for their damaged car—a baby blue 1967 Ford Mustang with an unfortunate bit of crumpling on the left front fender.

Now, as is common in graphic design work, there's a change in plans which causes the car's color to be a concern. So Sally updates her working copy to HEAD, fires up her photo editing software, and sets about tweaking the image so that the car is now cherry red. Meanwhile, Harry, feeling particularly inspired that day, decides that the image would have greater impact if the car also appears to have suffered greater impact. He, too, updates to HEAD, and then draws some cracks on the vehicle's windshield. He manages to finish his work before Sally finishes hers, and after admiring the fruits of his undeniable talent, commits the modified image. Shortly thereafter, Sally is finished with the car's new finish, and tries to commit her changes. But, as expected, Subversion fails the commit, informing Sally that now her version of the image is out of date.

Here's where the difficulty sets in. Were Harry and Sally making changes to a text file, Sally would simply update her working copy, receiving Harry's changes in the process. In the worst possible case, they would have modified the same region of the file, and Sally would have to work out by hand the proper resolution to the conflict. But these aren't text files—they are binary images. And while it's a simple matter to describe what one would expect the results of this content merge to be, there is precious little chance that any software exists which is smart enough to examine the common baseline image that each of these graphic artists worked against, the changes that Harry made, and the changes that Sally made, and spit out an image of a busted-up red Mustang with a cracked windshield!

Clearly, things would have gone more smoothly if Harry and Sally had serialized their modifications to the image. If, say, Harry had waited to draw his windshield cracks on Sally's now-red car, or if Sally had tweaked the color of a car whose windshield was already cracked. As is discussed in Kopier-rediger-flett-løsningen”, much of these types problems go away entirely where perfect communication between Harry and Sally exists. [14] But as one's version control system is, in fact, one form of communication, it follows that having that software facilitate the serialization of non-parallelizable energies is no bad thing. And this where Subversion's implementation of the lock-modify-unlock model steps into the spotlight. This is where we talk about Subversion's locking feature, which is similar to the reserved checkouts mechanisms of other version control systems.

Subversion's locking feature serves two main purposes:

  • Serializing access to a versioned object. By allowing a user to programmatically claim the exclusive right to change to a file in the repository, that user can be reasonably confident that energy invested on unmergeable changes won't be wasted—his commit of those changes will succeed.

  • Aiding communication. By alerting other users that serialization is in effect for particular versioned object, those other users can reasonably expect that the object is about to be changed by someone else, and they, too, can avoid wasting their time and energy on unmergeable changes that won't be committable due to eventual out-of-dateness.

When referring to Subversion's locking feature, one is actually talking about a fairly diverse collection of behaviors which include the ability to lock a versioned file [15] (claiming the exclusive right to modify the file), to unlock that file (yielding that exclusive right to modify), to see reports about which files are locked and by whom, to annotate files for which locking before editing is strongly advised, and so on. In this section, we'll cover all of these facets of the larger locking feature.

Creating locks

In the Subversion repository, a lock is a piece of metadata which grants exclusive access to one user to change a file. This user is said to be the lock owner. Each lock also has a unique identifier, typically a long string of characters, known as the lock token. The repository manages locks, ultimately handling their creation, enforcement, and removal. If any commit transaction attempts to modify or delete a locked file (or delete one of the parent directories of the file), the repository will demand two pieces of information—that the client performing the commit be authenticated as the lock owner, and that the lock token has been provided as part of the commit process as a sort of proof that client knows which lock it is using.

To demonstrate lock creation, let's refer back to our example of multiple graphic designers working with on the same binary image files. Harry has decided to change a JPEG image. To prevent other people from committing changes to the file while he is modifying it (as well as alerting them that he is about to change it), he locks the file in the repository using the svn lock command.

$ svn lock banana.jpg --message "Editing file for tomorrow's release."
'banana.jpg' locked by user 'harry'.
$

There are a number of new things demonstrated in the previous example. First, notice that Harry passed the --message option to svn lock. Similar to svn commit, the svn lock command can take comments (either via --message (-m) or --file (-F)) to describe the reason for locking the file. Unlike svn commit, however, svn lock will not demand a message by launching your preferred text editor. Lock comments are optional, but still recommended to aid communication.

Secondly, the lock attempt succeeded. This means that the file wasn't already locked, and that Harry had the latest version of the file. If Harry's working copy of the file had been out-of-date, the repository would have rejected the request, forcing Harry to svn update and reattempt the locking command. The locking command would also have failed if the file already been locked by someone else.

As you can see, the svn lock command prints confirmation of the successful lock. At this point, the fact that the file is locked becomes apparent in the output of the svn status and svn info reporting subcommands.

$ svn status
     K banana.jpg

$ svn info banana.jpg
Path: banana.jpg
Name: banana.jpg
URL: http://svn.example.com/repos/project/banana.jpg
Repository UUID: edb2f264-5ef2-0310-a47a-87b0ce17a8ec
Revision: 2198
Node Kind: file
Schedule: normal
Last Changed Author: frank
Last Changed Rev: 1950
Last Changed Date: 2006-03-15 12:43:04 -0600 (Wed, 15 Mar 2006)
Text Last Updated: 2006-06-08 19:23:07 -0500 (Thu, 08 Jun 2006)
Properties Last Updated: 2006-06-08 19:23:07 -0500 (Thu, 08 Jun 2006)
Checksum: 3b110d3b10638f5d1f4fe0f436a5a2a5
Lock Token: opaquelocktoken:0c0f600b-88f9-0310-9e48-355b44d4a58e
Lock Owner: harry
Lock Created: 2006-06-14 17:20:31 -0500 (Wed, 14 Jun 2006)
Lock Comment (1 line):
Editing file for tomorrow's release.

$

That the svn info command, which does not contact the repository when run against working copy paths, can display the lock token reveals an important fact about lock tokens—that they are cached in the working copy. The presence of the lock token is critical. It gives the working copy authorization to make use of the lock later on. Also, the svn status command shows a K next to the file (short for locKed), indicating that the lock token is present.

Now that Harry has locked banana.jpg, Sally is unable to change or delete that file:

$ svn delete banana.jpg
D         banana.jpg
$ svn commit -m "Delete useless file."
Deleting       banana.jpg
svn: Commit failed (details follow):
svn: DELETE of
'/repos/project/!svn/wrk/64bad3a9-96f9-0310-818a-df4224ddc35d/banana.jpg':
423 Locked (http://svn.example.com)
$

But Harry, after touching up the banana's shade of yellow, is able to commit his changes to the file. That's because he authenticates as the lock owner, and also because his working copy holds the correct lock token:

$ svn status
M    K banana.jpg
$ svn commit -m "Make banana more yellow"
Sending        banana.jpg
Transmitting file data .
Committed revision 2201.
$ svn status
$

Notice that after the commit is finished, svn status shows that the lock token is no longer present in working copy. This is the standard behavior of svn commit—it searches the working copy (or list of targets, if you provide such a list) for local modifications, and sends all the lock tokens it encounters during this walk to the server as part of the commit transaction. After the commit completes successfully, all of the repository locks that were mentioned are released—even on files that weren't committed. This is meant to discourage users from being sloppy about locking, or from holding locks for too long. If Harry haphazardly locks thirty files in a directory named images because he's unsure of which files he needs to change, yet only only changes four of those file, when he runs svn commit images, the process will still release all thirty locks.

This behavior of automatically releasing locks can be overridden with the --no-unlock option to svn commit. This is best used for those times when you want to commit changes, but still plan to make more changes and thus need to retain existing locks. You can also make this your default behavior by setting the no-unlock runtime configuration option (see “Konfigurasjonsområdet for bruk under kjøring”).

Of course, locking a file doesn't oblige one to commit a change to it. The lock can be released at any time with a simple svn unlock command:

$ svn unlock banana.c
'banana.c' unlocked.

Discovering locks

When a commit fails due to someone else's locks, it's fairly easy to learn about them. The easiest of these is svn status --show-updates:

$ svn status --show-updates
M              23   bar.c
M    O         32   raisin.jpg
       *       72   foo.h
Status against revision:     105
$

In this example, Sally can see not only that her copy of foo.h is out-of-date, but that one of the two modified files she plans to commit is locked in the repository. The O symbol stands for Other, meaning that a lock exists on the file, and was created by somebody else. If she were to attempt a commit, the lock on raisin.jpg would prevent it. Sally is left wondering who made the lock, when, and why. Once again, svn info has the answers:

$ svn info http://svn.example.com/repos/project/raisin.jpg
Path: raisin.jpg
Name: raisin.jpg
URL: http://svn.example.com/repos/project/raisin.jpg
Repository UUID: edb2f264-5ef2-0310-a47a-87b0ce17a8ec
Revision: 105
Node Kind: file
Last Changed Author: sally
Last Changed Rev: 32
Last Changed Date: 2006-01-25 12:43:04 -0600 (Sun, 25 Jan 2006)
Lock Token: opaquelocktoken:fc2b4dee-98f9-0310-abf3-653ff3226e6b
Lock Owner: harry
Lock Created: 2006-02-16 13:29:18 -0500 (Thu, 16 Feb 2006)
Lock Comment (1 line):
Need to make a quick tweak to this image.
$

Just as svn info can be used to examine objects in the working copy, it can also be used to examine objects in the repository. If the main argument to svn info is a working copy path, then all of the working copy's cached information is displayed; any mention of a lock means that the working copy is holding a lock token (if a file is locked by another user or in another working copy, svn info on a working copy path will show no lock information at all). If the main argument to svn info is a URL, then the information reflects the latest version of an object in the repository, and any mention of a lock describes the current lock on the object.

So in this particular example, Sally can see that Harry locked the file on February 16th to make a quick tweak. It being June, she suspects that he probably forgot all about the lock. She might phone Harry to complain and ask him to release the lock. If he's unavailable, she might try to forcibly break the lock herself or ask an administrator to do so.

Breaking and stealing locks

A repository lock isn't sacred—in Subversion's default configuration state, locks can be released not only by the person who created them, but by anyone at all. When somebody other than the original lock creator destroys a lock, we refer to this as breaking the lock.

From the administrator's chair, it's simple to break locks. The svnlook and svnadmin programs have the ability to display and remove locks directly from the repository. (For more information about these tools, see “En administrators verktøykasse”.)

$ svnadmin lslocks /usr/local/svn/repos
Path: /project2/images/banana.jpg
UUID Token: opaquelocktoken:c32b4d88-e8fb-2310-abb3-153ff1236923
Owner: frank
Created: 2006-06-15 13:29:18 -0500 (Thu, 15 Jun 2006)
Expires: 
Comment (1 line):
Still improving the yellow color.

Path: /project/raisin.jpg
UUID Token: opaquelocktoken:fc2b4dee-98f9-0310-abf3-653ff3226e6b
Owner: harry
Created: 2006-02-16 13:29:18 -0500 (Thu, 16 Feb 2006)
Expires: 
Comment (1 line):
Need to make a quick tweak to this image.

$ svnadmin rmlocks /usr/local/svn/repos /project/raisin.jpg
Removed lock on '/project/raisin.jpg'.
$

The more interesting option is allowing users to break each other's locks over the network. To do this, Sally simply needs to pass the --force to the unlock command:

$ svn status --show-updates
M              23   bar.c
M    O         32   raisin.jpg
       *       72   foo.h
Status against revision:     105
$ svn unlock raisin.jpg
svn: 'raisin.jpg' is not locked in this working copy
$ svn info raisin.jpg | grep URL
URL: http://svn.example.com/repos/project/raisin.jpg
$ svn unlock http://svn.example.com/repos/project/raisin.jpg
svn: Unlock request failed: 403 Forbidden (http://svn.example.com)
$ svn unlock --force http://svn.example.com/repos/project/raisin.jpg
'raisin.jpg' unlocked.
$

Now, Sally's initial attempt to unlock failed because she ran svn unlock directly on her working copy of the file, and no lock token was present. To remove the lock directly from the repository, she needs to pass a URL to svn unlock. Her first attempt to unlock the URL fails, because she can't authenticate as the lock owner (nor does she have the lock token). But when she passes --force, the authentication and authorization requirements are ignored, and the remote lock is broken.

Of course, simply breaking a lock may not be enough. In the running example, Sally may not only want to break Harry's long-forgotten lock, but re-lock the file for her own use. She can accomplish this by running svn unlock --force and then svn lock back-to-back, but there's a small chance that somebody else might lock the file between the two commands. The simpler thing to is steal the lock, which involves breaking and re-locking the file all in one atomic step. To do this, Sally passes the --force option to svn lock:

$ svn lock raisin.jpg
svn: Lock request failed: 423 Locked (http://svn.example.com)
$ svn lock --force raisin.jpg
'raisin.jpg' locked by user 'sally'.
$

In any case, whether the lock is broken or stolen, Harry may be in for a surprise. Harry's working copy still contains the original lock token, but that lock no longer exists. The lock token is said to be defunct. The lock represented by the lock-token has either been broken (no longer in the repository), or stolen (replaced with a different lock). Either way, Harry can see this by asking svn status to contact the repository:

$ svn status
     K raisin.jpg
$ svn status --show-updates
     B         32   raisin.jpg
$ svn update
  B  raisin.jpg
$ svn status
$

If the repository lock was broken, then svn status --show-updates displays a B (Broken) symbol next to the file. If a new lock exists in place of the old one, then a T (sTolen) symbol is shown. Finally, svn update notices any defunct lock tokens and removes them from the working copy.

Lock Communication

We've seen how svn lock and svn unlock can be used to create, release, break, and steal locks. This satisfies the goal of serializing commit access to a file. But what about the larger problem of preventing wasted time?

For example, suppose Harry locks an image file and then begins editing it. Meanwhile, miles away, Sally wants to do the same thing. She doesn't think to run svn status --show-updates, so she has no idea that Harry has already locked the file. She spends hours editing the file, and when she tries to commit her change, she discovers that either the file is locked or that she's out-of-date. Regardless, her changes aren't mergeable with Harry's. One of these two people has to throw away their work, and a lot of time has been wasted.

Subversion's solution to this problem is to provide a mechanism to remind users that a file ought to be locked before the editing begins. The mechanism is a special property, svn:needs-lock. If that property is attached to a file (regardless of its value, which is irrelevant), then Subversion will try to use filesystem-level permissions to make the file read-only, unless, of course, the user has explicitly locked the file. When a lock-token is present (as a result of running svn lock), the file becomes read-write. When the lock is released, the file becomes read-only again.

The theory, then, is that if the image file has this property attached, then Sally would immediately notice something is strange when she opens the file for editing. Many applications alert users immediately when a read-only file is opened for editing. And nearly all applications would at least prevent her from saving changes to the file. This reminds her to lock the file before editing, whereby she discovers the pre-existing lock:

$ /usr/local/bin/gimp raisin.jpg
gimp: error: file is read-only!
$ ls -l raisin.jpg
-r--r--r--   1 sally   sally   215589 Jun  8 19:23 raisin.jpg
$ svn lock raisin.jpg
svn: Lock request failed: 423 Locked (http://svn.example.com)
$ svn info http://svn.example.com/repos/project/raisin.jpg | grep Lock
Lock Token: opaquelocktoken:fc2b4dee-98f9-0310-abf3-653ff3226e6b
Lock Owner: harry
Lock Created: 2006-06-08 07:29:18 -0500 (Thu, 08 June 2006)
Lock Comment (1 line):
Making some tweaks.  Locking for the next two hours.
$
[Tips]Tips

Users and administrators alike are encouraged to attach the svn:needs-lock property to any file which cannot be contextually merged. This is the primary technique for encouraging good locking habits and preventing wasted effort.

Note that this property is a communication tool which works independently from the locking system. In other words, any file can be locked, whether or not this property is present. And conversely, the presence of this property doesn't make the repository require a lock when committing.

Unfortunately, the system isn't flawless. It's possible that even when a file has the property, the read-only reminder won't always work. Sometimes applications misbehave and hijack the read-only file, silently allowing users to edit and save the file anyway. There's not much that Subversion can do in this situation—at the end of the day, there's simply no substitution for good interpersonal communication. [16]

Externals Definitions

Sometimes it is useful to construct a working copy that is made out of a number of different checkouts. For example, you may want different subdirectories to come from different locations in a repository, or perhaps from different repositories altogether. You could certainly setup such a scenario by hand—using svn checkout to create the sort of nested working copy structure you are trying to achieve. But if this layout is important for everyone who uses your repository, every other user will need to perform the same checkout operations that you did.

Fortunately, Subversion provides support for externals definitions. An externals definition is a mapping of a local directory to the URL—and possibly a particular revision—of a versioned directory. In Subversion, you declare externals definitions in groups using the svn:externals property. You can create or modify this property using svn propset or svn propedit (see “Manipulering av egenskaper”). It can be set on any versioned directory, and its value is a multi-line table of subdirectories (relative to the versioned directory on which the property is set) and fully qualified, absolute Subversion repository URLs.

$ svn propget svn:externals calc
third-party/sounds             http://sounds.red-bean.com/repos
third-party/skins              http://skins.red-bean.com/repositories/skinproj
third-party/skins/toolkit -r21 http://svn.red-bean.com/repos/skin-maker

The convenience of the svn:externals property is that once it is set on a versioned directory, everyone who checks out a working copy with that directory also gets the benefit of the externals definition. In other words, once one person has made the effort to define those nested working copy checkouts, no one else has to bother—Subversion will, upon checkout of the original working copy, also checkout the external working copies.

Note the previous externals definition example. When someone checks out a working copy of the calc directory, Subversion also continues to checkout the items found in its externals definition.

$ svn checkout http://svn.example.com/repos/calc
A  calc
A  calc/Makefile
A  calc/integer.c
A  calc/button.c
Checked out revision 148.

Fetching external item into calc/third-party/sounds
A  calc/third-party/sounds/ding.ogg
A  calc/third-party/sounds/dong.ogg
A  calc/third-party/sounds/clang.ogg
…
A  calc/third-party/sounds/bang.ogg
A  calc/third-party/sounds/twang.ogg
Checked out revision 14.

Fetching external item into calc/third-party/skins
…

If you need to change the externals definition, you can do so using the regular property modification subcommands. When you commit a change to the svn:externals property, Subversion will synchronize the checked-out items against the changed externals definition when you next run svn update. The same thing will happen when others update their working copies and receive your changes to the externals definition.

[Tips]Tips

Because the svn:externals property has a multiline value, we strongly recommend that you use svn propedit instead of svn propset.

[Tips]Tips

You should strongly consider using explicit revision numbers in all of your externals definitions. Doing so means that you get to decide when to pull down a different snapshot of external information, and exactly which snapshot to pull. Besides avoiding the surprise of getting changes to third-party repositories that you might not have any control over, using explicit revision numbers also means that as you backdate your working copy to a previous revision, your externals definitions will also revert to the way they looked in that previous revision, which in turn means that the external working copies will be updated to match they way they looked back when your repository was at that previous revision. For software projects, this could be the difference between a successful and a failed build of an older snapshot of your complex codebase.

The svn status command also recognizes externals definitions, displaying a status code of X for the disjoint subdirectories into which externals are checked out, and then recursing into those subdirectories to display the status of the external items themselves.

The support that exists for externals definitions in Subversion today can be a little misleading, though. First, an externals definition can only point to directories, not files. Second, the externals definition cannot point to relative paths (paths like ../../skins/myskin). Third, the working copies created via the externals definition support are still disconnected from the primary working copy (on whose versioned directories the svn:externals property was actually set). And Subversion still only truly operates on non-disjoint working copies. So, for example, if you want to commit changes that you've made in one or more of those external working copies, you must run svn commit explicitly on those working copies—committing on the primary working copy will not recurse into any external ones.

Also, since the definitions themselves use absolute URLs, moving or copying a directory to which they are attached will not affect what gets checked out as an external (though the relative local target subdirectory will, of course, move with renamed directory). This can be confusing—even frustrating—in certain situations. For example, say you have a top-level directory named my-project, and you've created an externals definition on one of its subdirectories (my-project/some-dir) which tracks the latest revision of another of its subdirectories (my-project/external-dir).

$ svn co http://svn.example.com/projects .
A    my-project
A    my-project/some-dir
A    my-project/external-dir
…
Fetching external item into 'my-project/some-dir/subdir'
Checked out external at revision 11.

Checked out revision 11.
$ svn pget svn:externals my-project/some-dir
subdir http://svn.example.com/projects/my-project/external-dir

$

Now you use svn move to rename the my-project directory. At this point, your externals definition will still refer to a path under the my-project directory, even though that directory no longer exists.

$ svn mv -q my-project renamed-project
$ svn ci -m "Rename my-project to renamed-project."
Deleting       my-project
Adding         my-renamed-project

Committed revision 12.
$ svn up

Fetching external item into 'renamed-project/some-dir/subdir'
svn: Target path does not exist
$

Also, the fact that externals definitions use absolute URLs can cause problems with repositories that are available via multiple URL schemes. For example, if your Subversion server is configured to allow everyone to checkout the repository over http:// or https://, but only allow commits to come in via https://, you have an interesting problem on your hands. If your externals definitions use the http:// form of the repository URLs, you won't be able to commit anything from the working copies created by those externals. On the other hand, if they use the https:// form of the URLs, anyone who might be checking out via http:// because their client doesn't support https:// will be unable to fetch the external items. Be aware, too, that if you need to re-parent your working copy (using svn switch --relocate), externals definitions will not also be re-parented.

Finally, there might be times when you would prefer that svn subcommands would not recognize or otherwise operate on the external working copies created as the result of externals definition handling. In those instances, you can pass the --ignore-externals option to the subcommand.

Peg and Operative Revisions

We make use of the ability to copy, move, rename, and completely replace files and directories on our computers all the time. And your version control system shouldn't get in the way of your doing these things with your version-controlled files and directories, either. Subversion's file management support is quite liberating, affording almost as much flexibility for versioned files as you'd expect when manipulating your unversioned ones. But that flexibility means that across the lifetime of your repository, a given versioned object might have many paths, and a given path might represent several entirely different versioned objects. And this introduces a certain level of complexity to your interactions with those paths and objects.

Subversion is pretty smart about noticing when an object's version history includes such changes of address. For example, if you ask for the revision history log of a particular file that was renamed last week, Subversion happily provides all those logs—the revision in which the rename itself happened, plus the logs of relevant revisions both before and after that rename. So, most of the time, you don't even have to think about such things. But occasionally, Subversion needs your help to clear up ambiguities.

The simplest example of this occurs when a directory or file is deleted from version control, and then a new directory or file is created with the same name and added to version control. Clearly the thing you deleted and the thing you later added aren't the same thing. They merely happen to have had the same path, /trunk/object for example. What, then, does it mean to ask Subversion about the history of /trunk/object? Are you asking about the thing currently at that location, or the old thing you deleted from that location? Are you asking about the operations that have happened to all the objects that have ever lived at that path? Clearly, Subversion needs a hint about what you really want.

And thanks to moves, versioned object history can get far more twisted than that, even. For example, you might have a directory named concept, containing some nascent software project you've been toying with. Eventually, though, that project matures to the point that the idea seems to actually have some wings, so you do the unthinkable and decide to give the project a name. [17] Let's say you called your software Frabnaggilywort. At this point, it makes sense to rename the directory to reflect the project's new name, so concept is renamed to frabnaggilywort. Life goes on, Frabnaggilywort releases a 1.0 version, and is downloaded and used daily by hordes of people aiming to improve their lives.

It's a nice story, really, but it doesn't end there. Entrepreneur that you are, you've already got another think in the tank. So you make a new directory, concept, and the cycle begins again. In fact, the cycle begins again many times over the years, each time starting with that old concept directory, then sometimes seeing that directory renamed as the idea cures, sometimes seeing it deleted when you scrap the idea. Or, to get really sick, maybe you rename concept to something else for a while, but later rename the thing back to concept for some reason.

When scenarios like these occur, attempting to instruct Subversion to work with these re-used paths can be a little like instructing a motorist in Chicago's West Suburbs to drive east down Roosevelt Road and turn left onto Main Street. In a mere twenty minutes, you can cross Main Street in Wheaton, Glen Ellyn, and Lombard. And no, they aren't the same street. Our motorist—and our Subversion—need a little more detail in order to do the right thing.

In version 1.1, Subversion introduced a way for you to tell it exactly which Main Street you meant. It's called the peg revision, and it is a revision provided to Subversion for the sole purpose of identifying a unique line of history. Because at most one versioned object may occupy a path at any given time—or, more precisely, in any one revision—the combination of a path and a peg revision is all that is needed to refer to a specific line of history. Peg revisions are specified to the Subversion command-line client using at syntax, so called because the syntax involves appending an at sign (@) and the peg revision to the end of the path with which the revision is associated.

But what of the --revision (-r) of which we've spoken so much in this book? That revision (or set of revisions) is called the operative revision (or operative revision range). Once a particular line of history has been identified using a path and peg revision, Subversion performs the requested operation using the operative revision(s). To map this to our Chicagoland streets analogy, if we are told to go to 606 N. Main Street in Wheaton, [18] we can think of Main Street as our path and Wheaton as our peg revision. These two pieces of information identify a unique path which can travelled (north or south on Main Street), and will keep us from travelling up and down the wrong Main Street in search of our destination. Now we throw in 606 N. as our operative revision, of sorts, and we know exactly where to go.

Say that long ago we created our repository, and in revision 1 added our first concept directory, plus an IDEA file in that directory talking about the concept. After several revisions in which real code was added and tweaked, we, in revision 20, renamed this directory to frabnaggilywort. By revision 27, we had a new concept, a new concept directory to hold it, and a new IDEA file to describe it. And then five years and twenty thousand revisions flew by, just like they would in any good romance story.

Now, years later, we wonder what the IDEA file looked like back in revision 1. But Subversion needs to know if we are asking about how the current file looked back in revision 1, or are we asking for the contents of whatever file lived at concepts/IDEA in revision 1? Certainly those questions have different answers, and because of peg revisions, you can ask either of them. To find out how the current IDEA file looked in that old revision, you run:

$ svn cat -r 1 concept/IDEA 
svn: Unable to find repository location for 'concept/IDEA' in revision 1

Of course, in this example, the current IDEA file didn't exist yet in revision 1, so Subversion gives an error. The command above is shorthand for a longer notation which explicitly lists a peg revision. The expanded notation is:

$ svn cat -r 1 concept/IDEA@BASE
svn: Unable to find repository location for 'concept/IDEA' in revision 1

And when executed, it has the expected results. Peg revisions generally default to a value of BASE (the revision currently present in the working copy) when applied to working copy paths, and of HEAD when applied to URLs.

The perceptive reader is probably wondering at this point if the peg revision syntax causes problems for working copy paths or URLs that actually have at signs in them. After all, how does svn know whether news@11 is the name of a directory in my tree, or just a syntax for revision 11 of news? Thankfully, while svn will always assume the latter, there is a trivial workaround. You need only append an at sign to the end of the path, such as news@11@. svn only cares about the last at sign in the argument, and it is not considered illegal to omit a literal peg revision specifier after that at sign. This workaround even applies to paths that end in an at sign—you would use filename@@ to talk about a file named filename@.

Let's ask the other question, then—in revision 1, what were the contents of whatever file occupied the address concepts/IDEA at the time? We'll use an explicit peg revision to help us out.

$ svn cat concept/IDEA@1
The idea behind this project is to come up with a piece of software
that can frab a naggily wort.  Frabbing naggily worts is tricky
business, and doing it incorrectly can have serious ramifications, so
we need to employ over-the-top input validation and data verification
mechanisms.

Notice that we didn't provide an operative revision this time. That's because when no operative revision is specified, Subversion assumes a default operative revision that's the same as the peg revision.

As you can see, the output from our operation appears to be correct. The text even mentions frabbing naggily worts, so this is almost certainly the file which describes the software now called Frabnaggilywort. In fact, we can verify this using the combination of an explicit peg revision and explicit operative revision. We know that in HEAD, the Frabnaggilywort project is located in the frabnaggilywort directory. So we specify that we want to see how the line of history identified in HEAD as the path frabnaggilywort/IDEA looked in revision 1.

$ svn cat -r 1 frabnaggilywort/IDEA@HEAD
The idea behind this project is to come up with a piece of software
that can frab a naggily wort.  Frabbing naggily worts is tricky
business, and doing it incorrectly can have serious ramifications, so
we need to employ over-the-top input validation and data verification
mechanisms.

And the peg and operative revisions need not be so trivial, either. For example, say frabnaggilywort had been deleted from HEAD, but we know it existed in revision 20, and we want to see the diffs for its IDEA file between revisions 4 and 10. We can use the peg revision 20 in conjunction with the URL that would have held Frabnaggilywort's IDEA file in revision 20, and then use 4 and 10 as our operative revision range.

$ svn diff -r 4:10 http://svn.red-bean.com/projects/frabnaggilywort/IDEA@20
Index: frabnaggilywort/IDEA
===================================================================
--- frabnaggilywort/IDEA	(revision 4)
+++ frabnaggilywort/IDEA	(revision 10)
@@ -1,5 +1,5 @@
-The idea behind this project is to come up with a piece of software
-that can frab a naggily wort.  Frabbing naggily worts is tricky
-business, and doing it incorrectly can have serious ramifications, so
-we need to employ over-the-top input validation and data verification
-mechanisms.
+The idea behind this project is to come up with a piece of
+client-server software that can remotely frab a naggily wort.
+Frabbing naggily worts is tricky business, and doing it incorrectly
+can have serious ramifications, so we need to employ over-the-top
+input validation and data verification mechanisms.

Fortunately, most folks aren't faced with such complex situations. But when you are, remember that peg revisions are that extra hint Subversion needs to clear up ambiguity.

Nettverksmodellen

At some point, you're going to need to understand how your Subversion client communicates with its server. Subversion's networking layer is abstracted, meaning that the Subversion client exhibits the same general behaviors no matter what sort of server it speaks with. Whether it's talking to Apache via http:// or with svnserve via svn://, it responds to authentication challenges in the same ways, and even caches your login name and password for you. This section discusses these behaviors and shows you how to manage them to your liking.

Forespørsler og reponser

Subversionklienten bruker mesteparten av tida til å behandle arbeidskopier. Men når den trenger informasjon fra et depot foretar den en nettverksforespørsel og serveren kommer med et passende svar. Detaljene i nettverksprotokollen er skjult for brukeren; klienten prøver å aksessere en URL, og alt etter hvilket URL-skjema som brukes blir en passende protokoll brukt for å aksessere serveren (se Depot-URLer). Brukere kan kjøre svn --version for å se hvilke URL-skjema og protokoller klienten kan bruke.

Når serveren mottar en klientforespørsel, forlanger den vanligvis at klienten identifiserer seg. Den utsteder en autentiseringsforespørsel til klienten, og klienten svarer ved å legitimere seg ovenfor serveren. Når autentiseringen er komplett, svarer serveren med den originale informasjonen klienten spurte etter. Legg merke til at dette systemet er forskjellig fra systemer som CVS, hvor klienten på forhånd oppgir legitimasjon (logger inn) til serveren før noen forespørsel etter informasjon blir gjort. I Subversion henter serveren legitimasjonen ved å kontrollere klienten på det nødvendige tidspunktet i stedet for at klienten uoppfordret leverer den. Dette gjør visse operasjoner mer elegant. For eksempel, hvis en server er konfigurert til å la alle i hele verden få lese depotet, vil serveren aldri be om autentisering når klienten prøver en svn checkout.

Hvis klientens nettverksforespørsel skriver nye data til depotet (for eksempel svn commit), vil et nytt revisjonstre bli opprettet. Hvis klientens forespøsel ble autentisert, blir brukernavnet til den autentiserte brukeren lagret i svn:author-egenskapen i den nye revisjonen (se “Uversjonerte egenskaper”). Hvis klienten ikke ble autentisert (med andre ord, serveren spurte ikke etter legitimasjon), er revisjonens svn:author-egenskap tom.[19]

Lagring av klientlegitimasjon

Mange servere er satt opp til å forlange autentisering for hver eneste forespørsel. Dette kan bli et stort irritasjonsmoment for brukerne, som blir tvunget til å skrive passordet om og om igjen.

Heldigvis har Subversion en løsning på dette: Et innebygget system for å lagre legitimasjonen på disk. Normalt sett, når kommandolinjeklienten klarer å svare riktig på en autentiseringsforespørsel fra en server, lagres denne legitimasjonsinformasjonen i brukerens private konfigurasjonsområde – i ~/.subversion/auth/ på Unix-lignende systemer eller %APPDATA%/Subversion/auth/ i Windows. (Konfigurasjonsområdet er dekket mer inngående i “Konfigurasjonsområdet for bruk under kjøring”.) Data fra vellykkede autentiseringer lagres på disken, der nøkkelen er en kombinasjon av servernavn, port og området der autentiseringen gjelder.

Når klienten må gjennom en autentiseringsprosess, ser den først etter passende legitimasjonsdata i brukerens lager på disken. Hvis dette ikke finnes, eller de lagrede legitimasjonsdataene ikke er tilstrekkelig for å fullføre autentiseringen, spør klienten ganske enkelt brukeren etter informasjonen.

Sikkerhetsbevisste folk tenker nok med seg selv: Lagre passord på disken? Det er forferdelig! Sånt skal aldri gjøres! Men ta det med ro, det er ikke så farlig som det høres ut.

  • På Windows 2000 og senere bruker Subversionklienten standard kryptografitjenester i Windows for å kryptere passordet på disken. Fordi krypteringsnøkkelen blir vedlikeholdt av Windows og den er forbundet med brukerens egne innloggingsbrukerdata, kan bare brukeren dekryptere det lagrede passordet. (Merk: Hvis brukerens passord i Windows blir resatt av en administrator, kan ikke de lagrede passordene dekrypteres. Subversionklienten vil oppføre seg som om de ikke eksisterer og spørre etter passord når det er nødvendig.)

  • Similarly, on Mac OS X, the Subversion client stores all repository passwords in the login keyring (managed by the Keychain service), which is protected by the user's account password. User preference settings can impose additional policies, such as requiring the user's account password be entered each time the Subversion password is used.

  • For andre Unix-lignende operativsystemer eksisterer det ingen standardiserte nøkkelring-tjenester. Imidlertid er lagringsområdet i auth/ fortsatt beskyttet av rettigheter så bare brukeren (eieren) kan lese dataene derfra, ikke resten av verden. Operativsystemets egne filrettigheter beskytter passordet.

  • For den sanne paranoide som er villig til å ofre behageligheter, er det alltids mulig å deaktivere all lagring av legitimasjonsdata.

For å forhindre lagring for en enkelt kommando, spesifiser valget --no-auth-cache:

$ svn commit -F log_msg.txt --no-auth-cache
Authentication realm: <svn://host.example.com:3690> example realm
Username:  joe
Password for 'joe':

Adding         newfile
Transmitting file data .
Committed revision 2324.

# Passordet ble ikke lagret, så ved neste innlegging blir vi spurt på 
# nytt.

$ svn delete newfile
$ svn commit -F new_msg.txt
Authentication realm: <svn://host.example.com:3690> example realm
Username:  joe
…

Eller, hvis du vil slå av lagring av legitimasjonen permanent, kan du redigere config-fila (plassert ved siden av auth/-katalogen). Ved å sette store-auth-creds til no vil ingen legitimasjon bli lagret på disken i det hele tatt.

[auth]
store-auth-creds = no

Noen ganger vil brukere ønske å fjerne spesifikke legitimasjonsdata fra disklageret. For å gjøre dette, må du gå inn i auth/-området og manuelt slette den aktuelle fila. Legitimasjonen er lagret i individuelle filer, og hvis du ser på hver fil, vil du se nøkler og verdier. svn:realmstring-nøkkelen viser hvilket serverområde fila er assosiert med:

$ ls ~/.subversion/auth/svn.simple/
5671adf2865e267db74f09ba6f872c28
3893ed123b39500bca8a0b382839198e
5c3c22968347b390f349ff340196ed39

$ cat ~/.subversion/auth/svn.simple/5671adf2865e267db74f09ba6f872c28

K 8
username
V 3
joe
K 8
password
V 4
blah
K 15
svn:realmstring
V 45
<https://svn.domain.com:443> Joe's repository
END

Når du har funnet den riktige fila, er det bare å slette den.

Et siste ord om oppførselen under klientautentisering, en liten forklaring angående --username og --password er på sin plass. Mange delkommandoer for klienten godtar disse valgene, men det er viktig å forstå at bruken av disse valgene sender ikke brukerdata til serveren. Som tidligere nevnt, henter serveren brukerdata fra klienten når det er nødvendig; klienten kan ikke levere dataene når den vil. Hvis et brukernavn og/eller passord blir spesifisert som valg, vil de bare bli gitt til serveren hvis serveren spør etter dem.[20] Vanligvis blir disse valgene brukt når:

  • brukeren vil identifisere seg som en annen bruker enn brukernavnet på systemet, eller

  • et skript vil identifisere seg uten å bruke lagrede brukerdata.

Her er en avsluttende oversikt som beskriver hvordan en Subversionklient oppfører seg når den mottar en autentiseringsforespørsel:

  1. Sjekk om brukeren spesifiserte noen brukerdata som kommandolinjevalg med --username og/eller --password. Hvis ikke, eller hvis disse valgene ikke er i stand til å fullføre autentiseringen,

  2. Let opp serverens område i auth/-området for å se om brukeren allerede har lagret de nødvendige identifikasjonsdataene. Hvis ikke, eller hvis de lagrede brukerdataene ikke er tilstrekkelig for å autentisere,

  3. Spør brukeren.

Hvis klienten klarer å legitimere seg ved hjelp av noen av metodene nevnt ovenfor, vil den prøve å lagre brukerdataene på disken (unntatt hvis brukeren har slått av denne oppførselen, som tidligere nevnt).




[8] Hvis du kjenner til XML, er dette mye det samme som ASCII-delen av syntaksen for XML "Name".

[9] Retting av skrivefeil, grammatiske flauser og ting som er direkte feil i loggmeldinger er kanskje det vanligste bruksområdet for --revprop-valget.

[10] You think that was rough? During that same era, WordPerfect also used .DOC for their proprietary file format's preferred extension!

[11] The Windows filesystems use file extensions (such as .EXE, .BAT, and .COM) to denote executable files.

[12] Isn't that the whole point of a build system?

[13] … or maybe even a section of a book …

[14] Communication wouldn't have been such bad medicine for Harry and Sally's Hollywood namesakes, either, for that matter.

[15] Subversion does not currently allow locks on directories.

[16] Except, perhaps, a classic Vulcan mind-meld.

[17] You're not supposed to name it. Once you name it, you start getting attached to it. — Mike Wazowski

[18] 606 N. Main Street, Wheaton, Illinois, is the home of the Wheaton History Center. Get it—History Center? It seemed appropriate….

[19] Dette er egentlig et spørsmål som ofte dukker opp som et resultat av feil i konfigurasjonen på serveren.

[20] Som sagt, en vanlig feil er å feilkonfigurere serveren så den aldri spør etter autentiseringsinfo. Når brukere angir --username og --password til klienten, blir de overrasket over å se at dataene aldri blir brukt og at nye revisjoner fortsatt ser ut til å ha blitt lagt inn anonymt!

Kapittel 4. Forgrening og fletting

Forgrening (branching), merking (tagging) og fletting (merging) er konsepter felles for nesten alle versjonskontrollsystemer. Hvis du ikke er vant med disse idéene, gir vi en god introduksjon i dette kapittelet. Hvis du kjenner til dem, finner du det forhåpentligvis interessant å se hvordan Subversion har implementert disse idéene.

Forgreninger er en fundamental del av versjonskontroll. Hvis du skal tillate Subversion å behandle dine data, er dette en funksjon som du etterhvert kommer til å basere deg mye på. Dette kapittelet går ut i fra at du allerede er kjent med Subversions grunnleggende konsepter (Kapittel 1, Grunnleggende konsepter).

Hva er en forgrening?

Tenk deg at det er din jobb å vedlikeholde et dokument for en avdeling i firmaet ditt, en håndbok av et eller annet slag. En dag spør en annen avdeling deg etter den samme håndboka, men med noen deler spesialtilpasset for dem, siden de gjør ting litt forskjellig.

Hva gjør du i denne situasjonen? Du gjør den opplagte tingen: Du lager en annen kopi av dokumentet og begynner å vedlikeholde de to kopiene separat. Etterhvert som hver avdeling ber deg om å gjøre små forandringer, legger du dem inn i den ene kopien eller den andre.

Du vil ofte ønske å gjøre den samme forandringen i begge kopiene. Hvis du for eksempel finner en skrivefeil i den første kopien, er det veldig sannsynlig at den samme trykkfeilen eksisterer i den andre kopien. De to dokumentene er nesten like når alt kommer til alt; forskjellene er små og spesifikke.

Dette er det grunnleggende konseptet for en forgrening – det vil si en utviklingslinje som eksisterer uavhengig av en annen linje, men som likevel deler en felles historie hvis du ser langt nok tilbake i tid. En forgrening begynner bestandig livet som en kopi av noe, og går videre derfra ved å lage sin egen historie (se Figur 4.1, “Forgreninger av utviklingen”).

Figur 4.1. Forgreninger av utviklingen

Forgreninger av utviklingen


Subversion har kommandoer for å hjelpe deg å vedlikeholde parallelle forgreninger av filene og katalogene dine. Programmet lar deg opprette forgreninger ved å kopiere data, og husker at kopiene er relaterte til hverandre. I tillegg får du også hjelp til å duplisere forandringer fra en gren til en annen. Til sist, Subversion kan la porsjoner av arbeidskopien reflektere forskjellige forgreninger, så du kan blande og tilpasse forskjellige utviklingslinjer i ditt daglige arbeid.

Bruke forgreninger

På dette punktet skal du ha fått forståelsen av hvordan hver innlegging oppretter et helt nytt filsystemtre (kalt en revisjon) i depotet. Hvis ikke, gå tilbake og les om revisjoner i “Revisjoner”.

I dette kapittelet skal vi gå tilbake til det samme eksempelet fra Kapittel 1, Grunnleggende konsepter. Du husker at du og din kollega Sally deler et depot som inneholder to prosjekter – paint og calc. Merk imidlertid at i Figur 4.2, “Depotets utseende til å begynne med” inneholder hver prosjektkatalog underkataloger kalt trunk og branches. Grunnen til dette vil du snart få greie på.

Figur 4.2. Depotets utseende til å begynne med

Depotets utseende til å begynne med


Som tidligere, tenk deg at du og Sally begge har arbeidskopier av calc-prosjektet. Mer spesifikt, dere har begge en arbeidskopi av /calc/trunk. Alle filene for prosjektet er i denne underkatalogen istedenfor i selve /calc, fordi teamet ditt har bestemt at /calc/trunk er der hovedlinjen av utviklingen skal foregå.

La oss si at du har fått oppgaven å utføre en radikal reorganisering av prosjektet. Det vil ta lang tid å skrive, og vil påvirke alle filene i prosjektet. Problemet her er at du vil ikke forstyrre Sally, som er i full gang med å fikse småfeil her og der. Hun er avhengig av at den seneste versjonen av prosjektet (i /calc/trunk) alltid fungerer. Hvis du starter med å legge inn forandringene dine bit for bit, vil du ganske sikkert ødelegge ting for Sally.

En strategi er å krabbe inn i et hull; du og Sally kan stoppe med å dele informasjon for en uke eller to. Det vil si, starte med å omorganisere alle filene i arbeidskopien din, men ikke legge inn eller oppdatere før du er helt ferdig med oppgaven. Men det er en del problemer med denne metoden. For det første er det ikke særlig trygt. Folk flest liker å lagre arbeidet sitt til depotet med jevne mellomrom i tilfelle noe stygt skulle skje med arbeidskopien. For det andre er det ikke spesielt fleksibelt. Hvis du gjør arbeidet ditt på forskjellige datamaskiner (kanskje du har en arbeidskopi av /calc/trunk på to forskjellige maskiner) må du kopiere forandringene manuelt fram og tilbake, eller gjøre hele jobben på en enkelt maskin. På samme måte er det vanskelig å dele forandringene dine som er under utvikling med andre. Vanlig god praksis innen programutvikling er å la dine kolleger få se over arbeidet ditt mens du holder på. Hvis ingen ser innleggingene dine, går du glipp av potensiell respons. Til slutt, når du er ferdig med alle forandringene dine, kan du oppleve at det er veldig vanskelig å flette sammen det endelige resultatet ditt med resten av koden til firmaet. Sally (eller andre) kan ha gjort mange forandringer i depotet som er vanskelig å legge inn i arbeidskopien din – spesielt hvis du kjører svn update etter flere uker med isolasjon.

En bedre løsning er å opprette din egen forgrening, eller utviklingslinje, i depotet. Dette lar deg lagre det halvfungerende resultatet ditt med jevne mellomrom uten å blande det med arbeidet til andre, og samtidig kan du velge ut informasjon som du vil dele med dine kolleger. Du vil etter hvert få se nøyaktig hvordan dette fungerer.

Opprette en forgrening

Det å opprette en ny gren er veldig enkelt – du lager en kopi av prosjektet i depotet ved å bruke kommandoen svn copy. Subversion er ikke bare i stand til å kopiere enkle filer, men også hele kataloger. I dette tilfellet vil du lage en kopi av /calc/trunk-katalogen. Hvor skal den nye kopien være? Hvor du vil – det er et spørsmål om prosjektrutiner. La oss si at teamet ditt har som regel å opprette forgreninger i /calc/branches-området i depotet, og du vil kalle grenen din my-calc-branch. Det du vil er å lage en ny katalog, /calc/branches/my-calc-branch, som begynner livet som en kopi av /calc/trunk.

Det er to forskjellige måter å lage en kopi på. Vi vil demonstrere den rotete måten først, bare for å klargjøre konseptet. Til å begynne med, hent ut en arbeidskopi av prosjektets rotkatalog, /calc:

$ svn checkout http://svn.example.com/repos/calc bigwc
A  bigwc/trunk/
A  bigwc/trunk/Makefile
A  bigwc/trunk/integer.c
A  bigwc/trunk/button.c
A  bigwc/branches/
Sjekket ut revisjon 340.

For å lage en kopi er det nå bare å angi to arbeidskopistier til kommandoen svn copy:

$ cd bigwc
$ svn copy trunk branches/my-calc-branch
$ svn status
A  +   branches/my-calc-branch

I dette tilfellet kopierer svn copy katalogen trunk rekursivt til en ny arbeidskatalog, branches/my-calc-branch. Som du kan se av kommandoen svn status er den nye katalogen nå klargjort for å legges til i depotet. Men legg også merke til +-tegnet ved siden av bokstaven A. Dette indikerer at den klargjorte tilleggingen er en kopi av noe, og ikke noe nytt. Når du legger inn forandringene dine, vil Subversion lage /calc/branches/my-calc-branch i depotet ved å kopiere /calc/trunk istedenfor å sende hele arbeidskopien over nettverket en gang til:

$ svn commit -m "Lager en privat gren av /calc/trunk."
Legger til         branches/my-calc-branch
La inn revisjon 341.

Og nå den lettere måten å lage en gren på, som vi skulle fortalt deg om til å begynne med: svn copy kan operere direkte mot to URLer.

$ svn copy http://svn.example.com/repos/calc/trunk \
           http://svn.example.com/repos/calc/branches/my-calc-branch \
      -m "Lager en privat gren av /calc/trunk."

La inn revisjon 341.

Det er egentlig ingen forskjell på disse to metodene. Begge prosedyrene lager en ny katalog i revisjon 341, og den nye katalogen er en kopi av /calc/trunk. Dette er vist i Figur 4.3, “Depot med ny kopi”. Legg merke til at den andre metoden utfører en øyeblikkelig innlegging.[21] Det er en lettere prosedyre, fordi det ikke kreves at du må hente ut et stort speil av depotet. Faktisk trenger du med denne teknikken ikke en arbeidskopi i det hele tatt.

Figur 4.3. Depot med ny kopi

Depot med ny kopi


Arbeide med grenen

Nå som du har laget en gren av prosjektet, kan du hente ut en ny arbeidskopi for å starte bruken av den:

$ svn checkout http://svn.example.com/repos/calc/branches/my-calc-branch
A  my-calc-branch/Makefile
A  my-calc-branch/integer.c
A  my-calc-branch/button.c
Sjekket ut revisjon 341.

Det er ingenting spesielt med denne arbeidskopien; den avspeiler simpelthen bare en annen katalog i depotet. Men når du legger inn forandringer, vil ikke Sally se noen av dem når hun oppdaterer. Hennes arbeidskopi er fra /calc/trunk. (Pass på å lese “Bytte om en arbeidskopi” senere i dette kapittelet: Kommandoen svn switch er en alternativ måte å lage en arbeidskopi av en forgrening.)

La oss late som om en uke går, og de følgende innlegginger blir gjort:

  • Du gjør en forandring i /calc/branches/my-calc-branch/button.c som lager revisjon 342.

  • Du gjør en forandring i /calc/branches/my-calc-branch/integer.c som lager revisjon 343.

  • Sally gjør en forandring i /calc/trunk/integer.c som lager revisjon 344.

Det er nå to uavhengige utviklingslinjer, vist i Figur 4.4, “Forgreningen av ei fils historie”, som skjer med integer.c.

Figur 4.4. Forgreningen av ei fils historie

Forgreningen av ei fils historie


Ting blir interessante når du ser på historien til forandringene gjort i din kopi av integer.c:

$ pwd
/home/user/my-calc-branch

$ svn log --verbose integer.c
------------------------------------------------------------------------
r343 | bruker | 2002-11-07 15:27:56 -0600 (tor, 07 nov 2002) | 2 lines
Endrede filstier:
   M /calc/branches/my-calc-branch/integer.c

* integer.c:  frozzled the wazjub.

------------------------------------------------------------------------
r341 | bruker | 2002-11-03 15:27:56 -0600 (tor, 07 nov 2002) | 2 lines
Endrede filstier:
   A /calc/branches/my-calc-branch (fra /calc/trunk:340)

Lager en privat gren av /calc/trunk.

------------------------------------------------------------------------
r303 | sally | 2002-10-29 21:14:35 -0600 (tir, 29 okt 2002) | 2 lines
Endrede filstier:
   M /calc/trunk/integer.c

* integer.c:  Forandret en docstring.

------------------------------------------------------------------------
r98 | sally | 2002-02-22 15:35:29 -0600 (fre, 22 feb 2002) | 2 lines
Endrede filstier:
   M /calc/trunk/integer.c

* integer.c:  Legger til denne fila i prosjektet.

------------------------------------------------------------------------

Legg merke til at Subversion går gjennom historien av forgreningens integer.c hele veien tilbake gjennom tiden og krysser til og med punktet den ble kopiert. Opprettelsen av forgreningen vises som en hendelse i historien, fordi integer.c også ble kopiert når alt under /calc/trunk/ ble kopiert. Se nå hva som skjer når Sally kjører den samme kommandoen på hennes kopi av fila:

$ pwd
/home/sally/calc

$ svn log --verbose integer.c
------------------------------------------------------------------------
r344 | sally | 2002-11-07 15:27:56 -0600 (tor, 07 nov 2002) | 2 lines
Endrede filstier:
   M /calc/trunk/integer.c

* integer.c:  Ordnet en dunge med skrivefeil.

------------------------------------------------------------------------
r303 | sally | 2002-10-29 21:14:35 -0600 (tir, 29 okt 2002) | 2 lines
Endrede filstier:
   M /calc/trunk/integer.c

* integer.c:  Forandret en docstring.

------------------------------------------------------------------------
r98 | sally | 2002-02-22 15:35:29 -0600 (fre, 22 feb 2002) | 2 lines
Endrede filstier:
   M /calc/trunk/integer.c

* integer.c:  Legger til denne fila i prosjektet.

------------------------------------------------------------------------

Sally ser at hennes egen revisjon 344 forandrer seg, men ikke forandringen som du gjorde i revisjon 343. Hva Subversion angår, påvirket disse to innleggingene forskjellige filer på forskjellige plasseringer i depotet. Subversion viser imidlertid at de to filene deler en felles historie. Før grenkopieringen ble gjort i revisjon 341 var de den samme fila. Det er derfor både du og Sally ser forandringene gjort i revisjonene 303 og 98.

Nøkkelkonseptet bak forgreninger

Det er to viktige ting du bør huske fra denne seksjonen.

  1. Ulikt mange andre versjonskontrollsystemer eksisterer Subversions forgreninger som vanlige filsystemkataloger i depotet, ikke i en ekstra dimensjon. Disse katalogene inneholder bare noe ekstra historisk informasjon.

  2. Subversion har ikke noe internt begrep om en gren – bare kopier. Når du kopierer en katalog, er den resulterende nye katalogen bare en gren fordi du legger denne meningen til den. Du kan tenke på denne katalogen på en spesiell måte eller behandle den forskjellig, men for Subversion er den bare en vanlig katalog som tilfeldigvis er blitt opprettet ved kopiering.

Kopiere forandringer mellom forgreninger

Nå arbeider du og Sally på parallelle grener i prosjektet: Du arbeider på en privat gren, og Sally jobber i trunk, eller hovedlinjen av utviklingen.

For prosjekter som har et stort antall bidragsytere er det vanlig for de fleste personer å ha arbeidskopier av trunk. Når noen må gjøre forandringer som vil ta litt tid og som sannsynligvis kommer til å forstyrre trunk, er standard prosedyre å lage en privat gren og legge inn forandringer der til alt arbeidet er fullført.

Så, de gode nyhetene er at du og Sally ikke forstyrrer hverandre. De dårlige nyhetene er at det er veldig lett å drive for langt avgårde. Husk at ett av problemene med krabbe inn i et hull-strategien er at når du er ferdig med grenen din, vil det bli nesten umulig å flette inn dine forandringer tilbake til trunk uten et stort antall konflikter.

Istedenfor kan du og Sally fortsette med å dele forandringer mens du arbeider. Det er opp til deg å bestemme hvilke forandringer som er verdt å dele; Subversion gir deg muligheten til å selektivt kopiere forandringer mellom grener. Og når du er fullstendig ferdig med din gren, kan hele settet med grenforandringer bli kopiert tilbake til trunk.

Kopiere spesifikke forandringer

I den forrige seksjonen nevnte vi at både du og Sally gjorde forandringer til integer.c på forskjellige forgreninger. Hvis du ser på Sallys loggmelding for revisjon 344, kan du se at hun forandret noen stavefeil. Din kopi av den samme fila har uten tvil de samme skrivefeilene. Det er sannsynlig at dine fremtidige forandringer i denne fila vil påvirke de samme områdene som skrivefeilene ligger i, så du ligger an til å få potensielle konflikter når du en vakker dag fletter inn grenen din. Da er det bedre å motta Sallys forandringer nå, før du starter med å arbeide mye i det samme området.

Det er på tide å bruke kommandoen svn merge. Det skal vise seg at denne kommandoen er en veldig nær slektning av svn diff-kommandoen (som du leste om i Kapittel 2, Grunnleggende bruk). Begge kommandoene er i stand til å sammenligne to vilkårlige objekter i depotet og beskrive forskjellene. For eksempel kan du spørre svn diff om å vise deg den eksakte forandringen gjort av Sally i revisjon 344:

$ svn diff -r 343:344 http://svn.example.com/repos/calc/trunk

Index: integer.c
===================================================================
--- integer.c	(revisjon 343)
+++ integer.c	(revisjon 344)
@@ -147,7 +147,7 @@
     case 6:  sprintf(info->operating_system, "HPFS (OS/2 or NT)"); break;
     case 7:  sprintf(info->operating_system, "Macintosh"); break;
     case 8:  sprintf(info->operating_system, "Z-System"); break;
-    case 9:  sprintf(info->operating_system, "CPM"); break;
+    case 9:  sprintf(info->operating_system, "CP/M"); break;
     case 10:  sprintf(info->operating_system, "TOPS-20"); break;
     case 11:  sprintf(info->operating_system, "NTFS (Windows NT)"); break;
     case 12:  sprintf(info->operating_system, "QDOS"); break;
@@ -164,7 +164,7 @@
     low = (unsigned short) read_byte(gzfile);  /* read LSB */
     high = (unsigned short) read_byte(gzfile); /* read MSB */
     high = high << 8;  /* interpret MSB correctly */
-    total = low + high; /* add them togethe for correct total */
+    total = low + high; /* add them together for correct total */
 
     info->extra_header = (unsigned char *) my_malloc(total);
     fread(info->extra_header, total, 1, gzfile);
@@ -241,7 +241,7 @@
      Store the offset with ftell() ! */
 
   if ((info->data_offset = ftell(gzfile))== -1) {
-    printf("error: ftell() retturned -1.\n");
+    printf("error: ftell() returned -1.\n");
     exit(1);
   }
 
@@ -249,7 +249,7 @@
   printf("I believe start of compressed data is %u\n", info->data_offset);
   #endif
   
-  /* Set postion eight bytes from the end of the file. */
+  /* Set position eight bytes from the end of the file. */
 
   if (fseek(gzfile, -8, SEEK_END)) {
     printf("error: fseek() returned non-zero\n");

Kommandoen svn merge gjør omtrent nøyaktig det samme. Istedenfor å skrive forskjellene til terminalen din, blir de lagt direkte til arbeidskopien din som lokale modifikasjoner:

$ svn merge -r 343:344 http://svn.example.com/repos/calc/trunk
U  integer.c

$ svn status
M  integer.c

Utdataene fra svn merge viser at din kopi av integer.c ble patchet. Nå inneholder den Sallys forandring – forandringen er blitt kopiert fra trunk til din arbeidskopi på din private gren, og eksisterer nå som en lokal modifisering. På dette punktet er det opp til deg å se over den lokale modifiseringen og forsikre deg om at den fungerer korrekt.

I et annet scenario er det mulig at ting ikke gikk så bra og at integer.c gikk inn i en konflikttilstand. Du må kanskje løse konflikten ved hjelp av standard prosedyrer (se Kapittel 2, Grunnleggende bruk), eller hvis du finner ut at flettingen egentlig var en dårlig idé, kan du rett og slett gi opp og kjøre svn revert på den lokale forandringen.

Men hvis vi går ut i fra at du har sett over forandringen, kan du bruke svn commit til å legge inn forandringen på vanlig måte. På dette tidpunktet er forandringen blitt flettet inn i din depotgren. I versjonskontrollterminologi blir denne måten å kopiere forandringer mellom forgreninger på engelsk kalt porting. Det finnes ikke en standardisert betegnelse for dette på norsk, så vi bruker i denne boka uttrykket flette.

Når du legger inn de lokale modifiseringene, bør du forsikre deg om at loggmeldingen din nevner at du fletter en forandring fra en gren til en annen. For eksempel:

$ svn commit -m "integer.c: Flettet r344 (retting av skrivefeil) fra trunk."
Sending        integer.c
Sender fildata .
La inn revisjon 360.

Som du vil se i de neste seksjonene, er dette en veldig viktig god praksis å følge.

En liten advarsel: Selv om svn diff og svn merge er veldig like i konsept, har de i mange tilfeller forskjellig syntaks. Vær sikker på at du får lest om dem i Kapittel 9, Subversion Complete Reference for detaljer, eller spør svn help. For eksempel krever svn merge en arbeidskopi som et mål, det vil si en plass hvor den skal legge inn treforandringene. Hvis målet ikke er spesifisert, går den ut i fra at du prøver å utføre en av de følgende operasjonene:

  1. Du vil flette katalogforandringer inn i den gjeldende arbeidskatalogen.

  2. Du vil flette forandringene i en spesifikk fil inn i en fil med det samme navnet som eksisterer i den gjeldende arbeidskatalogen.

Hvis du fletter en katalog og ikke har spesifisert en målsti, går svn merge ut i fra det første tilfellet og prøver å legge inn forandringene til den gjeldende katalogen. Hvis du fletter ei fil, og denne fila (eller ei fil med det samme navnet) eksisterer i den gjeldende katalogen, går svn merge ut i fra det andre tilfellet og forsøker å legge inn forandringene til en lokal fil med det samme navnet.

Hvis du vil legge inn forandringer en annen plass, må du si fra om dette. Hvis du for eksempel sitter i foreldrekatalogen til arbeidskopien din, må du spesifisere målkatalogen som skal motta forandringene:

$ svn merge -r 343:344 http://svn.example.com/repos/calc/trunk my-calc-branch
U   my-calc-branch/integer.c

Nøkkelkonseptet bak fletting

Du har nå sett et eksempel på svn merge-kommandoen, og du skal få se flere. Hvis du er forvirret omkring hvordan fletting faktisk virker, er du ikke alene om det. Mange brukere (spesielt de som er nye innen versjonskontroll) er usikker på den riktige syntaksen til kommandoen, og når denne funksjonaliteten skal brukes. Men frykt ikke, denne kommandoen er faktisk mye enklere enn du tror! Det er en veldig enkel teknikk for å forstå nøyaktig hvordan svn merge virker.

Hovedkilden til forvirringen er navnet på kommandoen. Terminologien mergeflette – indikerer på en måte at grener blir kombinert sammen, eller at det er en form for mystisk sammenblanding av data som foregår. Det er ikke tilfellet. Et bedre navn for kommandoen hadde vært svn diff-and-applyfinn forskjell og legg denne til – fordi det er alt som skjer: To depottrær blir sammenlignet, og forskjellene blir lagt inn i arbeidskopien.

Kommandoen tar tre argumenter:

  1. Et innledende depottre (ofte kalt den venstre siden av sammenligningen),

  2. Et slutt-depottre (ofte kalt den høyre siden av sammenligningen),

  3. En arbeidskopi som skal motta forandringene som lokale forandringer (ofte kalt målet til flettingen).

Når disse tre argumentene er spesifisert, blir de to trærne sammenlignet og de forskjellene som programmet finner blir lagt inn i mål-arbeidskopien som lokale forandringer. Når kommandoen er ferdig, er ikke resultatet forskjellig fra om du hadde redigert filene for hånd, eller selv kjørt diverse svn add eller svn delete-kommandoer. Hvis du ikke liker resultatene, kan du enkelt kjøre svn revert for å omgjøre alle forandringene.

Syntaksen til svn merge lar deg spesifisere de tre nødvendige argumentene ganske fleksibelt. Her er noen eksempler:

$ svn merge http://svn.example.com/repos/branch1@150 \
            http://svn.example.com/repos/branch2@212 \
            min-arbeidskopi

$ svn merge -r 100:200 http://svn.example.com/repos/trunk min-arbeidskopi

$ svn merge -r 100:200 http://svn.example.com/repos/trunk

Den første syntaksen legger spesifikt opp alle tre argumentene, ved å nevne hvert tre på formen URL@REV og nevne arbeidskopimålet. Den andre syntaksen kan bli brukt som en snarvei for situasjoner når du sammenligner to forskjellige revisjoner på den samme URLen. Den siste syntaksen viser hvordan arbeidskopiargumentet er valgfritt; hvis det er utelatt, brukes den gjeldende katalogen.

Beste praksiser for fletting

Følge flettinger manuelt

Fletting av forandringer høres enkelt ut, men i praksis kan det bli en hodepine. Problemet er at hvis du gjentatte ganger fletter forandringer fra en gren til en annen, kan du ved en ulykke flette den samme forandringen to ganger. Når dette skjer, vil det noen ganger gå bra. Når ei fil blir patchet vil Subversion vanligvis oppdage at fila inneholder forandringen, og gjør ingenting. Men hvis den allerede eksisterende forandringen er blitt forandret på en eller annen måte, vil du få en konflikt.

Ideelt sett bør versjonskontrollsystemet forhindre forsøket på å legge inn doble forandringer til en gren. Det bør huske automatisk hvilke forandringer en gren allerede har mottatt, og bør være i stand til å liste dem ut for deg. Det bør bruke denne informasjonen til å hjelpe til med å automatisere flettinger så mye som mulig.

Dessverre er ikke Subversion et sånt system. I likhet med CVS lagrer ikke Subversion 1.0 noen informasjon om fletteoperasjoner. Når du legger inn lokale forandringer, har ikke depotet noen idé om hvorvidt disse forandringene kom fra en kjøring av svn merge, eller fra en redigering av filene for hånd.

Hva betyr dette for deg, brukeren? Det betyr at inntil den dagen Subversion får denne funksjonen, må du selv holde rede på fletteinformasjonen. Den beste plassen å gjøre dette er i selve loggmeldingen. Som demonstrert i det tidligere eksempelet, anbefales det at loggmeldingen din nevner et spesifikt revisjonsnummer (eller område av revisjoner) som blir flettet inn i grenen. Senere kan du kjøre svn log for å se over hvilke forandringer forgreningen allerede inneholder. Dette vil la deg varsomt konstruere en etterfølgende svn merge-kommando som ikke vil bli overflødig i forhold til tidligere flettede forandringer.

I den neste seksjonen vil vi vise noen eksempler på denne teknikken i praksis.

Vise flettinger på forhånd

Fordi fletting bare resulterer i lokale modifikasjoner, er det vanligvis ikke noen høyrisikooperasjon. Hvis flettingen går galt første gangen, kan du kjøre svn revert på forandringene og prøve igjen.

Men det er derimot mulig at arbeidskopien din allerede inneholder lokale forandringer. Forandringene lagt inn av en fletting vil bli blandet med de du har fra før, og det å kjøre svn revert er ikke lenger et alternativ. De to settene med forandringer kan bli umulig å separere.

I tilfeller som dette vil det være greit å kunne forutsi eller undersøke forandringer før de skjer. En enkel måte å gjøre det på er å kjøre svn diff med de samme argumentene som du planlegger å gi til svn merge, som vi allerede har vist i det første eksemplet vårt med fletting. En annen metode for forhåndsvisning er å angi --dry-run-valget til flettekommandoen:

$ svn merge --dry-run -r 343:344 http://svn.example.com/repos/calc/trunk
U  integer.c

$ svn status
# ingenting blir skrevet ut, arbeidskopien er fortsatt uforandret.

--dry-run-valget gjør egentlig ingen forandringer i arbeidskopien. Det viser bare statuskoder som ville blitt skrevet ut under en virkelig fletting. Det er nyttig for å få en høynivå-oversikt over den potensielle flettingen for de gangene der kjøring av svn diff gir alt for mange detaljer.

Konflikter under fletting

Akkurat som svn update-kommandoen, legger svn merge inn forandringer i arbeidskopien din. Og derfor er den også i stand til å lage konflikter. Konfliktene produsert av svn merge er imidlertid noen ganger forskjellige, og denne seksjonen forklarer disse forskjellene.

Til å begynne med, tenk deg at arbeidskopien din ikke inneholder noen lokale redigeringer. Når du svn update-er til en spesiell revisjon, vil forandringene sendt fra serveren alltid bli lagt inn på en renslig måte i arbeidskopien. Serveren produsererer deltaet ved å sammenligne to trær: Et virtuelt øyeblikksbilde av arbeidskopien din, og revisjonstreet du er er interessert i. Fordi den venstre siden av sammenligningen er nøyaktig lik det du allerede har, er deltaet garantert å korrekt konvertere arbeidskopien din til treet som er på høyre side.

Men svn merge har ingen slike garantier og kan være mye mer kaotisk: Brukeren kan be serveren om å sammenligne alle mulige trær, til og med trær som ikke er relatert til arbeidskopien! Dette betyr at det er et stort potensiale for menneskelige feil. Brukere vil noen ganger sammenligne to gale trær, og dermed lage et delta som ikke kan legges inn på en ren måte. svn merge vil gjøre sitt beste for å legge inn så mye av deltaet som mulig, men noen deler kan være umulige. Akkurat som patch-kommandoen i Unix noen ganger klager over failed hunks, vil svn merge klage over skipped targets:

$ svn merge -r 1288:1351 http://svn.example.com/repos/branch
U  foo.c
U  bar.c
Hoppet over savnet mål: «baz.c»
U  glub.c
C  glorb.h

$

I det forrige eksempelet kan tilfellet være at baz.c eksisterer både i øyeblikksbildet av grenen som sammenlignes, og det resulterende deltaet vil forandre filens innhold, men fila eksisterer ikke i arbeidskopien. Hva som enn er tilfelle, betyr skipped-meldingen at brukeren mest sannsynlig sammenligner to gale trær; de er det klassiske tegnet på en feil gjort av brukeren. Når dette skjer er det lett å rekursivt omgjøre alle forandringene gjort under flettingen (svn revert --recursive), slette eventuelle uversjonerte filer eller kataloger som ligger igjen etter tilbakestillingen, og kjøre svn merge med forskjellige argumenter.

Legg også merke til at det forrige eksempelet viser en konflikt som skjer i glorb.h. Vi har allerede fastslått at arbeidskopien ikke har noen lokale forandringer; hvordan er det da mulig at en lokal konflikt kan oppstå? Igjen, fordi brukeren kan bruke svn merge for å definere og legge til enhver gammel delta til arbeidskopien, kan denne deltaen inneholde tekstmessige forandringer som ikke kan legges helt uproblematisk inn i en arbeidsfil, selv om denne fila ikke har noen lokale forandringer.

En annen liten forskjell mellom svn update og svn merge er navnene på fulltekst-filene som blir opprettet når en konflikt oppstår. I “Løse konflikter (Flette inn andres forandringer)” så vi at en oppdatering produserer filene filnavn.mine, filnavn.rGAMMELREV og filnavn.rNYREV. Men når svn merge produserer en konflikt, oppretter den tre filer kalt filnavn.working, filnavn.left og filename.right. I dette tilfellet beskriver terminologien left og right hvilken side fila kom fra. I alle fall, disse forskjellige navnene vil hjelpe deg å skille mellom filer som er opprettet som følge av en oppdatering versus filer som er opprettet som resultat av en fletting.

Legge merke til eller ignorere slektskap

Når du snakker med en Subversionutvikler kan det hende du hører referanser til begrepet slektskapancestry. Dette ordet blir brukt til å beskrive forholdet mellom to objekter i et depot: Hvis de er relaterte til hverandre, vil det ene objektet være en stamfar til det andre.

For eksempel, tenk deg at du legger inn revisjon 100, som inkluderer en forandring i ei fil kalt foo.c. Da er foo.c@99 en stamfar til foo.c@100. På den annen side, tenk at du legger inn en sletting av foo.c i revisjon 101, og deretter legger til en ny fil med det samme navnet i revisjon 102. I dette tilfellet kan det se ut som om foo.c@99 og foo.c@102 er relaterte (de har den samme filstien), men de er faktisk totalt forskjellige objekter i depotet. De deler ingen historie eller slektskap.

Grunnen til at vi tar dette opp er for å fremheve en viktig forskjell mellom svn diff og svn merge. Den første kommandoen ignorerer slektskap, mens den sistnevnte kommandoen er ganske følsom for det. Hvis du for eksempel ber svn diff om å sammenligne revisjon 99 og 102 av foo.c, vil du se linjebaserte forskjeller; diff-kommandoen sammenligner blindt to stier. Men hvis du ber svn merge om å sammenligne de samme to objektene, vil den oppdage at de er urelaterte og først prøve å slette den gamle fila og deretter legge til den nye fila. Utdataene fra programmet vil indikere en sletting etterfulgt av en tillegging:

D  foo.c
A  foo.c

De fleste flettinger involverer sammenligning av trær som er slektsmessig relatert til hverandre, og derfor har svn merge denne oppførselen som standard. Men nå og da vil du kanskje bruke merge-kommandoen til å sammenligne to urelaterte trær. For eksempel har du kanskje importert to kildekodetrær som representerer forskjellige utgivelser av et programprosjekt (se “Leverandørgrener”). Hvis du ber svn merge om å sammenligne de to trærne, vil du se at hele det første treet blir slettet, fulgt av en tillegging av hele det andre treet!

I disse situasjonene vil du at svn merge bare gjør en stibasert sammenligning og ignorerer enhver relasjon mellom filer og kataloger. Legg til valget --ignore-ancestry til flettekommandoen, og den vil oppføre seg akkurat som svn diff. (Og på motsatt måte vil --notice-ancestry-valget få svn diff til å oppføre seg som merge-kommandoen.

Vanlige bruksområder

Det er mange forskjellige bruksområder for forgreninger og svn merge, og denne seksjonen beskriver de vanligste som du sannsynligvis vil komme over.

Flette en hel gren til en annen

For å fullføre eksempelet vårt vil vi nå reise fram i tiden. Tenk deg at flere dager har gått, og mange forandringer har skjedd både i trunk og på den private grenen din. Tenk deg så at du er ferdig med arbeidet på den private grenen; funksjonaliteten eller feilrettingen er endelig fullført, og nå vil du flette alle forandringene fra grenen din til trunk så andre kan få glede av dem.

Så hvordan bruker vi svn merge i dette tilfellet? Husk at denne kommandoen sammenligner to trær og legger forandringene inn i en arbeidskopi. For å motta forandringene må du derfor ha en arbeidskopi av trunk. Vi går ut i fra at du enten har den originale liggende (helt oppdatert), eller at du nylig hentet ut en fersk arbeidskopi av /calc/trunk.

Men hvilke to trær skal sammenlignes? Ved første øyekast ser det innlysende ut: Bare sammenlign seneste treet fra trunk med det seneste treet fra forgreningen. Men pass på – denne antakelsen er feil, noe som mange nye brukere har brent seg på. Siden svn merge opererer på samme måte som svn diff, vil en sammenligning mellom trærne i nyeste trunk og gren ikke bare vise forandringene som du har gjort på grenen. En slik sammenligning viser alt for mange forandringer: Den vil ikke bare vise tilleggingene av dine forandringer på grenen, men også fjerningen av forandringer i trunk som aldri skjedde på din gren.

For å bare vise forandringene som skjedde på din gren, må du sammenligne tilstanden ved starten av grenen din i forhold til dens endelige tilstand. Ved å bruke svn log på grenen kan du se at den ble opprettet i revisjon 341. Og den endelige tilstanden får du ved å bruke HEAD-revisjonen. Dette betyr at du vil sammenligne revisjonene 341 og HEAD i forgreningskatalogen og legge disse forskjellene inn i en arbeidskopi av trunk.

[Tips]Tips

En fin måte å finne revisjonen en gren ble opprettet i (basen av forgreningen) er å bruke valget --stop-on-copy til svn log. Delkommandoen svn log vil normalt vise hver eneste forandring gjort på grenen, inkludert å gå forbi kopieringen som opprettet grenen. Så vanligvis vil du også se historien fra trunk. --stop-on-copy-valget vil stoppe loggutlistingen med en gang svn log finner ut at målet ble kopiert eller skiftet navn.

Så hvis vi går videre i eksempelet,

$ svn log --verbose --stop-on-copy \
          http://svn.example.com/repos/calc/branches/my-calc-branch
…
------------------------------------------------------------------------
r341 | bruker | 2002-11-03 15:27:56 -0600 (tor, 07 nov 2002) | 2 lines
Endrede filstier:
   A /calc/branches/my-calc-branch (fra /calc/trunk:340)

$

Som forventet er den siste revisjonen skrevet ut av denne kommandoen den revisjonen der my-calc-branch ble opprettet ved kopiering.

Her er den siste fletteprosedyren, og deretter:

$ cd calc/trunk
$ svn update
På revisjon 405.

$ svn merge -r 341:405 http://svn.example.com/repos/calc/branches/my-calc-branch
U   integer.c
U   button.c
U   Makefile

$ svn status
M   integer.c
M   button.c
M   Makefile

# … Undersøk forskjellene, kompiler, test osv …

$ svn commit -m "Flettet forandringer mellom r341:405 fra my-calc-branch til trunk."
Sender        integer.c
Sender        button.c
Sender        Makefile
Sender fildata ...
La inn revisjon 406.

Igjen, legg merke til at loggmeldingen veldig spesifikt nevner området av forandringer som ble flettet inn på trunk. Husk alltid å gjøre dette, fordi det er vital informasjon som du vil trenge senere.

For eksempel, tenk at du bestemmer deg for å fortsette arbeidet på grenen en uke til, for å fullføre feilrettingen eller en forbedring av den originale funksjonaliteten. Depotets HEAD-revisjon er nå 480, og du er klar til å utføre en ny fletting fra den private grenen din til trunk. Men som diskutert i “Beste praksiser for fletting” vil du ikke flette forandringene du allerede har flettet før; du vil bare flette alt nytt på grenen siden forrige gang du flettet. Trikset er å finne ut hva som er nytt.

Første skritt er å kjøre svn log på trunk og se etter en loggmelding fra forrige gang du flettet fra grenen:

$ cd calc/trunk
$ svn log
…
------------------------------------------------------------------------
r406 | bruker | 2004-02-08 11:17:26 -0600 (søn, 08 feb 2004) | 1 line

Flettet forandringer mellom r341:405 fra my-calc-branch til trunk.
------------------------------------------------------------------------
…

Aha! Siden alle grenforandringene som skjedde mellom revisjonene 341 og 405 ble flettet til trunk som revisjon 406, vet du nå at du bare vil flette grenforandringene etter dette – ved å sammenligne revisjonene 406 og HEAD.

$ cd calc/trunk
$ svn update
På revisjon 480.

# Vi ser at HEAD er 480 for øyeblikket, så vi bruker den for å utføre 
# flettingen:

$ svn merge -r 406:480 http://svn.example.com/repos/calc/branches/my-calc-branch
U   integer.c
U   button.c
U   Makefile

$ svn commit -m "Flettet forandringer mellom r406:480 fra my-calc-branch til trunk."
Sender        integer.c
Sender        button.c
Sender        Makefile
Sender fildata ...
La inn revisjon 481.

Nå inneholder trunk alle forandringene som ble gjort i den andre omgangen på grenen. På dette punktet kan du enten slette grenen (dette vil vi komme tilbake til) eller fortsette arbeidet på grenen og repetere denne prosedyren for etterfølgende flettinger.

Omgjøre forandringer

En annen vanlig bruksmåte for svn merge er å omgjøre en forandring som allerede er blitt lagt inn. Tenk deg at du jobber glad og fornøyd på en arbeidskopi av /calc/trunk, og plutselig finner ut at forandringen du gjorde langt tilbake i revisjon 303, som forandret integer.c, er helt feil. Den skulle aldri vært lagt inn. Du kan bruke svn merge for å angre forandringen i arbeidskopien din, og deretter legge inn de lokale forandringene til depotet. Alt du trenger å gjøre er å spesifisere en omvendt forskjell:

$ svn merge -r 303:302 http://svn.example.com/repos/calc/trunk
U  integer.c

$ svn status
M  integer.c

$ svn diff
…
# Sjekk at forandringen er fjernet
…

$ svn commit -m "Fjernet forandringen som ble lagt inn i r303."
Sender        integer.c
Sender fildata .
La inn revisjon 350.

En måte å tenke på en depotrevisjon er som en spesifikk gruppe av forandringer (noen versjonskontrollsystemer kaller disse forandringssettchangesets). Ved å bruke -r-valget kan du be svn merge om å legge inn et forandringssett, eller et helt område av forandringssett, til arbeidskopien din. I vårt tilfelle med å omgjøre en forandring ber vi svn merge om å legge inn forandringssett nummer 303 baklengs inn i arbeidskopien vår.

Husk at det å rulle tilbake en forandring som dette er akkurat likt enhver annen svn merge-operasjon, så du bør bruke svn status og svn diff for å forsikre deg om at arbeidet ditt er i den tilstanden du vil det skal være i, og deretter bruke svn commit for å sende den endelige versjonen til depotet. Etter innleggingen er dette spesielle forandringssettet ikke lenger representert i HEAD-revisjonen.

Og så tenker du kanskje: Nåh, dette omgjorde vel egentlig ikke innleggingen? Forandringen eksisterer fortsatt i revisjon 303. Hvis noen henter ut en versjon av calc-prosjektet mellom revisjonene 303 og 349, vil de se den gale forandringen, ikke sant?

Ja, det stemmer. Når vi snakker om å fjerne en forandring, snakker vi egentlig om å fjerne den fra HEAD. Den originale forandringen eksisterer fortsatt i depotets historie. I de fleste situasjoner er dette greit nok. De fleste er bare interessert i å følge HEAD av et prosjekt uansett. Det er imidlertid spesielle tilfeller der du virkelig vil ødelegge alle spor etter innleggingen, kanskje la noen inn et konfidensielt dokument ved en ulykke. Dette er ikke så lett, viser det seg, fordi Subversion ble spesielt designet for å aldri miste informasjon. Revisjoner er uforanderlige trær som bygger på hverandre. Det å fjerne en revisjon fra historien vil forårsake en dominoeffekt som vil føre til kaos i alle etterfølgende revisjoner og muligens gjøre alle arbeidskopiene ubrukelige.[23]

Hente tilbake slettede elementer

Det som er fint med versjonskontrollsystemer er at informasjon aldri går tapt. Selv om du sletter ei fil eller en katalog, kan den være borte fra HEAD-revisjonen, men objektet eksisterer fortsatt i tidligere revisjoner. Et av de vanligste spørsmålene nye brukere spør om, er: Hvordan får jeg den gamle fila eller katalogen min tilbake?.

Første skritt er å definere nøyaktig hvilket element du skal prøve å hente tilbake. Her er en nyttig metafor: Du kan tenke på hvert objekt i depotet som om det eksisterer i et slags todimensjonalt koordinatsystem. Det første koordinatet er et spesifikt revisjonstre, og det andre koordinatet er en sti inne i dette treet. Så hver versjon av fila eller katalogen din kan bli definert som et spesifikt koordinatpar.

Subversion har ingen Attic-katalog som CVS har,[24] så du må bruke svn log for å finne det eksakte koordinatparet som du vil hente tilbake. En god strategi er å kjøre svn log --verbose i en katalog som inneholdt det slettede elementet ditt. Valget --verbose viser en liste over alle forandrede elementer i hver revisjon; alt du trenger å gjøre er å finne revisjonen der du slettet fila eller katalogen. Du kan gjøre dette visuelt, eller ved å bruke et annet verktøy for å undersøke utdataene fra loggen (ved hjelp av grep, eller kanskje ved hjelp av et inkrementelt søk i en tekstbehandler).

…
------------------------------------------------------------------------
r808 | joe | 2003-12-26 14:29:40 -0600 (fre, 26 des 2003) | 3 lines
Endrede filstier:
   D /calc/trunk/real.c
   M /calc/trunk/integer.c

La inn Fast Fourier transform-funksjoner i integer.c .
Slettet real.c fordi koden nå ligger i double.c .
…

I eksempelet går vi ut i fra at du ser etter en slettet fil kalt real.c. Ved å se gjennom loggene for en foreldrekatalog, har du funnet ut at denne fila ble slettet i revisjon 808. Derfor er den siste versjonen av fila der den fortsatt eksisterte i revisjonen like før dette. Konklusjon: Du vil hente tilbake stien /calc/trunk/real.c fra revisjon 807.

Dette var den vanskelige delen – etterforskningen. Nå som du vet hva du vil hente tilbake, har du to forskjellige valg.

En måte er å bruke svn merge for å legge inn revisjon 808 i revers. (Vi har allerede gått gjennom hvordan vi omgjør forandringer, se “Omgjøre forandringer”.) Dette vil ha samme effekten som å legge til real.c en gang til som en lokal modifisering. Fila vil bli klargjort for tillegging, og etter en innlegging med svn commit vil fila eksistere i HEAD igjen.

Men i dette spesielle eksempelet er det kanskje ikke den beste strategien. Å legge inn revisjon 808 i revers vil ikke bare klargjøre real.c for tillegging, men loggmeldingen indikerer at det vil også bli omgjort forandringer i integer.c, noe som du ikke ønsker. Du kan selvfølgelig bakoverflette revisjon 808 og deretter kjøre svn revert på de lokale forandringene i integer.c, men denne teknikken skalerer ikke alltid like bra. Hva hvis det var 90 filer som forandret seg i revisjon 808?

En annen og mer målrettet strategi er å ikke bruke svn merge i det hele tatt, men derimot svn copy. Kopier ganske enkelt den eksakte revisjonens og stiens koordinatpar fra depotet til arbeidskopien din:

$ svn copy --revision 807 \
           http://svn.example.com/repos/calc/trunk/real.c ./real.c

$ svn status
A  +   real.c

$ svn commit -m "Hentet tilbake real.c from revisjon 807, /calc/trunk/real.c ."
Legger til         real.c
Sender fildata .
La inn revisjon 1390.

Plusstegnet som vises i statusoversikten indikerer at elementet ikke bare er klargjort for tillegging, men er klargjort for tillegging med historie. Subversion husker hvor det ble kopiert fra. I framtiden vil kjøring av svn log på denne fila gå tilbake forbi gjenoppstandelsen av fila og gjennom hele historien den hadde før revisjon 807. Med andre ord, denne nye real.c er ikke egentlig ny; den er en direkte etterkommer av den originale, slettede fila.

Selv om eksempelet vårt viser at vi henter tilbake ei fil, legg merke til at disse samme teknikkene virker like godt når det gjelder å hente tilbake slettede kataloger.

Vanlige forgreningsmønstre

Versjonskontroll blir vanligvis brukt til programutvikling, så her er en rask kikk på to av de vanligste forgrenings-/flettemønstere som blir brukt av programmeringsteam. Hvis du ikke bruker Subversion til programutvikling, kan du hoppe over denne seksjonen. Hvis du er en programutvikler som bruker versjonskontroll for første gang, følg nøye med, da disse fremgangsmåtene blant erfarne brukere ofte er ansett som de beste metodene. Disse prosessene er ikke spesifikke for Subversion; de kan brukes med ethvert versjonskontrollsystem. Men det kan hjelpe å se dem beskrevet i Subversionterminologi.

Utgivelsesgrener

Programvare har vanligvis denne livssyklusen: Kode, teste, offentliggjøre, repetere. Det er to problemer med denne prosessen. For det første trenger utviklere å skrive ny funksjonalitet mens kvalitetssikringsteam tester versjoner som er ment å skulle være stabil. Nytt arbeide kan ikke stoppe opp mens programvaren blir testet ut. For det andre, teamet må nesten alltid støtte eldre, utgitte versjoner av programvaren; hvis en feil blir oppdaget i den seneste koden, eksisterer den sannsynligvis også i utgitte versjoner, og kundene vil ønske å få denne feilen rettet uten å måtte vente på en ny stor utgivelse.

Og det er her versjonskontroll kan hjelpe. Den vanlige prosedyren ser ut som dette:

  • Utviklerne legger inn alt nytt arbeid til trunk. Daglige forandringer legges inn på /trunk: Ny funksjonalitet, retting av feil og så videre.

  • trunk blir kopiert til en utgivelses-gren. Når teamet synes programvaren er klar for utgivelse (for eksempel en 1.0-versjon), kan /trunk bli kopiert til /branches/1.0.

  • Teamene fortsetter å arbeide parallelt. Et team begynner inngående testing av utgivelsesgrenen, mens et annet team fortsetter på nytt arbeid (for eksempel på det som skal bli versjon 2.0) i /trunk. Hvis det blir funnet feil på et av stedene, blir nødvendige reparasjoner flettet fram og tilbake. Men på et punkt stopper også denne prosessen. Grenen er frosset for avsluttende testing rett før en utgivelse.

  • Grenen blir merket og utgitt. Når testingen er ferdig, blir /branches/1.0 kopiert til /tags/1.0.0 som et referanseøyeblikksbilde. De merkede filene pakkes og sendes ut til kundene.

  • Grenen blir vedlikeholdt over tid. Mens arbeidet fortsetter på /trunk for versjon 2.0, blir fortsatt feil som blir funnet på /trunk flettet derfra til /branches/1.0. Når et tilstrekkelig antall feil er blitt rettet, kan vedlikeholderne bestemme seg for å lage en 1.0.1-utgivelse: /branches/1.0 blir kopiert til /tags/1.0.1, og de merkede filene blir pakket og utgitt.

Hele denne prosessen repeteres mens programvaren modnes: Når arbeidet for 2.0 er komplett, blir en ny utgivelsesgren for 2.0 opprettet, testet, merket og eventuelt utgitt. Etter noen år ender depotet opp med et antall grener i vedlikeholdsmodus, og et antall merker som representerer ferdige, utgitte versjoner.

Funksjonalitetsgrener

En funksjonalitetsgren er den typen gren som har vært det dominerende eksempelet i dette kapittelet, den typen du har arbeidet på mens Sally fortsetter å arbeide på /trunk. Det er en midlertidig gren som er opprettet for å arbeide på en kompleks forandring uten å la det gå ut over stabiliteten til /trunk. I motsetning til utgivelsesgrener (som kanskje må bli støttet for alltid) blir funksjonalitetsgrener født, brukt en stund, flettet tilbake til trunk, og deretter til sist slettet. De har en begrenset nyttighetsperiode.

Igjen, prosjekt-policy varierer veldig når det gjelder nøyaktig når det passer å opprette en funksjonalitetsgren. Noen prosjekter bruker ikke funksjonalitetsgrener i det hele tatt; innlegginger til /trunk er tilgjengelig for alle. Fordelen med dette systemet er at det er enkelt – ingen trenger å lære om forgrening eller fletting. Ulempen er at koden i trunk ofte er ustabil eller ubrukelig. Andre prosjekter bruker forgreninger til det ekstreme; ingen forandringer blir noen gang lagt direkte inn på trunk. Til og med de enkleste forandringer blir laget på en gren med kort levetid, nøye kontrollert og deretter flettet til trunk. Så blir grenen slettet. Dette systemet garanterer en eksepsjonelt stabil og brukbar trunk til enhver tid, men med en pris i form av mer arbeid i prosessen.

Noen prosjekter velger en rute midt i mellom. De insisterer på at /trunk skal kunne kompilere og passere systemsjekker til enhver tid. En funksjonalitetsgren er bare nødvendig når en forandring krever et stort antall innlegginger som kan gå ut over stabiliteten. En god tommelfingerregel er å stille dette spørsmålet: Hvis utvikleren jobbet i flere dager i isolasjon og deretter la inn hele den store forandringen på en gang (så /trunk aldri ble ustabil), ville den blitt for stor for gjennomlesing? Hvis svaret til det er ja, bør forandringen bli utviklet på en funksjonalitetsgren. Etter hvert som utvikleren legger inn økende forandringer til grenen, kan de bli sett over av kolleger.

Til sist har vi spørsmålet om hvordan man best kan holde en fremtidig gren i synk med trunk etterhvert som arbeidet går fram. Som vi nevnte tidligere, er det en stor risiko å arbeide på en gren i flere uker eller måneder; forandringer på trunk kommer strømmende inn, til punktet der de to utviklingslinjene er såpass forskjellige at det kan bli et mareritt å flette grenen tilbake til trunk.

Denne situasjonen unngås best ved å jevnlig flette trunk-forandringer inn på grenen. Lag en regel: En gang i uken fletter du forrige ukes forandringer til grenen. Vær nøye når du gjør dette; flettingen må sjekkes for å unngå problemet med gjentatte flettinger (som beskrevet i “Følge flettinger manuelt”). Du må skrive nøyaktige loggmeldinger med detaljer om hvilket revisjonsområde som allerede er blitt flettet (som demonstrert i “Flette en hel gren til en annen”). Det kan høres skremmende ut, men er faktisk ganske enkelt å gjøre.

Etterhvert er du klar til å flette den synkroniserte funksjonalitetsgrenen tilbake til trunk. For å gjøre dette, start med å gjøre en avsluttende fletting av de siste trunk-forandringene til grenen. Når det er gjort, vil de siste versjonene av grenen og trunk være absolutt like, bortsett fra forandringene på grenen din. Så i dette spesielle tilfellet, vil du flette ved å sammenligne grenen med trunk:

$ cd trunk-i-arbeidskopien

$ svn update
På revisjon 1910.

$ svn merge http://svn.example.com/repos/calc/trunk@1910 \
            http://svn.example.com/repos/calc/branches/mybranch@1910
U  real.c
U  integer.c
A  nykatalog
A  nykatalog/nyfil
…

Ved å sammenligne HEAD-revisjonen for trunk med HEAD-revisjonen på grenen, kan du definere ett delta som beskriver kun de forandringene som du gjorde til grenen; begge utviklingsgrener inneholder allerede forandringene fra trunk.

En annen måte å tenke på dette mønsteret er at den ukentlige synkroniseringen er det samme som å kjøre svn update i en arbeidskopi, mens det siste trinnet med fletting er det samme som å kjøre svn commit fra en arbeidskopi. Når alt kommer til alt, er jo en arbeidskopi en grunn, privat gren. Det er en gren som bare er i stand til å lagre én forandring om gangen.

Bytte om en arbeidskopi

Kommandoen svn switch flytter en eksisterende arbeidskopi til en annen gren. Selv om denne kommandoen strengt tatt ikke er nødvendig for å arbeide med forgreninger, gir den en fin snarvei for brukere, I det tidligere eksempelet vårt, etter at du opprettet en privat gren, hentet du ut en fersk arbeidskopi av den nye katalogen i depotet. Istedenfor kan du rett og slett be Subversion om å forandre arbeidskopien din av /calc/trunk til å avspeile plasseringen til den nye grenen:

$ cd calc

$ svn info | grep Nettadresse
Nettadresse: http://svn.example.com/repos/calc/trunk

$ svn switch http://svn.example.com/repos/calc/branches/my-calc-branch
U   integer.c
U   button.c
U   Makefile
Oppdatert til revisjon 341.

$ svn info | grep Nettadresse
Nettadresse: http://svn.example.com/repos/calc/branches/my-calc-branch

Etter å ha byttet om til grenen, er ikke arbeidskopien mer forskjellig enn om du hadde gjort en fersk uthenting av katalogen. Og det er vanligvis mer praktisk å bruke denne kommandoen, fordi forskjellene mellom grener ofte er ganske små. Serveren sender bare et minimalt sett med forandringer nødvendig for å avspeile grenkatalogen.

svn switch-kommandoen tar også et --revision (-r)-valg, så du trenger ikke alltid å flytte arbeidskopien din til tuppen av grenen.

Selvfølgelig, de fleste prosjekter er mer kompliserte enn calc-eksempelet vårt, og inneholder flere underkataloger. Subversionbrukere følger ofte en spesiell algoritme ved bruk av grener:

  1. Kopier hele trunk fra prosjektet til en ny grenkatalog.

  2. Bytt bare om en del av trunk-arbeidskopien for å avspeile forgreningen.

Med andre ord, hvis en bruker vet at grenarbeidet kun trenger å skje i en spesiell underkatalog, bruker de svn switch for å flytte bare denne underkatalogen til grenen. (Og noen ganger vil brukere bare bytte om en enkelt arbeidsfil til grenen!) På denne måten kan de fortsette å motta normale oppdateringer fra trunk til mesteparten av arbeidskopien deres, men de ombyttede delene vil forbli immune (unntatt hvis noen legger inn en forandring til denne grenen). Denne funksjonaliteten legger til en hel ny dimensjon til konseptet med en blandet arbeidskopi – ikke bare kan arbeidskopier inneholde en blanding av av arbeidsrevisjoner, men også en blanding av depotbeliggenheter.

Hvis arbeidskopien din inneholder et antall ombyttede katalogtrær fra forskjellige depotplasseringer, fortsetter den å virke som normalt. Når du oppdaterer, vil du motta patcher til hvert undertre der det er nødvendig. Når du legger inn forandringer, vil dine lokale forandringer fortsatt bli lagt inn som en enkel, atomisk forandring til depotet.

Legg merke til at mens det er greit for arbeidskopien din å avspeile en blanding av depotplasseringer, må alle disse plasseringene være innenfor det samme depotet. Subversiondepoter er foreløpig ikke i stand til å kommunisere med hverandre; det er en funksjonalitet som er planlagt etter Subversion 1.0.[25]

Fordi svn switch egentlig er en variant av svn update oppfører den seg på samme måte; alle lokale modifiseringer i arbeidskopen blir tatt vare på når nye data ankommer fra depotet. Dette lar deg gjøre alle mulige lure triks.

For eksempel, tenk deg at du har en arbeidskopi av /calc/trunk og gjør et antall forandringer i den. Så finner du plutselig ut at du skulle gjøre disse forandringene på en gren istedenfor. Ikke noe problem! Når du bruker svn switch for å flytte arbeidskopien til grenen, vil de lokale forandringene bli værende. Du kan deretter teste og legge dem inn på grenen.

Merker (tags)

Et annet vanlig versjonskontrollkonsept er et merketag. Et merke er bare et øyeblikksbilde av et prosjekt på et spesiell tidspunkt. I Subversion ser denne idéen ut til å være overalt. Hver depotrevisjon er akkurat det – et øyeblikksbilde av filsystemet etter hver innlegging.

Men folk vil ofte ønske å gi mer menneskevennlige navn på merker, som versjon-1.0. Og de ønsker å ta øyeblikksbilder av mindre underkataloger i filsystemet. Når alt kommer til alt, er det ikke så lett å huske at versjon-1.0 av et programprosjekt er en spesiell underkatalog av revisjon 4822.

Lage et enkelt merke

Atter en gang kommer svn copy og redder situasjonen. Hvis du vil lage et øyeblikksbilde av /calc/trunk nøyaktig som den ser ut i HEAD-revisjonen, kan du lage en kopi av den:

$ svn copy http://svn.example.com/repos/calc/trunk \
           http://svn.example.com/repos/calc/tags/versjon-1.0 \
      -m "Merker 1.0-versjonen av «calc»-prosjektet."

La inn revisjon 351.

Dette eksempelet forutsetter at en /calc/tags-katalog allerede eksisterer. (Hvis den ikke gjør det, se svn mkdir.) Etter at kopieringen er fullført, vil den nye versjon-1.0-katalogen for alltid være et øyeblikksbilde av hvordan prosjektet så ut i HEAD-revisjonen på den tiden du lagde kopien. Selvfølgelig vil du være mer presis angående hvilken revisjon du kopierer, i tilfelle noen andre kan ha lagt inn forandringer til prosjektet mens du ikke så det. Så hvis du vet at revisjon 350 av /calc/trunk er nøyaktig det øeblikksbildet du ønsker, kan du spesifisere dette ved å angi -r 350 til svn copy-kommandoen.

Men vent nå litt: Er ikke denne prosedyren med opprettelse av merker den samme prosedyren som vi brukte da vi lagde en gren? Ja, faktisk er det det. I Subversion er det ingen forskjell på et merke og en gren. Begge er bare vanlige kataloger som er opprettet ved kopiering. Akkurat som med grener er den eneste grunnen til at en kopiert katalog er et merke fordi mennesker har bestemt seg for å behandle den på denne måten: Så lenge ingen legger inn forandringer i katalogen, forblir den for alltid et øyeblikksbilde. Hvis noen begynner å legge inn forandringer i den, blir den en gren.

Hvis du administrerer et depot, er det to fremgangsmåter du kan bruke for å holde rede på merker. Den første fremgangsmåten er ikke rør: Som en del av reglene for prosjektet, bestem hvor i depotet merkene skal ligge, og gjør det klart for alle brukere hvordan de skal behandle kataloger som de kopierer inn dit. (Det vil si, vær sikker på at de vet at nye innlegginger ikke skal skje der.) Den andre fremgangsmåten er mer paranoid: Du kan bruke et av aksesskontrollskriptene som følger med Subversion til å forhindre noen fra å gjøre noe annet enn å opprette nye kopier i merkeområdet (se Kapittel 6, Serverkonfigurasjon). Den paranoide ruten er imidlertid vanligvis ikke nødvendig. Hvis en bruker legger inn en forandring i en merkekatalog, kan du enkelt og greit omgjøre forandringen som nevnt i den forrige seksjonen. Dette er versjonskontroll, tross alt.

Lage et komplekst merke

Noen ganger vil du at øyeblikksbildet skal være mer komplisert enn en enkel katalog med en enkelt revisjon.

For eksempel, tenk deg at prosjektet ditt er mye større enn calc-eksempelet vårt: Det inneholder mange underkataloger og mange flere filer. Mens du holder på med arbeidet, bestemmer du deg kanskje for at du må lage en arbeidskopi som skal ha en spesiell funksjonalitet sammen med feilrettinger. Du kan oppnå dette ved å selektivt tilbakedatere filer eller kataloger til spesielle revisjoner (ved å bruke svn update -r i stor skala) eller ved å bytte om filer og kataloger til spesielle grener (ved hjelp av svn switch). Når du er ferdig, er arbeidskopien din et virvar av depotplasseringer fra forskjellige revisjoner. Men etter at du har kjørt noen tester, vet du at dette er akkurat sånn som du vil ha det.

På tide å lagre et øyeblikksbilde. Det å kopiere en URL til en annen vil ikke fungere her. I dette tilfellet ønsker du å lage et øyeblikksbilde av din eksakte arbeidskopi og lagre den i depotet. Heldigvis har svn copy faktisk fire forskjellige bruksmåter (som du kan lese om i Kapittel 9, Subversion Complete Reference), inkludert muligheten til å kopiere et tre av en arbeidskopi til depotet:

$ ls
min-arbeidskopi/

$ svn copy min-arbeidskopi 
http://svn.example.com/repos/calc/tags/mittmerke

La inn revisjon 352.

Nå er det en ny katalog i depotet, /calc/tags/mittmerke, som er et eksakt øyeblikksbilde av arbeidskopien din – blandede revisjoner, URLer og hele pakken.

Andre brukere har funnet interessante måter å bruke denne funksjonaliteten på. Noen ganger er det situasjoner hvor du har en dunge med lokale forandringer i arbeidskopien, og du vil at en kollega skal se på dem. Istedenfor å kjøre svn diff og sende patchfila (som ikke vil fange opp treforandringer eller forandringer i symbolske linker eller egenskaper), kan du istedenfor bruke svn copy for å sende arbeidskopien til et privat område i depotet. Kollegaen din kan dermed enten hente ut en nøyaktig kopi av arbeidskopien din, eller bruke svn merge for å motta de eksakte forandringene dine.

Vedlikehold av grener

Du har kanskje sett nå at Subversion er ekstremt fleksibel. Fordi grener og merker blir laget med den samme underliggende mekanismen (kopier av kataloger), og fordi grener og merker vises i filsystemet, finner mange Subversion litt skremmende. Den er nesten for fleksibel. I denne seksjonen vil vi komme med noen forslag på hvordan du kan arrangere og vedlikeholde dataene dine over tid.

Utseendet på depotet

Det er noen standardiserte, anbefalte måter å organisere et depot på. Mange lager en trunk-katalog for å lagre hovedlinjen av utviklingen, en branches-katalog som inneholder grenkopier, og en tags-katalog som inneholder merker. Hvis et depot bare inneholder ett prosjekt, lager man ofte disse toppkatalogene:

/trunk
/branches
/tags

Hvis et depot inneholder flere prosjekter, legger administratorer vanligvis depotet opp etter prosjekt (se “Velge en depot-layout” for å lese mer om prosjektrøtter):

/paint/trunk
/paint/branches
/paint/tags
/calc/trunk
/calc/branches
/calc/tags

Du står selvfølgelig fritt til å ignorere disse vanlige oppsettene. Du kan lage alle mulige varianter, hva som enn fungerer best for deg og ditt team. Husk at hva du enn velger, er du ikke forpliktet til å ha det sånn for alltid. Du kan reorganisere depotet ditt når du vil. Fordi grener og merker er vanlige kataloger, kan svn move-kommandoen flytte eller skifte navn på dem sånn som du ønsker. Å bytte fra et utseende til et annet er bare snakk om å utføre en serie flyttinger på serveren; hvis du ikke liker måten ting er organisert på i depotet, er det bare å ommøblere på katalogene.

Men husk at selv om det å flytte kataloger er en enkel sak, må du også tenke på brukerne dine. Ommøbleringen kan være forvirrende for brukere med eksisterende arbeidskopier. Hvis en bruker har en arbeidskopi fra en spesiell depotkatalog, kan svn move-operasjonen fjerne stien fra den seneste revisjonen. Når brukeren kjører svn update neste gang, vil hun bli fortalt at arbeidskopien hennes representerer en sti som ikke lenger finnes, og brukeren vil bli tvunget til å bruke svn switch for å sette arbeidskopien til den nye plasseringen.

Levetid for data

En annen fin funksjonalitet med Subversions modell er at grener og merker kan ha begrenset levetid, akkurat som ethvert annet versjonert element. Tenk deg for eksempel at du etterhvert blir ferdig med alt arbeidet på din personlige gren i calc-prosjektet. Etter at du har flettet alle dine forandringer tilbake til /calc/trunk, trenger ikke grenkatalogen å ligge der mer:

$ svn delete http://svn.example.com/repos/calc/branches/min-calc-gren \
             -m "Fjerner avlegs gren i calc-prosjektet."

La inn revisjon 375.

Og nå er forgreningen borte. Vel, selvfølgelig er den ikke egentlig borte, katalogen mangler bare fra HEAD-revisjonen og distraherer dermed ingen. Hvis du bruker svn checkout, svn switch eller svn list for å undersøke en tidligere revisjon, vil du fortsatt være i stand til å se den gamle grenen din.

Hvis det ikke er nok å bare undersøke den slettede katalogen, kan du alltids hente den tilbake. Å hente tilbake data i Subversion er veldig enkelt. Hvis det er en slettet katalog (eller fil) som du vil hente tilbake inn i HEAD, kan du bruke svn copy -r for å kopiere den fra den gamle revisjonen:

$ svn copy -r 374 http://svn.example.com/repos/calc/branches/min-calc-gren \
                  http://svn.example.com/repos/calc/branches/min-calc-gren

La inn revisjon 376.

I eksempelet vårt hadde den personlige grenen din en relativt kort levetid, du kan ha laget den for å ordne en feil eller legge til en ny funksjonalitet. Når oppgaven din er gjort, er levetiden til grenen over. Men innen programutvikling er det også vanlig å ha to hoved-grener som lever ved siden av hverandre for veldig lange perioder. For eksempel, tenk deg at det er på tide å utgi en stabil versjon av calc-prosjektet til offentligheten, og du vet at det kommer til å ta noen måneder å luke ut feil av programmet. Du vil ikke at folk skal legge inn ny funksjonalitet til prosjektet, men du vil heller ikke at utviklerne skal stoppe programmeringen. Så istedenfor lager du en stabil gren av programmet som ikke vil forandre seg så mye:

$ svn copy http://svn.example.com/repos/calc/trunk \
         http://svn.example.com/repos/calc/branches/stabil-1.0 \
         -m "Lager stabil gren av calc-prosjektet."

La inn revisjon 377.

Og nå kan utviklerne fortsette med å legge til rykende ferske (eller eksperimentelle) funksjoner til /calc/trunk, og du kan lage en regel for prosjektet som sier at kun feilrettinger skal legges inn i /calc/branches/stabil-1.0. Det vil si, mens brukerne fortsetter å arbeide i trunk, kan feilrettinger selektivt bli flettet over til den stabile grenen. Selv etter at den stabile grenen er på markedet, vil du sannsynligvis fortsette å vedlikeholde grenen i lang tid – det vil si så lenge du fortsetter med å vedlikeholde utgivelsen for kunder.

Leverandørgrener

Som det ofte er når man utvikler programvare, er dataene du har under versjonskontroll ofte nært knyttet til, eller avhengig av, noen andres data. Vanligvis vil behovene til prosjektet ditt tilsi at du holder deg mest mulig oppdatert som mulig med dataene som du får fra denne eksterne enheten uten å ofre stabiliteten til ditt eget prosjekt. Denne situasjonen oppstår hele tiden – alle steder der informasjonen generert av en gruppe har en direkte effekt på hva som er generert av en annen gruppe.

For eksempel, programvareutviklere kan utvikle en programpakke som bruker tredjeparts biblioteker. Subversion har akkurat et slikt forhold til Apache Portable Runtime library (se “The Apache Portable Runtime Library”). Kildekoden til Subversion avhenger av APR-biblioteket for alle behov innen portabilitet. I tidligere faser av utviklingen til Subversion, fulgte prosjektet brukergrensesittet for APR veldig nøye, og brukte alltid den helt nyeste koden til biblioteket. Så som både APR og Subversion har modnet, prøver Subversion å synkronisere med kun velprøvde, stabile utgaver av APR-biblioteket.

Hvis prosjektet ditt nå består av noen adres informasjon, er det flere måter du kan prøve å synkronisere denne informasjonen med din egen. Det mest smertefulle kan være å gi muntlige eller nedskrevne instruksjoner til alle bidragsyterne for prosjektet, og fortelle dem at de må være sikre på at de har de absolutt riktige versjonene av denne tredjepartsinformasjonen. Hvis tredjepartsinformasjonen lagres i et Subversion-depot, kan du også bruke Subversions externals-definisjon for å effektivt nagle fast spesifikke versjoner av den informasjonen til en spesiell plassering i din egen arbeidskopi (se “Externals Definitions”).

Men noen ganger vil du vedlikeholde spesialtilpassede versjoner av tredjeparts programvare i ditt eget versjonskontrollsystem. Hvis vi går tilbake til programutviklingseksempelet, kan det være nødvendig for programmerere å gjøre forandringer i tredjepartsbiblioteket for eget bruk. Disse forandringene kan inneholde ny funksjonalitet eller filrettinger, internt vedlikeholdt bare til de blir del av en offisiell utgivelse av tredjepartsbiblioteket. Eller forandringene blir kanskje aldri sendt tilbake til vedlikeholderne av biblioteket, men fungerer bare som hjemmeskrudde løsninger for å få biblioteket til å dekke behovene enda bedre.

Nå står du ovenfor en interessant situasjon. Prosjektet ditt kunne lagret spesialforandringene i tredjepartsdataene som noe helt annet, som å bruke patchfiler eller fullstendige alternative versjoner av filer og kataloger. Men dette vedlikeholdet har en tendens til å bli en hodepine som krever en eller annen mekanisme som du bruker til å legge inn dine spesialforandringer i tredjepartsdataene. Det vil også være nødvendig å regenerere disse forandringene med hver eneste etterfølgende versjon av tredjepartsdataene som du følger med på.

Løsningen på dette problemet er å bruke leverandørgrener (engelsk: vendor branches). En leverandørgren er et katalogtre i deitt eget versjonskontrollsystem som inneholder informasjon utgitt av en tredjepart eller leverandør. Hver versjon av leverandørens data som du bestemmer det for å legge inn i prosjektet ditt, kalles vendor drop.

Leverandørgrener gir to fordeler. For det første, ved å lagre den nåværende versjonen av leverandørdataene i ditt eget versjonskontrollsystem, trenger medlemmene i prosjektet ditt aldri å lure på om de har den riktige versjonen som en del av de vanlige arbeidskopioppdateringene. For det andre, fordi dataene er i ditt eget Subversiondepot, kan du lagre forandringene dine direkte i dem – du trenger ikke lengre å ha en automatisert (eller enda verre, manuell) metode for å legge inn tilpasningene dine.

Generell prosedyre for vedlikehold av leverandørgrener

Dette er måten vedlikehold av leverandørgrener vanligvis fungerer på. Du lager en katalog på toppnivå (som for eksempel /vendor) for å lagre leverandørgrenene. Deretter importerer du tredjepartskoden inn i en underkatalog i denne toppkatalogen. Så kopierer du denne underkatalogen inn på grenen der hovedutviklingen foregår (for eksempel /trunk på den riktige plasseringen. Du gjør alltid dine lokale forandringer på grenen der hovedutviklingen foregår. For hver ny utgivelse av koden du følger med på, legger du den inn på leverandørgrenen og fletter forandringene inn i /trunk og ordner eventuelle konflikter som måtte oppstå mellom dine lokale forandringer og de offisielle forandringene.

Kanskje vil et eksempel hjelpe på å klarne opp i fremgangsmåten. Vi bruker en situasjon der utviklingsteamet lager et regneprogram som lenker mot et tredjeparts bibliotek for kompleks aritmetikk, libcomplex. Vi starter med den innledende opprettelsen av leverandørgrenen og den første importen av leverandørutgivelsen. Vi kaller leverandørgrenen libcomplex, og leverandørutgivelsene går i en underkatalog i leverandørgrenen kalt current. Og siden svn import oppretter alle de mellomliggende foreldrekataloger som vi trenger, kan vi faktisk gjøre begge disse stegene med en enkelt kommando.

$ svn import /sti/til/libcomplex-1.0 \
             http://svn.example.com/repos/vendor/libcomplex/current \
             -m 'Importerer innledende 1.0-versjon'
…

Vi har nå den nåværende versjonen av libcomplex-kildekoden i /vendor/libcomplex/current. Nå merker vi denne versjonen (se “Merker (tags)” og deretter kopierer den inn på hovedutviklingsgrenen. Kopien vår vil opprette en ny katalog kalt libcomplex i den eksisterende prosjektkatalogen calc. Det er i denne kopien av leverandørdataene vi vil gjøre forandringene.

$ svn copy http://svn.example.com/repos/vendor/libcomplex/current  \
           http://svn.example.com/repos/vendor/libcomplex/1.0      \
           -m 'Merker libcomplex-1.0'
…
$ svn copy http://svn.example.com/repos/vendor/libcomplex/1.0  \
           http://svn.example.com/repos/calc/libcomplex        \
           -m 'Legger libcomplex-1.0 inn på hovedgrenen'
…

Vi henter ut prosjektets hovedgren – som nå inneholder en kopi av den første leverandørutgivelsen – og vi setter i gang med å tilpasse libcomplex-koden. Før vi vet ordet av det, er den modifiserte versjonen av libcomplex fullstendig integrert i kalkulatorprogrammet.[26]

Noen uker senere slipper utviklerne av libcomplex en ny versjon av biblioteket – versjon 1.1 – som inneholder trivelig funksjonalitet som vi har lyst på. Vi vil oppgradere til denne nye versjonen, men uten å miste forandringene vi gjorde i den eksisterende versjonen. Det vi egentlig vil gjøre, er å erstatte den nåværende utviklingsversjonen med en kopi av libcomplex 1.1 og deretter legge inn forandringene våre i den nye versjonen. Men vi gjør det faktisk den andre veien, legger inn forandringene i libcomplex mellom versjon 1.0 og 1.1 i den modifiserte kopien av den.

For å gjennomføre denne oppgraderingen, henter vi ut en kopi av leverandørgrenen og erstatter koden i current-katalogen med den nye koden for libcomplex 1.1. Vi kopierer bokstavelig talt nye filer på toppen av eksisterende filer, kanskje ved å pakke ut .tar.gz-fila oppå de eksisterende filene og katalogene. Meningen med dette er å få current-katalogen til å inneholde kun koden fra libcomplex 1.1, og å forsikre seg om at all denne koden er under versjonskontroll. Og en annen ting var at vi ville at dette skulle skje uten å forstyrre versjonskontrollhistorien alt for mye.

Etter å ha erstattet 1.0-koden med 1.1, vil svn status vise filer med lokale forandringer sammen med filer som kanskje er uversjonert eller mangler. Hvis vi gjorde det vi skulle, er de uversjonerte filene bare de nye filene introdusert i 1.1-versjonen av libcomplex – vi kjører svn add på disse for å få dem under versjonskontroll. De manglende filene er filer som var i 1.0, men ikke i 1.1, og på disse stiene kjører vi svn delete. Helt til slutt, når current-arbeidskopien kun inneholder koden for libcomplex 1.1, legger vi inn forandringene vi gjorde for å få den til å se ut som den gjør.

Nå inneholder current-grenen den nye leverandørversjonen. Vi merker den nye versjonen (på den samme måten vi tidligere merket 1.0-versjonen) og fletter deretter forandringene mellom merket for den forrige versjonen og den nye gjeldende versjonen inn i hovedutviklingsgrenen.

$ cd arbeidskopier/calc
$ svn merge http://svn.example.com/repos/vendor/libcomplex/1.0      \
            http://svn.example.com/repos/vendor/libcomplex/current  \
            libcomplex
… # Rydd opp i alle konfliktene mellom deres og våre forandringer
$ svn commit -m 'merging libcomplex-1.1 into the main branch'
…

I enkle sitasjoner vil den nye versjonen av tredjepartsdataene se ut som, fra et fil og katalog-syn, akkurat om den forrige versjonen. Ingen av filene i libcomplex vil være slettet, ha fått nytt navn eller blitt flyttet til andre plasseringer – den nye versionen vil bare inneholde tekstmessige forandringer i forhold til den forrige. I en perfekt verden ville våre forandringer legge seg inn i den nye versjonen uten antydning til komplikasjoner eller konflikter.

Men det er ikke alltid så enkelt, og faktisk er det ganske vanlig for kildekodefiler å bli flyttet rundt mellom programutgivelser. Dette kompliserer prosessen som går ut på å forsikre seg om at våre forandringer fortsatt er gyldige for den nye versjonen av koden, noe som kan ende med den situasjonen at vi manuelt må gjenopprette våre forandringer i den nye versjonen. Når Subversion vet om historien til en gitt kildefil – inkludert alle dens tidligere plasseringer – er prosessen med å flette inn den nye versjonen av biblioteket ganske enkel. Men vi er ansvarlig for å fortelle Subversion hvordan kildekodelayouten forandret seg fra leverandørversjon til leverandørversjon.

svn_load_dirs.pl

Vendor drops that contain more than a few deletes, additions and moves complicate the process of upgrading to each successive version of the third-party data. So Subversion supplies the svn_load_dirs.pl script to assist with this process. This script automates the importing steps we mentioned in the general vendor branch management procedure to make sure that mistakes are minimized. You will still be responsible for using the merge commands to merge the new versions of the third-party data into your main development branch, but svn_load_dirs.pl can help you more quickly and easily arrive at that stage.

In short, svn_load_dirs.pl is an enhancement to svn import that has several important characteristics:

  • It can be run at any point in time to bring an existing directory in the repository to exactly match an external directory, performing all the necessary adds and deletes, and optionally performing moves, too.

  • It takes care of complicated series of operations between which Subversion requires an intermediate commit—such as before renaming a file or directory twice.

  • It will optionally tag the newly imported directory.

  • It will optionally add arbitrary properties to files and directories that match a regular expression.

svn_load_dirs.pl takes three mandatory arguments. The first argument is the URL to the base Subversion directory to work in. This argument is followed by the URL—relative to the first argument—into which the current vendor drop will be imported. Finally, the third argument is the local directory to import. Using our previous example, a typical run of svn_load_dirs.pl might look like:

$ svn_load_dirs.pl http://svn.example.com/repos/vendor/libcomplex \
                   current                                        \
                   /path/to/libcomplex-1.1
…

You can indicate that you'd like svn_load_dirs.pl to tag the new vendor drop by passing the -t command-line option and specifying a tag name. This tag is another URL relative to the first program argument.

$ svn_load_dirs.pl -t libcomplex-1.1                              \
                   http://svn.example.com/repos/vendor/libcomplex \
                   current                                        \
                   /path/to/libcomplex-1.1
…

When you run svn_load_dirs.pl, it examines the contents of your existing current vendor drop, and compares them with the proposed new vendor drop. In the trivial case, there will be no files that are in one version and not the other, and the script will perform the new import without incident. If, however, there are discrepancies in the file layouts between versions, svn_load_dirs.pl will prompt you for how you would like to resolve those differences. For example, you will have the opportunity to tell the script that you know that the file math.c in version 1.0 of libcomplex was renamed to arithmetic.c in libcomplex 1.1. Any discrepancies not explained by moves are treated as regular additions and deletions.

The script also accepts a separate configuration file for setting properties on files and directories matching a regular expression that are added to the repository. This configuration file is specified to svn_load_dirs.pl using the -p command-line option. Each line of the configuration file is a whitespace-delimited set of two or four values: a Perl-style regular expression to match the added path against, a control keyword (either break or cont), and then optionally a property name and value.

\.png$              break   svn:mime-type   image/png
\.jpe?g$            break   svn:mime-type   image/jpeg
\.m3u$              cont    svn:mime-type   audio/x-mpegurl
\.m3u$              break   svn:eol-style   LF
.*                  break   svn:eol-style   native

For each added path, the configured property changes whose regular expression matches the path are applied in order, unless the control specification is break (which means that no more property changes should be applied to that path). If the control specification is cont—an abbreviation for continue—then matching will continue with the next line of the configuration file.

Any whitespace in the regular expression, property name, or property value must be surrounded by either single or double quote characters. You can escape quote characters that are not used for wrapping whitespace by preceding them with a backslash (\) character. The backslash escapes only quotes when parsing the configuration file, so do not protect any other characters beyond what is necessary for the regular expression.

Oppsummering

Vi har gått gjennom en god del i dette kapittelet. Vi har diskutert konseptene rundt merker og grener, og demonstrert hvordan Subversion implementerer disse konseptene ved å kopiere kataloger med svn copy-kommandoen. Vi har vist hvordan svn merge brukes for å kopiere forandringer fra en gren til en annen, eller omgjøre feile forandringer. Vi har gått over bruken av svn switch for å lage arbeidskopier med blandede revisjoner. Og vi har snakket om hvordan man kan vedlikeholde organiseringen og levetiden til grener i et depot.

Husk mantraet til Subversion: Grener og merker er billige. Bruk dem så mye du vil!




[21] Subversion støtter ikke kopiering mellom forskjellige depot. Når du bruker URLer med svn copy eller svn move kan du bare kopiere elementer innenfor det samme depotet.

[22] I fremtiden planlegger Subversionprosjektet å bruke (eller finne opp) et utvidet patchformat som beskriver forandringer i trestruktur og egenskaper.

[23] Subversionprosjektet har imidlertid planer om å legge inn en svnadmin obliterate-kommando som vil ta seg av oppgaven med å permanent slette informasjon. I mellomtiden, se “svndumpfilter” for en mulig omvei om problemet.

[24] Fordi CVS ikke versjonerer trær, lager den et Attic-område innenfor hver depotkatalog som en måte å huske slettede filer på.

[25] Du kan imidlertid bruke svn switch med --relocate-valget hvis URL-en til serveren forandrer seg og du ikke vil forkaste en eksisterende arbeidskopi. Se svn switch-seksjonen i Kapittel 9, Subversion Complete Reference for mer informasjon og et eksempel.

[26] Og uten en eneste bug, selvfølgelig!

Kapittel 5. Depotadministrasjon

Subversiondepotet er den sentrale lagringsplassen for versjonerte data for ethvert antall prosjekter. Som sådan blir det en opplagt kandidat for all kjærlighet og oppmerksomhet en administrator kan tilby. Selv om depotet vanligvis er et element som krever lite vedlikehold, er det viktig å forstå hvordan du kan konfigurere og passe på det så potensielle problemer blir unngått, og aktuelle problemer løst på en trygg måte.

I dette kapittelet vil vi diskutere hvordan du kan opprette og konfigurere et Subversiondepot. Vi vil også snakke om depotvedlikehold, inkludert bruken av verktøyene svnlook og svnadmin (som følger med Subversion). Vi vil adressere vanlige spørsmål og feilgrep, og komme med noen forslag til hvordan du kan legge opp dataene i depotet.

Hvis du planlegger å aksessere et Subversiondepot bare i rollen som en bruker som har data under versjonskontroll (det vil si via en Subversionklient), kan du hoppe over hele dette kapitlet. Hvis du derimot er, eller vil bli, en administrator for et Subversiondepot,[27] bør du så absolutt følge med i dette kapittelet.

Det grunnleggende ved et depot

Før vi hopper inn i det mer generelle innen emnet depotadministrasjon, la oss definere videre hva et depot er. Hvordan ser det ut? Hvordan føles det? Vil det ha teen sin varm eller med is, søt, og med sitron? Som en administrator blir det forventet av deg at du må forstå sammensetningen av et depot både fra et logisk perspektiv – det å styre med hvordan data er representert i depotet – og fra et fysisk skrue-og-mutter-perspektiv – hvordan et depot ser ut og oppfører seg i sammenheng med verktøy som ikke hører med til Subversion-pakken. Den følgende seksjonen dekker noen av disse grunnleggende konseptene på et høyt nivå.

Forståelse av transaksjoner og revisjoner

Konseptmessig sagt er et Subversiondepot en sekvens av trær. Hvert tre er et øyeblikksbilde av hvordan filene og katalogene så ut på et spesielt tidspunkt. Disse øyeblikksbildene er opprettet som et resultat av klientoperasjoner og blir kalt revisjoner.

Hver revisjon begynner livet som et transaksjonstre. Når du gjør en innlegging, bygger en klient en Subversiontransaksjon som avspeiler deres lokale forandringer (pluss eventuelle forandringer som er blitt lagt inn i tillegg til depotet siden begynnelsen av innleggingsprosessen), og instruerer deretter depotet om å lagre dette treet som det neste øyeblikksbildet i sekvensen. Hvis innleggingen lykkes, blir transaksjonen innlemmet i et nytt revisjonstre, og blir tildelt et nytt revisjonsnummer. Hvis innleggingen av en eller annen grunn ikke lykkes, blir transaksjonen ødelagt og klienten informeres om feilen.

Oppdateringer fungerer på en lignende måte. Klienten bygger et midlertidig transaksjonstre som avspeiler tilstanden til arbeidskopien. Depotet sammenligner deretter dette transaksjonstreet med revisjonstreet i den forespurte revisjonen (vanligvis det nyeste, eller yngste treet), og sender tilbake informasjon som forteller klienten om hvilke forandringer som er nødvendig for å forandre deres arbeidskopi til et replikat av det aktuelle revisjonstreet. Etter at oppdateringen er fullført, blir den midlertidige transaksjonen slettet.

Bruken av transaksjonstrær er den eneste måten å gjøre permanente forandringer til et depots versjonskontrollerte filsystem. Det er imidlertid viktig å forstå at livløpet til en transaksjon er komplett fleksible. I tilfellet med oppdateringer er transaksjoner midlertidige trær som blir øyeblikkelig ødelagt. I tilfellet med innlegginger blir transaksjoner transformert inn i permanente revisjoner (eller fjernet hvis innleggingen feiler). I tilfelle en generell feil eller programfeil oppstår, er det mulig at en transaksjon kan bli liggende igjen i depotet (uten å påvirke noe som helst, men tar opp diskplass).

I teorien vil kanskje hele arbeidsflytapplikasjoner en gang gi mer nøyaktig kontroll med levetiden til en transaksjon. Det er mulig å tenke seg et system som ved hver transaksjon beregnet på å bli en revisjon blir satt på venting etter at klienten er ferdig med å beskrive sine forandringer til depotet. Dette ville muliggjøre at hver ny innlegging kan bli sett over av noen andre, kanskje en manager eller ledende utvikler, som kan velge å forfremme transaksjonen til en revisjon eller avbryte den.

Uversjonerte egenskaper

Transaksjoner og revisjoner i Subversiondepotet kan ha vedlagte egenskaper. Disse egenskapene er generiske nøkkel-til-verdi-mappinger, og blir vanligvis brukt til å lagre informasjon om treet som de er vedlagt. Navnene og verdiene til disse egenskapene er lagret i depotets filsystem, sammen med resten av dataene for treet.

Revisjons- og transaksjonsegenskaper er nyttige for å assosiere informasjon sammen med et tre som ikke er spesifikt relatert til filene og katalogene i dette treet ― den typen informasjon som ikke er behandlet av arbeidskopier for klienten. For eksempel, når en ny innleggingstransaksjon er opprettet i depotet, legger Subversion en egenskap til denne transaksjonen kalt svn:date – et tidsmerke som representerer tidspunktet transaksjonen ble opprettet. Når innleggingsprosessen er fullført, og transaksjonen blir forfremmet til en permanent revisjon, har treet også fått en egenskap for å lagre brukernavnet til revisjonens forfatter (svn:author) og en egenskap for å lagre loggmeldingen som hører til denne revisjonen svn:log.

Revisjons- og transaksjonsegenskaper er uversjonerte egenskaper – når de blir modifisert blir den foregående verdien permanent forkastet. Selv om revisjonstrær er uforanderlige, gjelder ikke dette egenskapene som er vedlagt disse trærne. Du kan legge til, fjerne, og modifisere revisjonsegenskaper til enhver tid i fremtiden. Hvis du legger inn en ny revisjon og senere finner ut at du la inn feil informasjon eller skrivefeil i loggmeldingen, kan du enkelt forandre verdien i svn:log-egenskapen med en ny, rettet loggmelding.

Datalagring i depotet

I Subversion 1.1 er det to valg for å lagre data i et Subversiondepot. En depottype lagrer alt i en Berkeley DB-database; den andre typen lagrer data som ordinære flate filer i et tilpasset format. Fordi Subversionutviklere ofte referer til et depot som det (versjonerte) filsystemet, har de lagt seg til vanen med å refere til den sistnevnte typen depot som FSFS[28] – en versjonert filsystemimplementasjon som bruker det vanlige filsystemet til operativsystemet for å lagre data.

Når et depot er opprettet, må administratoren bestemme om Berkeley DB eller FSFS skal brukes. Det er fordeler og ulemper med begge to, som vi vil gå gjennom ganske snart. Ingen av de bakenforliggende depotene er mer offisielle enn andre, og programmer som aksesserer depotet er beskyttet fra denne implementasjonsdetaljen. Programmer har ingen formening om hvordan depotet lagrer data; de ser bare revisjons- og transaksjonstrær gjennom depotgrensesnittet.

Tabell 5.1, “Sammenligning av datalagring i depoter” inneholder en tabell som gir en oversikt over forskjellene mellom depoter av typen Berkeley DB og FSFS. De neste seksjonene går inn i detalj.

Tabell 5.1. Sammenligning av datalagring i depoter

FunksjonalitetBerkeley DBFSFS
Følsom for avbrytelserveldig; krasj og problemer med rettigheter kan etterlate databasen i en fastkilt (Engelsk: wedged) tilstand som krever journalførte gjenopprettingsprosedyrer.ganske ufølsom.
Kan brukes fra et ikke-skrivbart mediumneija
Plattformuavhengig lagringneija
Brukbar over nettverksfilsystemneija
Depotstørrelselitt størrelitt mindre
Skalerbarhet: Antall revisjonstrærdatabase; ingen problemerytelsen på noen eldre filsystemer blir dårligere med tusenvis av elementer i en katalog.
Skalerbarhet: Kataloger med mange filerlangsommereraskere
Hastighet: Uthenting av nyeste koderaskerelangsommere
Hastighet: Store innleggingerlangsommere, men arbeidet blir spredt ut over innleggingenraskere, men forsinkelse i avslutningen kan forårsake tidsavbrudd for klienten.
Behandling av grupperettigheterfølsom for problemer med umask; det beste er om den blir aksessert av bare en bruker.jobber seg rundt problemer med umask
Kodemodenheti bruk siden 2001i bruk siden 2004


Berkeley DB

I den innledende designfasen av Subversion bestemte utviklerne seg for å bruke Berkeley DB av diverse grunner, blant annet dens åpne lisens, transaksjonsstøtte, stabilitet, effektivitet, enkelt grensesnitt, trådsikkerhet, støtte for databasepekere og så videre.

Berkeley DB tilbyr reell støtte for transaksjoner – kanskje dens kraftigste funksjonalitet. Flere prosesser som aksesserer Subversiondepotene dine trenger ikke å tenke på faren ved å rote til hverandres data. Isolasjonen som transaksjonssystemet tilbyr er slik at for enhver operasjon ser Subversions depotkode et statisk bilde av en database – ikke en database som konstant forandres av en annen prosess – og kan foreta avgjørelser basert på dette bildet. Hvis avgjørelsen kommer i konflikt med det en annen prosess gjør, blir hele operasjonen rullet tilbake som om den aldri skjedde, og Subversion prøver forsiktig operasjonen mot et nytt, oppdatert (og fortsatt statisk) bilde av databasen.

En annen fin funksjonalitet med Berkeley DB er varme backuper (hot backups) – muligeten til å ta sikkerhetskopi av databasen uten å ta den ned. Vi vil diskutere hvordan du tar backup av depotet i “Sikkerhetskopi av depotet”, men fordelene med å kunne ta fullstendige fungerende kopier av depotene dine uten nedetid er innlysende.

Berkeley DB er også et veldig sikkert databasesystem. Subversion bruker Berkeley DBs loggefasiliteter, som betyr at databasen først lager en beskrivelse i loggfiler på disken om hva den er i ferd med å gjøre, og foretar deretter selve modifiseringen. Dette er for å forsikre seg om at i tilfelle noe går galt, kan databasesystemet hente tilbake et tidligere sjekkpunkt – en posisjon i loggfilene som den vet ikke er ødelagt – og spille av transaksjoner inntil dataene er gjenopprettet til en fungerende tilstand. Se “Bruken av diskplass” for mer angående loggfilene i Berkeley DB.

Men alle roser har torner, og derfor må vi være klar over noen kjente begrensninger i Berkeley DB. For det første er ikke Berkeley DB-miljøer portable. Du kan ikke bare kopiere et Subversiondepot som er laget på et UNIX-system til et Windows-system og forvente at det skal virke. Selv om mye av Berkely DB-formatet er arkitekturuavhengig, er det andre aspekter med miljøet som ikke er det. For det andre bruker Subersion Berkeley DB på en måte som ikke vil fungere i Windows 95/98 – hvis du må ha depotet på en Windowsmaskin, bruk Windows 2000 eller Windows XP. Legg heller aldri et Berkeley DB-depot på en nettverksdisk. Selv om Berkeley DB lover å oppføre seg korrekt på nettverksdisker som oppfyller spesielle kriterier, er det nesten ingen kjente nettverksdelinger som faktisk oppfyller alle disse spesifikasjonene.

Til sist, fordi Berkeley DB er et bibliotek linket direkte inn i Subversion, er det mer sårbart for avbrudd enn et typisk relasjonsdatabasesystem. De fleste SQL-systemer har for eksempel en dedisert serverprosess som fordeler all tilgang til tabeller. Hvis et program som aksesserer databasen krasjer av en eller annen grunn, oppdager daemonen som styrer databasen at forbindelsen er brutt og ordner opp i eventuelt rot som blir liggende igjen. Og fordi databasedaemonen er den eneste prosessen som aksesserer tabellene, trenger ikke applikasjoner å tenke på rettighetskonflikter. Disse tingene er imidlertid ikke tilfelle med Berkeley DB. Subversion (og programmer som bruker Subversionbiblioteker) aksesserer databasetabellene direkte, noe som betyr at et programkrasj kan etterlate databasen i en midlertidig, utilgjengelig tilstand. Når dette skjer, må en administrator be Berkeley DB om gjenoppretting til et sjekkpunkt, noe som er litt plagsomt. Andre ting kan føre til at et depot kiler seg fast (wedge) sammen med krasjede prosesser, som for eksempel programmer som kommer i konflikt angående eierskap og tilgang til databasefilene. Så mens et Berkeley DB-depot er ganske raskt og skalerbart, fungerer det best når det kun blir brukt av én enkelt serverprosess som kjører som én bruker – som for eksempel Apaches httpd eller svnserve (se Kapittel 6, Serverkonfigurasjon) – istedenfor å aksessere det med mange forskjellige brukere via file:/// eller svn+ssh://-URLer. Hvis et Berkeley DB-depot blir brukt direkte med flere forskjellige brukere, pass på at du har lest “Støtte for flere metoder for tilgang til depotet”.

FSFS

I midten av 2004 ble et nytt lagringsformat for depotet laget, et som ikke bruker en database i det hele tatt. Et FSFS-depot lagrer et revisjonstre i en enkelt fil, og alle depotets revisjoner kan dermed finnes i en enkelt underkatalog full av nummererte filer. Transaksjoner blir opprettet i separate underkataloger. Når den er komplett, blir en enkelt transaksjonsfil opprettet og flyttet til revisjonskatalogen og garanterer dermed at innleggingen blir atomisk. Og fordi en revisjonsfil er permanent og uforanderlig, kan depotet også bli tatt backup av mens det er i bruk, akkurat som et Berkeley DB-depot.

Revisjonsfilformatet representerer en revisjons katalogstruktur, filinnhold og forskjeller i forhold til filer i andre revisjonstrær. Ulikt en Berkeley DB-database, er dette lagringsformatet portabelt mellom forskjellige operativsystemer og er ikke sensitiv ovenfor CPU-arkitektur. Fordi det ikke blir brukt journalfiler eller filer som bruker delt hukommelse, kan depotet trygt aksesseres via et nettverksfilsystem og bli utforsket i et skrivebeskyttet miljø. Mangelen på databaseoverhead betyr også at den samlede depotstørrelsen blir en del mindre.

FSFS har også forskjellige ytelseskarakteristikker. Når en katalog med mange filer legges inn, bruker FSFS en O(N)-algoritme for å legge til poster, mens Berkeley DB bruker en O(N^2)-algoritme for å skrive hele katalogen en gang til. På den annen side skriver FSFS den seneste versjonen av ei fil som en delta (forskjell) mot en tidligere versjon, noe som betyr at det å hente ut det seneste treet er litt langsommere enn å hente fullteksten lagret i en HEAD-revisjon i Berkeley DB. FSFS har også en lengre forsinkelse når en innlegging skal fullføres, noe som i ekstreme tilfeller kan føre til at klienter får et tidsavbrudd under venting på respons.

Men den viktigste forskjellen er FSFSs evne til å ikke bli fastkilt hvis noe går galt. Hvis en prosess som bruker en Berkeley DB-database får problemer med rettigheter eller plutselig krasjer, er ikke databasen brukbar før en administrator gjenoppretter den. Hvis det samme skjer med en prosess som bruker et FSFS-depot, blir ikke depotet påvirket i det hele tatt. I verste fall blir bare noen transaksjonsdata liggende igjen.

Det eneste virkelige argumentet mot FSFS er fartstiden det har hatt i forhold til Berkeley DB. Det er ikke like mye brukt og har ikke blitt stresstestet like mye, så derfor er mange av disse antakelsene om hastighet og skalerbarhet nettopp det: Antakelser, basert på gode gjetninger. I teorien lover den en lavere barriere å forsere for nye administratorer og er forventet å skape mindre problemer. I praksis vil bare tiden vise om dette stemmer.

Opprettelse og konfigurering av depotet

Det å opprette et Subversiondepot er en utrolig enkel oppgave. svnadmin-verktøyet som følger med Subversion har en delkommando som gjør akkurat det. For å opprette et nytt depot, er det bare å kjøre:

$ svnadmin create /sti/til/depot

Dette oppretter et nytt depot i katalogen /sti/til/depot. Dette nye depotet starter livet ved revisjon 0, som er definert til å bare innholde en rot på toppnivå (/) i filsystemet. Revisjon 0 har også en enkelt revisjonsegenskap satt innledningsvis, svn:date, som er satt til tidspunktet depotet ble opprettet.

I Subversion 1.2 blir et depot opprettet i FSFS-formatet som standard (se “Datalagring i depotet”). Formatet kan bli eksplisitt valgt med --fs-type-valget:

$ svnadmin create --fs-type fsfs /sti/til/depot
$ svnadmin create --fs-type bdb /sti/til/annet/depot
[Advarsel]Advarsel

Opprett ikke et Berkeley DB-depot på en nettverksdisk – det kan ikke eksistere på et fjerntliggende filsystem som NFS, AFS eller Windows SMB. Berkeley DB krever at det underliggende filsystemet har implementert streng POSIX låsesemantikk, og enda viktigere, muligheten til å mappe filer direkte inn i prosesshukommelsen. Nesten ingen nettverksfilsystemer tilbyr disse mulighetene. Hvis du forsøker å bruke Berkeley DB på en nettverksdisk, er resultatene uforutsigelige – du kan se mystiske feilmeldinger med en gang, eller det kan gå månedsvis før du oppdager at depotet i all stillhet blir herpa.

Hvis du trenger flere datamaskiner for å aksessere depotet, lager du et FSFS-depot på nettverksdisken, ikke et Berkeley DB-depot. Eller enda bedre, sett opp en skikkelig serverprosess (som for eksempel Apache eller svnserve), legg depotet i et lokalt filsystem som serveren kan aksessere og gjør depotet tilgjengelig over et nettverk. Kapittel 6, Serverkonfigurasjon dekker denne prosessen i detalj.

Du har kanskje lagt merke til at stiargumentet til svnadmin bare var en vanlig filsystemsti og ikke en URL lik det svn-klienten bruker når den refererer til depot. Både svnadmin og svnlook ansees som serverside-verktøy – de blir brukt på maskinen hvor depotet ligger for å undersøke og modifisere aspekter ved depotet, og er faktisk ikke i stand til å utføre oppgaver over nettverket. En vanlig feil som blir gjort av nybakte Subversionbrukere er å gi URLer (til og med av typene local og file:) til disse to programmene.

Så, etter at du har kjørt svnadmin create-kommandoen, har du et skinnende nytt depot i sin egen katalog. La oss ta en kikk på hva som egentlig er laget i denne katalogen.

$ ls depot
conf/  dav/  db/  format  hooks/  locks/  README.txt

Med unntak av filene README.txt og format, er depotkatalogen en samling av underkataloger. Som i andre områder av Subversion-designet er modularitet gitt stor oppmerksomhet, og hierarkisk organisering er foretrukket framfor rotete kaos. Her er en rask beskrivelse av alle elementene som du ser i den nye depotkatalogen:

conf

En katalog som inneholder konfigurasjonsfiler for depotet.

dav

En katalog der Apache og mod_dav_svn lagrer sine husholdningsdata.

db

Der alle dine versjonerte data ligger. Denne katalogen er enten et Berkeley DB-miljø (full av databasetabeller og andre ting) eller et FSFS-miljø som inneholder revisjonsfiler.

format

Ei fil som inneholder en enkelt heltallsverdi som spesifiserer versjonsnummeret til depotlayouten.

hooks

En katalog full av maler for påhakningsskript (Engelsk: hooks) og påhakningsskriptene selv, når du har installert noen.

locks

En katalog for Subversions låsedata, brukt for å følge tilganger til depotet.

README.txt

Ei fil som bare informerer sine lesere om at de ser på et Subversiondepot.

Generelt sett skal du ikke fikle med depotet for hånd. svnadmin-verktøyet skal være nok til alle nødvendige forandringer i depotet, eller du kan se på tredjeparts verktøy (som Berkeley DBs verktøysamling) for å finpusse relevante delseksjoner av depotet. Noen unntak gjelder imidlertid, og disse skal vi gå gjennom her.

Påhakningsskript

Et påhakningsskript (på engelsk kalt hooks) er et program som blir utløst av en hendelse i depotet, som for eksempel opprettelsen av en ny revisjon eller modifiseringen av en uversjonert egenskap. Hver påhakning blir gitt nok informasjon til å fortelle hva denne hendelsen er, hvilke mål den opererer på, og brukernavnet til personen som satte i gang hendelsen. Avhengig av påhakningens utdata eller returstatus, kan påhakningsprogrammet fortsette hendelsen, stoppe den, eller utsette den på en eller annen måte.

hooks-katalogen er, som standard, fylt med maler for diverse depotpåhakninger.

$ ls depot/hooks/
post-commit.tmpl          post-unlock.tmpl          pre-revprop-change.tmpl
post-lock.tmpl            pre-commit.tmpl           pre-unlock.tmpl
post-revprop-change.tmpl  pre-lock.tmpl             start-commit.tmpl

Det er en mal for hver påhakning som Subversiondepotet implementerer, og ved å undersøke innholdet til disse eksempelskriptene, kan du se hva som fører til at hvert av disse skriptene begynner å kjøre og hvilke data som blir levert til dette skriptet. Det som også ligger i mange av disse malene er eksempler på hvordan man kan bruke skriptet i sammenheng med andre programmer som følger med Subversion for å utføre vanlige, nyttige oppgaver. For å faktisk installere en påhakning som virker, trenger du bare å plassere et kjørbart program eller skript i depot/hooks-katalogen som kan bli kjørt basert på navnet (som for eksempel start-commit eller post-commit) til påhakningen.

På Unix-plattformer betyr dette å legge inn et skript eller program (som kan være et shellskript, et Pythonprogram, et kompilert C-program, eller hva som helst annet) som heter akkurat det samme som påhakningen. Selvfølgelig, malfilene er der for mer enn bare informasjonsverdien – den letteste måten å installere en påhakning på Unixplattformer er å bare kopiere den riktige malfila til ei ny fil som mangler .tmpl-etternavnet, finpusse på innholdet, og forsikre deg om at skriptet er kjørbart. Men Windows bruker filetternavn til å avgjøre hvorvidt et program er kjørbart eller ikke, så da må du legge inn et program der hovednavnet er navnet på påhakningen, og der etternavnet er en av de spesielle etternavnene som Windows kjenner igjen som kjørbare, for eksempel .exe eller .com for programmer, og .bat for batchfiler.

[Tips]Tips

Av sikkerhetsgrunner kjører Subversion påhakningsskript med et tomt miljø (environment) – det betyr, ingen miljøvariabler er satt i det hele tatt, ikke engang $PATH eller %PATH%. På grunn av dette blir mange adminstratorer forvirret når påhakningsskriptet kjører fint for hånd, men virker ikke når det blir kjørt av Subversion. Pass på å eksplisitt sette variabler i skriptet og/eller bruk absolutte stier til programmer.

Det er lagt inn ni påhakninger i Subversiondepotet:

start-commit

Denne blir kjørt allerede før innleggingstransaksjonen er opprettet. Det blir vanligvis brukt til å avgjøre om brukeren har innleggingsprivilegier i det hele tatt. Depotet leverer to argumenter til dette programmet: Stien til depotet, og brukernavnet som forsøker seg på innleggingen. Hvis programmet returnerer en verdi som ikke er null, blir denne innleggingen stoppet allerede før transaksjonen blir laget. Hvis påhakningen skriver data til standardfeil, vil det bli sendt tilbake til klienten.

pre-commit

Dette blir kjørt når transaksjonen er komplett, men før den er lagt inn. Vanligvis blir denne påhakningen brukt til å beskytte mot innlegginger som er forbudt på grunn av innhold eller beliggenhet (for eksempel kan serveren kreve at alle innlegginger til en spesiell gren inneholder et billettnummer fra feildatabasen, eller at den innkommende loggmeldingen ikke er tom). Depotet leverer to argumenter til dette programmet: Stien til depotet, og navnet på transaksjonen som legges inn. Hvis programmet returnerer en verdi som ikke er null, avbrytes innleggingen og transaksjonen blir fjernet. Hvis programmet skriver data til stderr, vil dette bli sendt tilbake til klienten.

Subversiondistribusjonen inneholder noen aksesskontrollskript (i tools/hook-scripts-katalogen i kildekodefiltreet til Subversion) som kan bli kalt fra pre-commit for å kunne legge inn finjustert kontroll for skriveaksess. En annen mulighet er å bruke Apache-modulen mod_authz_svn som gir både lese- og skrivekontroll i individuelle kataloger (se “Adgangskontroll på katalognivå”). I en framtidig versjon av Subversion planlegger vi å legge inn lister for aksesskontroll (ACL) direkte inn i filsystemet.

post-commit

Dette blir kjørt etter at transaksjonen er lagt inn, og en ny revisjon er opprettet. De fleste vil bruke denne påhakningen til å sende ut beskrivende eposter om innleggingen eller for å ta backup av depotet. Depotet gir to argumenter til dette programmet: Stien til depotet, og det nye revisjonsnummeret som ble opprettet. Returverdien fra programmet blir ignorert.

Subversiondistribusjonen inneholder skriptene mailer.py og commit-email.pl (i tools/hook-scripts/-katalogen i Subversiontreet) som kan bli brukt til å sende epost med (og/eller legge til en loggfil) en beskrivelse av en mottatt innlegging. Denne mailen inneholder en liste over de stiene som ble forandret, loggmeldingen som er vedlagt innleggingen, forfatteren og datoen til innleggingen, sammen med en GNU diff-visning av forandringene som ble gjort til diverse filer som del av innleggingen.

Et annet nyttig verktøy som følger med Subversion er skriptet hot-backup.py (i tools/backup/-katalogen i kildekodetreet til Subversion). Dette skriptet tar varme backuper av Subversiondepotet (en funksjonalitet støttet av den bakenforliggende Berkeley DB-databasen), og kan bli brukt til å foreta en øyeblikkslagring av depotet mellom hver innlegging for arkiverings- eller sikkerhetsformål.

pre-revprop-change

Fordi Subversions revisjonsegenskaper ikke er versjonerte, vil det å forandre slike egenskaper (for eksempel svn:log-egenskapen som inneholder loggmeldingen for innleggingen) overskrive den forrige verdien for alltid. Siden data kan gå tapt her, har Subversion denne påhakningen (og dens motstykke post-revprop-change) så depotadministratorer kan lage logger med forandringer i disse elementene ved bruk av eksterne hjelpemidler hvis de vil det. Som en forholdsregel mot å miste uversjonerte data, vil ikke Subversionklienter få lov til å forandre revisjonsegenskaper i det hele tatt hvis ikke denne påhakningen er aktivisert i depotet ditt.

Denne påhakningen kjører like før en slik modifisering blir lagt inn i depotet. Depotet leverer fire argumenter til denne påhakningen: Stien til depotet, revisjonen som egenskapen som skal forandres befinner seg på, det autentiserte brukernavnet til personen som gjør forandringen, og navnet på selve egenskapen.

post-revprop-change

Som nevnt tidligere, er denne påhakningen motstykket til pre-revprop-change-påhakningen. For paranoiaens skyld vil faktisk ikke dette skriptet kjøre uten at pre-revprop-change-skriptet finnes. Når begge disse skriptene finnes, kjører post-revprop-change-påhakningen like etter at en revisjonsegenskap er blitt forandret, og blir vanligvis brukt til å sende en epost som inneholder den nye verdien til den forandrede egenskapen. Depotet leverer fire argumenter til denne påhakningen: Stien til depotet, revisjonen som egenskapen tilhører, det godkjente brukernavnet til personen som gjør forandringen, og navnet på selve egenskapen.

Subversiondistribusjonen inkluderer skriptet propchange-email.pl (i tools/hook-scripts/-katalogen i Subversions kildekodetre) som kan bli brukt til å sende epost med (og/eller legge til en loggfil) detaljene om en egenskapsforandring. Denne eposten inneholder revisjonen og navnet til den forandrede egenskapen, brukeren som gjorde forandringen, og den nye verdien til egenskapen.

pre-lock

Denne påhakningen kjøres hver gang noen prøver å låse ei fil. Den kan bli brukt til å forby låser i det hele tatt, eller å definere et mer komplekst regelsett som spesifiserer nøyaktig hvilke brukere som får lov til å låse spesielle stier. Hvis påhakningen finner en allerede eksisterende lås, kan den også bestemme om en bruker har lov til å stjele den eksisterende låsen. Depotet leverer tre argumenter til påhakningen: Stien til depotet, stien som blir låst, og navnet på brukeren som prøver å utføre låsingen. Hvis programmet returnerer en verdi som ikke er null, blir låseprosessen avbrutt og alt som blir skrevet til standard feil blir sendt tilbake til klienten.

post-lock

Denne påhakningen kjører etter at en sti er låst. Den låste stien sendes til påhakningens standard inn, og påhakningen mottar også to argumenter: Stien til depotet og brukeren som utførte låsingen. Skriptet kan dermed sende melding via epost eller logge hendelsen på den måten som er bestemt. Fordi låsingen allerede har skjedd, blir utdataene fra påhakningen ignorert.

pre-unlock

Denne påhakningen kjøres når noen prøver å fjerne en lås på ei fil. Den kan brukes til å lage regler som spesifiserer hvilke brukere som har lov til å låse opp spesielle stier. Den er spesielt viktig for å avgjøre regler om bryting av låser. Hvis bruker A låser ei fil, får bruker B lov til å bryte låsen? Hva hvis låsen er mer enn en uke gammel? Denne typen ting kan bli bestemt og gjennomført av påhakningen. Depotet leverer tre argumenter til påhakningen: Stien til depotet, stien som låses opp, og navnet på brukeren som prøver å fjerne låsen. Hvis programmet returnerer en verdi som ikke er null, blir opplåsingsprosessen avbrutt og alt som blir skrevet til standardfeil leveres til klienten.

post-unlock

Denne påhakningen kjøres etter at en sti er låst opp. Stien som er låst opp sendes til skriptets standard inn, og det mottar også to argumenter: Stien til depotet og brukeren som fjernet låsen. Påhakningen kan dermed sende epost eller logge hendelsen på den måten som er valgt. Fordi fjerningen av låsen allerede har skjedd, blir utdataene fra påhakningen ignorert.

[Advarsel]Advarsel

Ikke forsøk å forandre transaksjonen ved å bruke påhakningsskript. Et vanlig eksempel på dette ville være å automatisk sette egenskaper som svn:eol-style eller svn:mime-type under innleggingen. Selv om dette kan se ut som en god idé, fører det til problemer. Hovedproblemet er at klienten ikke vet om forandringen gjort av påhakningsscriptet, og det er ingen måte å informere klienten om at den er utdatert. Denne inkonsekventheten kan føre til overraskende og uventet oppførsel.

Istedenfor å forsøke å modifisere transaksjonen, er det mye bedre å sjekke transaksjonen i pre-commit og nekte innlegging hvis den ikke møter de ønskede kravene.

Subversion vil forsøke å kjøre påhakningsskriptene som den samme brukeren som eier prosessen som aksesserer Subversiondepotet. I de fleste tilfeller blir depotet aksessert via Apache HTTP-serveren og mod_dav_svn, så denne brukeren er den samme som Apache kjører som. Selve påhakningene må bli satt opp med rettigheter på operativsystemnivå som tillater denne brukeren å kjøre dem. Dette betyr også at enhver fil eller program (inkludert selve Subversiondepotet) aksessert direkte eller indirekte av påhakningen vil bli aksessert som den samme brukeren. Med andre ord, vær obs på mulig rettighetsproblematikk som kan forhindre påhakningsskriptet fra å utføre de oppgavene du har satt det til.

Konfigurasjon av Berkeley DB

Et Berkeley DB-miljø er en innkapsling av en eller flere databaser, loggfiler, regionfiler og konfigurasjonsfiler. Berkeley DB-miljøet har sitt eget sett med konfigurasjonsverdier for ting som antallet databaselåser som er tillatt brukt på en gang, maksimal størrelse på journalloggfiler og så videre. Subversions filsystemkode velger i tillegg standardverdier for noen av konfigurasjonsvalgene i Berkeley DB.

Folkene i Sleepycat (produsentene av Berkeley DB) innser at forskjellige databaser har forskjellige krav, og de har derfor lagt inn en mekanisme for å overstyre mange av konfigurasjonsverdiene til Berkeley DB under kjøring. Berkeley sjekker at fila DB_CONFIG finnes i hver miljøkatalog, og leser valgene som er i denne fila for bruk med akkurat dette Berkeley-miljøet.

Berkeley-konfigurasjonsfila for ditt depot ligger i miljøkatalogen db i depot/db/DB_CONFIG. Subversion oppretter selv denne fila når den lager resten av depotet. Fila inneholder innledningsvis noen standardvalg sammen med pekere til dokumentasjonen til Berkeley DB som ligger på nettet så du kan lese om hva disse valgene gjør. Du har selvfølgelig også muligheten til å legge til alle valg som Berkeley DB støtter til DB_CONFIG-fila. Pass bare på at mens Subversion aldri prøver å lese eller forstå innholdet i fila og bruker ingen av valgene i den, vil du unngå å gjøre forandringer i konfigurasjonen som får Berkeley DB seg til å oppføre seg annerledes enn det Subversionkoden forventer. I tillegg vil ikke forandringer gjort i DB_CONFIG aktiviseres før du gjenoppretter databasemiljøet (ved bruk av svnadmin recover).

Vedlikehold av depotet

Å vedlikeholde et Subversiondepot kan være en skremmende oppgave, mest på grunn av kompleksiteten som er innebygget i systemer med en bakenforliggende database. Å utføre oppgaven godt handler om å kjenne verktøyene – hva de er, når de skal brukes, og hvordan de brukes. Denne seksjonen vil introdusere deg for administrasjonsverktøy som følger med Subversion, og hvordan få dem til å utføre oppgaver som flytting av depot, oppgraderinger, sikkerhetskopiering og opprydding.

En administrators verktøykasse

Subversion har en håndfull programmer som er nyttige til å opprette, inspisere, modifisere og reparere depotet ditt. La oss se litt nærmere på hvert av disse verktøyene. Etterpå vil vi gå raskt over noen av de programmene som er inkludert i Berkeley DB-distribusjonen som tilbyr funksjonalitet spesifikk til databasedelen i depotet som ikke Subversions egne verktøy tar seg av.

svnlook

svnlook er et verktøy som følger med Subversion. Det er beregnet for å utforske de forskjellige revisjonene og transaksjonene i et depot. Ingen deler av dette programmet prøver å forandre depotet – det er et bare lese-verktøy. svnlook blir vanligvis brukt av påhakningsskriptene i depotet for å rapportere forandringene som er i ferd med å bli lagt inn (i tilfellet med pre-commit-påhakningen) eller det som nettopp ble lagt inn (i tilfellet med post-commit-påhakningen) i depotet. En depotadministrator kan bruke dette verktøyet for diagnoseformål.

svnlook har en likefrem syntaks:

$ svnlook help
general usage: svnlook SUBCOMMAND REPOS_PATH [ARGS & OPTIONS ...]
Note: any subcommand which takes the '--revision' and '--transaction'
      options will, if invoked without one of those options, act on
      the repository's youngest revision.
Type "svnlook help <subcommand>" for help on a specific subcommand.
…

Nesten hver eneste av delkommandoene til svnlook kan operere på enten et revisjons- eller transaksjonstre og skrive ut informasjon om selve treet eller hvordan det skiller seg ut fra den forrige revisjonen i depotet. Du bruker valgene --revision og --transaction for å spesifisere henholdsvis hvilken revisjon eller transaksjon som skal undersøkes. Legg merke til at mens revisjonsnumre fremstår som naturlige tall, er transaksjonsnavn alfanumeriske strenger. Husk at filsystemet bare tillater gjennomgang av transaksjoner som enda ikke er lagt inn (transaksjoner som ikke har resultert i en ny revisjon). De fleste depot vil ikke ha noen slike transaksjoner, fordi transaksjoner vanligvis enten er lagt inn (som diskvalifiserer dem fra visning) eller avbrutt og fjernet.

Hvis både valgene --revision og --transaction mangler, vil svnlook undersøke den yngste (eller HEAD) revisjonen i depotet. Så de følgende to kommandoene gjør akkurat det samme når 19 er den yngste revisjonen i depotet som ligger i /sti/til/depot:

$ svnlook info /sti/til/depot
$ svnlook info /sti/til/depot --revision 19

Det eneste unntaket fra disse reglene om delkommandoer er svnlook youngest-delkommandoen, som ikke tar noen valg, og bare skriver ut nummeret for HEAD-revisjonen.

$ svnlook youngest /sti/til/depot
19

Utdataene fra svnlook er designet for å være lesbare både for menneske og maskin. Som et eksempel kan vi ta utdataene fra delkommandoen info:

$ svnlook info /sti/til/depot
sally
2002-11-04 09:29:13 -0600 (Mon, 04 Nov 2002)
27
La til det vanlige
greske treet.

Utdataene fra info-delkommandoen er definert som:

  1. Forfatteren, etterfulgt av linjeslutt.

  2. Datoen, etterfulgt av linjeslutt.

  3. Antallet tegn i loggmeldingen, etterfulgt av linjeslutt.

  4. Selve loggmeldingen, etterfulgt av linjeslutt.

Disse utdataene er leselige for det menneskelige øye, det vil si at elementer som datoen blir vist som tekst istedenfor noe mer obskurt (som antall nanosekunder siden isbilen kjørte forbi). Men disse utdataene er også lesbare for en datamaskin – fordi loggmeldingen kan inneholde flere linjer og ha ubegrenset lengde, skriver svnlook lengden på denne meldingen før selve meldingen. Dette tillater skript og andre programmer som bruker denne kommandoen å gjøre intelligente valg angående loggmeldingen, som hvor mye hukommelse som skal reserveres for meldingen, eller i det minste hvor mange bytes som må hoppes over når disse utdataene ikke er den siste datadelen i strømmen.

En annen vanlig bruk av svnlook er å faktisk vise innholdet i et revisjons- eller transaksjonstre. Kommandoen svnlook tree viser katalogene og filene i det forespurte treet. Hvis du angir valget --show-ids, vil den også vise noderevisjons-ID for hver av disse stiene (som vanligvis er mer nyttige for utviklere enn vanlige brukere).

$ svnlook tree /sti/til/depot --show-ids
/ <0.0.1>
 A/ <2.0.1>
  B/ <4.0.1>
   lambda <5.0.1>
   E/ <6.0.1>
    alpha <7.0.1>
    beta <8.0.1>
   F/ <9.0.1>
  mu <3.0.1>
  C/ <a.0.1>
  D/ <b.0.1>
   gamma <c.0.1>
   G/ <d.0.1>
    pi <e.0.1>
    rho <f.0.1>
    tau <g.0.1>
   H/ <h.0.1>
    chi <i.0.1>
    omega <k.0.1>
    psi <j.0.1>
 iota <1.0.1>

Når du har sett på layouten for kataloger og filer i treet ditt, kan du bruke kommandoer som svnlook cat, svnlook propget og svnlook proplist for å grave dypere i detaljene om disse filene og katalogene.

svnlook kan utføre en rekke andre forespørsler, vise delsett av biter av informasjon som vi har nevnt tidligere, rapportere hvilke stier som ble modifisert i en gitt revisjon eller transaksjon, vise tekst- og egenskapsforskjeller gjort med filer og kataloger og så videre. Det følgende er en rask beskrivelse av den nåværende listen med delkommandoer som svnlook aksepterer, og utdataene fra disse delkommandoene:

author

Skriv treets forfatter.

cat

Skriv innholdet av ei fil i treet.

changed

List alle filer og kataloger som forandret seg i treet.

date

Skriv dato og klokkeslett for treet.

diff

Lag unified diff (patch) av forandrede filer.

dirs-changed

List katalogene i treet som enten selv forandret seg, eller der en fil under den forandret seg.

history

Vis interessante punkter i historien for en versjonert sti (steder der modifiseringer eller kopieringer skjedde).

info

Skriv treets forfatter, tidspunkt, antall tegn i loggmeldingen og selve loggmeldingen.

lock

Hvis en sti er låst, beskriv låseattributtene.

log

Vis loggmeldingen for treet.

propget

Skriv verdien for en egenskap på en sti i treet.

proplist

Skriv navnene og verdiene til egenskapene satt på stier i treet.

tree

Skriv en liste over treet, med valgfri visning av filsystemets noderevisions-IDer som er assosiert med hver sti.

uuid

Skriv depotets UUID – Universal Unique IDentifier.

youngest

Skriv det yngste revisjonsnummeret.

svnadmin

Programmet svnadmin er depotadministratorens beste venn. Ved siden av å gi muligheten til å opprette Subversiondepoter, tillater dette programmet deg å utføre flere vedlikeholdsoperasjoner på disse depotene. Syntaksen på svnadmin er lik den i svnlook:

$ svnadmin help
general usage: svnadmin SUBCOMMAND REPOS_PATH  [ARGS & OPTIONS ...]
Type "svnadmin help <subcommand>" for help on a specific subcommand.

Available subcommands:
   create
   deltify
   dump
   help (?, h)
…

Vi har allerede nevnt delkommandoen create i svnadmin (se “Opprettelse og konfigurering av depotet”). De fleste andre vil vi gå grundigere gjennom senere i dette kapitlet. Nå nøyer vi oss med å ta en rask kikk på hva de forskjellige delkommandoene tilbyr.

create

Opprett et nytt Subversiondepot.

deltify

Gå over et spesifisert revisjonsområde og utfør forløper-deltifisering på stiene som forandret seg i disse revisjonene. Hvis ingen revisjoner er spesifisert, vil denne kommandoen rett og slett bare deltifisere HEAD-revisjonen.

dump

Dump innholdet av depotet, begrenset av et spesifisert sett av revisjoner, i et portabelt dumpformat.

hotcopy

Lag en varm kopi av et depot. Du kan kjøre denne kommandoen til enhver tid og lage en trygg kopi av depotet, selv om andre prosesser bruker depotet.

list-dblogs

(Bare Berkeley DB-depot.) List stiene for Berkeley DB-loggfiler assosiert med depotet. Denne listen inkluderer alle loggfiler ― de som fortsatt brukes av Subversion, sammen med de som ikke lenger er i bruk.

list-unused-dblogs

(Bare Berkeley DB-depot.) List stiene for Berkeley DB-loggfiler assosiert med, men ikke lenger brukt av depotet. Du kan trygt fjerne disse loggfilene fra depotet og muligens arkivere dem for senere bruk i tilfelle du en gang får bruk for katastrofe-gjenoppretting av depotet.

load

Last et sett revisjoner inn i et depot fra en strøm av data som bruker det samme portable dumpformatet generert av dump-delkommandoen.

lslocks

List og beskriv enhver lås som eksisterer i depotet.

lstxns

List navnene på Subversiontransaksjonene som ikke er lagt inn, men som eksisterer i depotet.

recover

Utfør gjenoppretting på et depot som trenger det, vanligvis etter at en fatal feil er oppstått som forhindret en prosess fra å lukke kommunikasjonen med depotet på en skikkelig måte.

rmlocks

Fjern låser fra listede stier betingelsesløst.

rmtxns

Fjern Subversiontransaksjoner fra depotet på en renslig måte (kan bruke utdataene fra lstxns-delkommandoen).

setlog

Erstatt den nåværende verdien i svn:log-egenskapen (loggmelding) for en angitt revisjon i depotet med en ny verdi.

verify

Verifiser innholdet i et depot. Dette inkluderer blant annet sjekk av kontrollsummer til de versjonerte dataene som er lagret i depotet.

svndumpfilter

Siden Subversion lagrer alt i et skjult databasesystem, er det å prøve på manuelle forandringer ikke spesielt lurt, for ikke å si vanskelig. Og når dataene er lagret i depotet, har ikke Subversion noen enkel måte å fjerne disse dataene.[29] Men det er ikke til å komme forbi at det er noen ganger du vil manipulere historien til depotet ditt. Det kan være at du vil fjerne alle spor etter ei fil som ble lagt til ved en ulykke (og som av en eller annen grunn ikke skal være der). Eller du har kanskje flere prosjekter som deler et enkelt depot, og du bestemmer deg for å dele dem opp i sine egne depoter. For å utføre oppgaver som dette, trenger administratorer en mer håndterlig og formbar representasjon av dataene i deres egne depot – dumpformatet for Subversiondepot.

Dumpformatet for Subversiondepot er en representasjon av forandringene som du har gjort i dine versjonerte data over tid, i et menneskelig lesbart format. Du bruker kommandoen svnadmin dump for å generere dumpdataene og svnadmin load for å legge disse dataene inn i et nytt depot (se “Flytte et depot”). Den fine tingen med det menneskelesbare dumpformatet er at du kan inspisere og modifisere det hvis du er forsiktig. Selvfølgelig, bakdelen er at hvis du har to år med depotaktivitet pakket inn i en stor dumpfil, vil det ta deg lang, lang tid å manuelt inspisere og modifisere den.

Selv om det ikke vil være det vanligste verktøyet til bruk for depotadministratoren, gir svndumpfilter en veldig spesiell type nyttig funksjonalitet – muligheten til å raskt og enkelt modifisere disse dumpdataene ved å fungere som et stibasert filter. Du gir ganske enkelt programmet en liste over stier som du vil beholde, eller en liste med stier som du vil fjerne, og sender deretter dumpdataene fra depotet via et rør gjennom dette filteret. Resultatet er en modifisert strøm av dumpdata som kun inneholder de versjonerte stiene som du (eksplisitt eller implisitt) ba om.

Syntaksen for svndumpfilter er som følger:

$ svndumpfilter help
general usage: svndumpfilter SUBCOMMAND [ARGS & OPTIONS ...]
Type "svndumpfilter help <subcommand>" for help on a specific subcommand.

Available subcommands:
   exclude
   include
   help (?, h)

Her er det bare to interessante delkommandoer. De gir deg valget mellom eksplisitt eller implisitt inkludering av stier i strømmen:

exclude

Filtrer bort et sett med stier fra dumpdatastrømmen.

include

Tillat bare de angitte stiene å slippe gjennom dumpdatastrømmen.

La oss se på et realistisk eksempel på hvordan du vil bruke dette programmet. Vi diskuterer en annen plass (se “Velge en depot-layout”) prosessen med å bestemme hvordan dataene i depotene dine skal legges opp – om du vil bruke ett depot for hvert prosjekt eller kombinere dem, hvordan du arrangerer ting innenfor depotet og så videre. Men noen ganger etter at nye revisjoner begynner å komme inn, tenker du på nytt over layouten og vil gjøre noen forandringer. En vanlig forandring er å bestemme seg for å flytte flere prosjekter som deler et enkelt depot inn i separate depot for hvert prosjekt.

Vårt hypotetiske depot inneholder tre prosjekter: calc, calendar og spreadsheet. De har levd ved siden av hverandre som følger:

/
   calc/
      trunk/
      branches/
      tags/
   calendar/
      trunk/
      branches/
      tags/
   spreadsheet/
      trunk/
      branches/
      tags/

For å få disse tre prosjektene inn i deres egne depot, dumper vi først hele depotet:

$ svnadmin dump /path/to/repos > depot-dumpfil
* Dumped revision 0.
* Dumped revision 1.
* Dumped revision 2.
* Dumped revision 3.
…
$

Så kjører vi denne dumpfila gjennom filteret og for hver gang inkluderer vi bare en av katalogene på toppnivå, noe som resulterer i tre nye dumpfiler:

$ cat depot-dumpfil | svndumpfilter include calc > calc-dumpfil
…
$ cat depot-dumpfil | svndumpfilter include calendar > cal-dumpfil
…
$ cat depot-dumpfil | svndumpfilter include spreadsheet > ss-dumpfil
…
$

På dette punktet må du ta en avgjørelse. Hver av dumpfilene fine vil lage et gyldig depot, men vil gjenskape stiene nøyaktig som de var i det opprinnelige depotet. Dette betyr at selv om du vil ha et depot kun for calc-prosjektet, vil dette depotet fortsatt ha en toppkatalog kalt calc. Hvis du vil at katalogene trunk, tags og branches skal være i roten av depotet, vil du kanskje ønske å redigere dumpfilene og forandre Node-path og Node-copyfrom-path i headerne så de ikke lengre inneholder denne calc/-komponenten i stien. I tillegg ønsker du å fjerne seksjonen i dumpdataene som oppretter calc-katalogen. Det vil se ut omtrent som dette:

Node-path: calc
Node-action: add
Node-kind: dir
Content-length: 0

[Advarsel]Advarsel

Hvis du planlegger å redigere dumpfila manuelt for å fjerne en toppkatalog, vær sikker på at tekstbehandleren din ikke er satt til å automatisk konvertere linjeslutt til det lokale formatet (det vil si \r\n til \n). Dette vil føre til at innholdet ikke vil samsvare med metadataene og dumpfila vil dermed bli ubrukelig.

Alt som gjenstår nå er å opprette dine tre nye depot og laste hver dumpfil inn i det riktige depotet:

$ svnadmin create calc; svnadmin load calc < calc-dumpfil
<<< Started new transaction, based on original revision 1
     * adding path : Makefile ... done.
     * adding path : button.c ... done.
…
$ svnadmin create calendar; svnadmin load calendar < cal-dumpfil
<<< Started new transaction, based on original revision 1
     * adding path : Makefile ... done.
     * adding path : cal.c ... done.
…
$ svnadmin create spreadsheet; svnadmin load spreadsheet < ss-dumpfil
<<< Started new transaction, based on original revision 1
     * adding path : Makefile ... done.
     * adding path : ss.c ... done.
…
$

Begge delkommandoene til svndumpfilter godtar valg for å bestemme hva de skal gjøre med tomme revisjoner. Hvis en gitt revisjon bare inneholdt forandringer i stier som ble filtrert bort kan denne revisjonen som nå er tom bli betraktet som uinteressant eller til og med uønsket. Så for å gi brukeren kontroll over hva som skal gjøres med disse revisjonene, har svndumpfilter disse kommandolinjevalgene:

--drop-empty-revs

Ikke lag tomme revisjoner i det hele tatt – utelat dem.

--renumber-revs

Hvis tomme revisjoner er droppet (ved bruk av valget --drop-empty-revs), forandres revisjonsnumrene på de gjenværende revisjonene så det ikke blir mellomrom i den numeriske sekvensen.

--preserve-revprops

Hvis tomme revisjoner ikke droppes, ta vare på revisjonsegenskaper (loggmelding, forfatter, dato, egendefinerte egenskaper og så videre) for disse tomme revisjonene. Tomme revisjoner vil ellers bare inneholde det originale tidspunktet og en generert loggmelding som indikerer at denne revisjonen ble tømt av svndumpfilter.

Selv om svndumpfilter kan være veldig nyttig og sparer masse tid, er det dessverre et par ting å passe på. For det første er dette verktøyet overfølsom for sti-semantikk. Legg merke til om stiene i dumpfila er spesifisert med eller uten skråstreker i starten. Dette vil du se i Node-path og Node-copyfrom-path i headerne.

…
Node-path: spreadsheet/Makefile
…

Hvis stiene har innledende skråstreker, skal du også ha innledende skråstreker i stiene som du leverer til svndumpfilter include og svndumpfilter exclude (og hvis de ikke har det, skal du ikke gjøre det). Videre, hvis dumpfila di har inkonsekvent bruk av innledende skråstreker av en eller annen grunn,[30] bør du normalisere disse stiene så de alle enten har eller mangler innledende skråstreker.

I tillegg kan kopierte stier gi deg litt trøbbel. Subversion støtter kopioperasjoner i depotet, der en ny sti blir opprettet ved å kopiere en allerede eksisterende sti. Det er mulig at på et eller annet punkt i livsløpet til depotet blir ei fil eller katalog kopiert fra en plass som svndumpfilter utelater, til en plass som programmet inkluderer. For å gjøre dumpdataene selvforsynt, må svndumpfilter vise tilleggingen av den nye stien – inkludert innholdet av alle filer opprettet av kopieringen – og ikke vise denne tilleggingen som en kopiering fra en kilde som ikke eksisterer i den filtrerte dumpdatastrømmen. Men fordi dumpformatet i Subversion bare viser hva som ble forandret i hver revisjon, kan det være at innholdet i kilden for kopien ikke er tilgjengelig. Hvis du har mistanke om at du har denslags kopier i depotet ditt, vil du kanskje tenke gjennom valget ditt av inkluderte/utelatte stier på nytt.

Berkeley DB-verktøy

Hvis du bruker et Berkeley DB-depot, vil alle strukturer og data være i et sett med databasetabeller i katalogen db i depotet ditt. Denne underkatalogen er en vanlig Berkeley DB miljøkatalog, og kan derfor bli brukt i forbindelse med alle Berkeley databaseverktøy (du kan se dokumentasjonen for disse verktøyene på Sleepycats hjemmeside, http://www.sleepycat.com/).

For daglig Subversionbruk er disse verktøyene unødvendige. Mesteparten av funksjonaliteten som vanligvis er nødvendig for Subversiondepot er blitt duplisert i svnadmin-verktøyet. For eksempel, svnadmin list-unused-dblogs og svnadmin list-dblogs utfører en del av hva Berkeley-kommandoen db_archive gjør, og svnadmin recover gjenspeiler de vanlige bruksmåter for db_recover-programmet.

Det er fortsatt noen få Berkeley DB-programmer som du kan finne nyttige. Programmene db_dump og db_load skriver og leser henholdsvis et tilpasset filformat som beskriver nøkler og verdier i en Berkeley DB-database. Siden Berkeley DB-databaser ikke er portable på tvers av maskinarkitekturer, er dette formatet en nyttig måte å overføre disse databasene fra maskin til maskin, uavhengig av arkitektur eller operativsystem. I tillegg kan programmet db_stat gi deg nyttig informasjon om statusen til Berkeley DB-miljøet, inkludert detaljert statistikk om undersystemer som tar seg av låsing og lagring.

Depotvedlikehold

Subversiondepotet ditt vil vanligvis kreve veldig lite tilsyn når det er konfigurert sånn som du vil ha det. Det er imidlertid enkelte ganger en administrator må trå til med manuell assistanse. Verktøyet svnadmin gir nyttig funksjonalitet for å hjelpe deg med å utføre oppgaver som:

  • modifisere loggmeldinger

  • fjerne døde transaksjoner

  • gjenopprette fastkilte depoter, og

  • flytte depotinnholdet til et annet depot.

Den delkommandoen som kanskje blir brukt mest i svnadmin er setlog. Når en transaksjon er lagt inn i depotet og forfremmet til en revisjon, blir den beskrivende loggmeldingen assosiert med denne nye revisjonen lagret som en uversjonert egenskap vedlagt selve revisjonen. Med andre ord, depotet husker bare den seneste verdien til egenskapen, og forkaster tidligere versjoner.

Noen ganger skjer det at det blir feil i en loggmelding (en skrivefeil eller kanskje noe feilinformasjon). Hvis depotet er satt opp (ved bruk av påhakningene pre-rev-prop-change og post-revprop-change; se “Påhakningsskript”) til å akseptere forandringer i denne loggmeldingen etter at innleggingen er ferdig, kan brukeren fikse loggmeldingen fra en annen maskin ved bruk av svn-programmets propset-kommando (se Kapittel 9, Subversion Complete Reference). Men fordi det her er en potensiell sjanse for å miste informasjon for alltid, er standard oppsett på et Subversiondepot å ikke godta forandringer i uversjonerte egenskaper – unntatt av en administrator.

Hvis en loggmelding må forandres av en administrator, kan dette gjøres ved å bruke svnadmin setlog. Denne kommandoen forandrer loggmeldingen (svn:log-egenskapen) på en gitt revisjoen i et depot, ved å lese den nye verdien fra ei fil.

$ echo "Her er den nye, korrekte loggmeldingen" > nylogg.txt
$ svnadmin setlog mittdepot nylogg.txt -r 388

Kommandoen svnadmin setlog alene er fortsatt bundet av den samme beskyttelsen mot å modifisere uversjonerte egenskaper som en klient på en annen maskin er – påhakningsskriptene pre-revprop-change og post-revprop-change blir fortsatt aktivisert og må derfor settes opp til å godta denne typen forandringer. Men en administrator kan gå rundt denne beskyttelsen ved å angi valget --bypass-hooks til svnadmin setlog-kommandoen.

[Advarsel]Advarsel

Men husk at ved å omgå påhakningsskriptene unngår du også utføring av ting som meldinger via email om forandringer i egenskaper, backupsystemer som følger med på egenskapsforandringer og så videre. Med andre ord, vær meget forsiktig med hva du forandrer og hvordan du forandrer det.

En annen vanlig måte å bruke svnadmin på er å spørre depotet om utestående – muligens døde – Subversiontransaksjoner. Hvis en innlegging feiler, blir transaksjonen vanligvis ryddet opp i. Det vil si, selve transaksjonen blir fjernet fra depotet, og alle dataene assosiert med (og bare med) denne transaksjonen blir fjernet i samme slengen. Men enkelte ganger kan det skje en feil på en måte som gjør at oppryddingen av transaksjonen aldri skjer. Dette kan skje av flere grunner: Kanskje ble klientoperasjonen uelegant avsluttet av brukeren, eller en nettverksfeil kan ha skjedd midt i en operasjon og så videre. Uansett grunnen, døde transaksjoner kan skje. De gjør ingen reell skade utenom å okkupere en liten del av diskplassen, og en pertentlig administrator vil nok ønske å fjerne dem.

Du kan bruke svnadmins lstxns-kommando for å liste navnene på utestående transaksjoner som ligger i depotet for øyeblikket.

$ svnadmin lstxns mittdepot
19
3a1
a45
$

Hvert element i de resulterende utdataene kan deretter bli brukt sammen med svnlook (og dens valg --transaction) for å finne ut hvem som lagde transaksjonen, når den ble laget, hvilke typer forandringer som ble gjort i transaksjonen – med andre ord, om transaksjonen er eller ikke er en trygg kandidat for sletting! Hvis den er det, kan transaksjonens navn leveres til svnadmin rmtxns som vil utføre fjerning av transaksjonen. rmtxns-delkommandoen kan faktisk motta dataene direkte fra det som lstxns genererer!

$ svnadmin rmtxns mittdepot `svnadmin lstxns mittdepot`
$

Hvis du bruker disse to delkommandoene som dette, bør du vurdere å gjøre depotet midlertidig utilgjengelig for klienter. På denne måten kan ingen starte på en legitim transaksjon før du starter på opprenskningen. Det følgende er en skallsnutt som raskt kan generere informasjon om hver utestående transaksjon i depotet ditt:

Eksempel 5.1. txn-info.sh (Rapporterer utestående transaksjoner)

#!/bin/sh

### Generer informasjon om alle utestående transaksjoner i et 
### Subversiondepot.

REPOS="${1}"
if [ "x$REPOS" = x ] ; then
  echo "bruk: $0 STI_TIL_DEPOT"
  exit
fi

for TXN in `svnadmin lstxns ${REPOS}`; do 
  echo "---[ Transaksjon ${TXN} ]-------------------------------------------"
  svnlook info "${REPOS}" --transaction "${TXN}"
done


Du kan kjøre det foregående skriptet ved å bruke /sti/til/txn-info.sh /sti/til/depot. Utdataene er hovedsaklig flere biter av utdataene fra svnlook info som er satt sammen (se “svnlook”), og vil se ut som noe i denne retningen:

$ txn-info.sh mittdepot
---[ Transaksjon 19 ]-------------------------------------------
sally
2001-09-04 11:57:19 -0500 (Tue, 04 Sep 2001)
0
---[ Transaksjon 3a1 ]-------------------------------------------
harry
2001-09-10 16:50:30 -0500 (Mon, 10 Sep 2001)
39
Prøver å legge inn over et skrøpelig nettverk.
---[ Transaksjon a45 ]-------------------------------------------
sally
2001-09-12 11:09:28 -0500 (Wed, 12 Sep 2001)
0
$

En transaksjon som har vært avbrutt over lengre tid representerer vanligvis en feilet eller avbrutt innlegging. Tidspunktet til en transaksjon kan bidra med interessant informasjon – for eksempel, hvor sannsynlig er det at en operasjon som begynte for ni måneder siden fortsatt er aktiv?

Kort sagt er det ikke nødvendig å foreta ukloke beslutninger angående fjerning av transaksjoner. Forskjellige kilder til informasjon – inkludert Apaches feil- og adgangslogg, loggene med gjennomførte Subversioninnlegginger og så videre – kan bli tatt med i beslutningsprosessen. Til sist kan administratoren rett og slett kommunisere med eieren av en tilsynelatende død transaksjon (via email, for eksempel) for å fastslå om transaksjonen faktisk er i en zombietilstand.

Bruken av diskplass

Selv om prisen på datalagring har stupt de siste årene, er bruken av diskplass fortsatt noe administratorer må tenke på hvis de vil versjonere store mengder data. Hver eneste ekstra byte konsumert av det aktive depotet er en byte som må tas backup av utenfor maskinen, kanskje flere ganger som del av roterende backuper. Hvis du bruker et Berkeley DB-depot, er den primære lagringsmekanismen et komplekst databasesystem og det er nyttig å vite hvilke deler av dataene som må forbli på den aktive siten, hvilke som det må tas sikkerhetskopi av, og hva som trygt kan fjernes. Denne seksjonen handler spesifikt om Berkeley DB, FSFS-depot har ingen ekstra data som kan ryddes opp i eller brukes om igjen.

Inntil nylig var de største synderne når det gjelder diskplass som brukes av Subversiondepoter loggfilene der Berkeley DB utfører skrivingen på forhånd før de aktuelle databasefilene modifiseres. Disse filene inneholder alle operasjonene som blir utført når databasen skal forandres fra en tilstand til en annen – mens databasefilene til enhver tid avspeiler en viss tilstand, inneholder loggfilene alle de mange småforandringene langs veien mellom tilstander. Derfor kan de øke i omfang ganske fort.

Heldigvis, fra og med 4.2-versjonen av Berkeley DB har databasemiljøet muligheten til å fjerne sine egne ubrukte loggfiler uten eksterne prosedyrer. Ethvert depot som er laget med en svnadmin som er kompilert mot Berkeley DB 4.2 eller større vil bli konfigurert for denne automatiske slettingen av loggfiler. Hvis du ikke vil ha denne funksjonaliteten aktivisert, kan du ganske enkelt angi valget --bdb-log-keep til svnadmin create-kommandoen. Hvis du glemmer å gjøre dette, eller forandrer mening på et senere tidspunkt, kan du redigere fila DB_CONFIG som ligger i katalogen db i depotet. Du kommenterer bort linjen som inneholder direktivet set_flags DB_LOG_AUTOREMOVE og kjører deretter svnadmin recover på depotet ditt for å aktivisere forandringene i konfigrasjonen. Se “Konfigurasjon av Berkeley DB” for mer informasjon om databasekonfigurasjon.

Uten noen form for automatisk sletting av loggfiler på plass, vil loggfilene samle seg opp etterhvert som du bruker depotet. Dette er faktisk en form for God Ting i databasesystemet – du vil være i stand til å gjenopprette hele databasen ved bruk av loggfilene alene, så disse filene kan være nyttige for gjenoppretting etter en katastrofe. Men vanligvis vil du arkivere loggfilene som ikke lenger er i bruk av Berkeley DB og deretter fjerne dem fra disken for å spare plass. Bruk kommandoen svnadmin list-unused-dblogs for å liste ut de ubrukte loggfilene:

$ svnadmin list-unused-dblogs /sti/til/depot
/sti/til/depot/log.0000000031
/sti/til/depot/log.0000000032
/sti/til/depot/log.0000000033

$ svnadmin list-unused-dblogs /sti/til/depot | xargs rm
## diskplassen er frigjort!

For å holde størrelsen på depotet så liten som mulig, bruker Subversion deltifisering (eller deltifisert lagring) inne i selve depotet. Deltifisering involverer å kode representasjonen av en porsjon data som en samling av forskjeller mot en annen porsjon data. Hvis de to delene med data er veldig like, resulterer denne deltifiseringen i sparing av lagringsplass for den deltifiserte porsjonen – istedenfor å ta opp plass lik størrelsen av de originale dataene, brukes nå nok plass for å si: Jeg ser ut akkurat som de dataene der borte, unntatt de følgende forandringene. Mer spesifikt, hver gang en ny versjon av ei fil blir lagt inn i depotet, koder Subversion den forrige versjonen (egentlig flere tidligere versjoner) som en delta mot den nye versjonen. Resultatet er at mesteparten av depotdataene som har en tendens til å forandre seg i størrelse – innholdet av versjonerte filer – blir lagret med en mye mindre datamengde enn den originale fulltekst-representasjonen av disse dataene.

[Notat]Notat

Fordi alle Subversions depotdata som blir deltifisert blir lagret i en enkelt Berkeley DB-databasefil, vil ikke nødvendigvis det å redusere størrelsen på de lagrede verdiene nødvendigvis redusere størrelsen på selve databasefila. Berkeley DB vil imidlertid ha interne poster med ubrukte områder i databasefila, og vil bruke disse områdene først før den øker størrelsen på databasefila. Så selv om deltifisering ikke medfører øyeblikkelig sparing av diskplass, kan det redusere fremtidig økning i databasestørrelsen ganske drastisk.

Depotgjenoppretting

Som nevnt i “Berkeley DB”, kan et Berkeley DB-depot noen ganger bli etterlatt i en frosset tilstand hvis det ikke blir skikkelig lukket. Når dette skjer, må en administrator rulle databasen tilbake i funksjonell stand.

For å beskytte dataene i depotet ditt, bruker Berkeley DB en låsemekanisme. Denne mekanismen forsikrer at deler av databasen ikke blir oppdatert samtidig av flere sin aksesserer databasen, og at hver prosess ser dataene i den korrekte tilstanden som da disse dataene ble lest fra databasen. Når en prosess må forandre noe i databasen sjekker den først om det eksisterer en lås på måldataene. Hvis dataene ikke er låst, låser denne prosessen dataene, gjør forandringene som den ønsker å gjøre, og låser deretter opp dataene. Andre prosesser blir tvunget til å vente inntil denne låsen er fjernet før de får lov til å fortsette med tilgangen til denne seksjonen av databasen. (Dette har ingenting å gjøre med de låsene som du, brukeren, kan bruke på versjonerte filer i depotet; se Three meanings of lock for mer informasjon.)

Under bruk av Subversiondepotet kan fatale feil (som å gå tom for diskplass eller tilgjengelig hukommelse) eller avbrytelser forhindre en prosess fra å fjerne låsene som den har plassert i databasen. Resultatet er at det bakenforliggende databasesystemet blir fastkilt. Når dette skjer, vil ethvert forsøk på å aksessere depotet henge til evig tid (siden hver ny tilgang vil vente på at en lås skal forsvinne – noe som ikke kommer til å skje).

For det første, hvis dette skjer med depotet ditt, ingen panikk. Berkeley DB-filsystemet benytter seg av databasetransaksjoner og sjekkpunkter og forhåndsskriver journaler for å forsikre at bare de mest katastrofale hendelser[31] kan ødelegge databasen permanent. En tilstrekkelig paranoid depotadministrator vil ta sikkerhetskopier av depotet til en annen maskin på en eller annen måte, men ikke få systemadministratoren din til å hente tilbake det som er på backuptapen helt enda.

For det andre, bruk den følgende oppskriften for å forsøke å fjerne fastkilingen av depotet:

  1. Sjekk at det ikker er noen prosesser som aksesserer (eller forsøker å få tilgang) til depotet. For depot på nettverket betyr dette at Apache HTTP også må kjøres ned.

  2. Bli brukeren som eier og vedlikeholder depotet. Dette er viktig fordi en gjenoppretting av depotet med gal bruker kan forandre rettighetene på filene i depotet så det fortsatt vil være utilgjengelig selv etter at det er reparert.

  3. Kjør kommandoen svnadmin recover /sti/til/depot. Du vil nå se noe i likhet med dette:

    Repository lock acquired.
    Please wait; recovering the repository may take some time...
    
    Recovery completed.
    The latest repos revision is 19.
    

    Denne kommandoen kan ta flere minutter å fullføre.

  4. Start Subversionserveren på nytt.

Denne prosedyren reparerer nesten ethvert tilfelle av låste databaser. Pass på at du kjører denne kommandoen som brukeren som eier og vedlikeholder databasen, ikke bare som root. Deler av gjenopprettingsprosessen kan føre til at diverse databasefiler blir opprettet på nytt (delte områder av hukommelsen, for eksempel). Gjenoppretting som root vil lage disse filene som om de er eid av root, noe som betyr at til og med etter at du setter opp forbindelsen til databasen igjen, klarer ikke vanlige brukere å få tilgang til den.

Hvis den nevnte prosedyren av en eller annen grunn ikke klarer å reparere depotet ditt, skal du gjøre to ting. Først flytter du det ødelagte depotet ut av veien og legger inn den siste sikkerhetskopien av den. Deretter, send en email til Subversionbrukerlisten (på ) der du beskriver problemet i detalj. Dataintegritet har ekstremt høy prioritet for Subversionutviklerne.

Flytte et depot

Et Subversionfilsystem har dataene sine spredt over flere databasetabeller på en måte som generelt bare er forstått av (og som bare har interesse for) selve Subversionutviklerne. Ting kan imidlertid skje som gjør at alt eller litt av disse dataene må samles i et enkeltstående og portabelt flatt filformat. Subversion har en slik mekanisme, implementert som et par svnadmin-delkommandoer: dump og load.

Den vanligste grunnen til å dumpe og laste et Subversiondepot er på grunn av forandringer i selve Subversion. Etterhvert som Subversion modnes, skjer det noen ganger at det blir gjort forandringer i det bakenforliggende databaseoppsettet som fører til at Subversion blir inkompatibel med tidligere versjoner av depotet. Andre grunner for dumping og lasting kan være å flytte et Berkeley DB-depot til et annet operativsystem eller en annen CPU-arkitektur, eller for å bytte mellom Berkeley DB- og FSFS-lagringsformat. Den anbefalte måten å gjøre dette på er relativt enkel:

  1. Bruk din nåværende versjon av svnadmin, dump depotene dine til dumpfiler.

  2. Oppgrader til den nye versjonen av Subversion.

  3. Flytt de gamle depotene ut av veien, og opprett nye på plassen deres ved å bruke den nye versjonen av svnadmin.

  4. Så laster du dumpfilene inn i de respektive nyopprettede depotene ved å bruke den nye versjonen av svnadmin.

  5. Pass på å kopiere alle egne tilpasninger fra de gamle depotene til de nye, inkludert DB_CONFIG-filer og påhakningsskript. Det kan være lurt å lese hva som er forandret i den nye versjonen av Subversion for å se om det er noen forandringer der som gjør at du må gjøre forandringer i påhakningsskriptene eller konfigurasjonen.

  6. Hvis flytteprosessen gjør depotet ditt tilgjengelig på en annen URL (for eksempel flyttet til en annen maskin eller blir aksessert på en annen måte), bør du be alle brukerne dine om å kjøre svn switch --relocate på sine eksisterende arbeidskopier. Se svn switch.

svnadmin dump vil generere utdata med en rekke depotrevisjoner som er i Subversions spesiallagde filsystemdumpformat. Dumpformatet sendes til standard ut-strømmen (stdout), mens informative meldinger sendes til standardfeil-strømmen (stderr). Dette gjør at du kan omdirigere utdatastrømmen til ei fil mens du holder øye med statusen i terminalvinduet.

$ svnlook youngest mittdepot
26
$ svnadmin dump mittdepot > dumpfil
* Dumped revision 0.
* Dumped revision 1.
* Dumped revision 2.
…
* Dumped revision 25.
* Dumped revision 26.

Når denne prosessen er ferdig, vil du ha en enkelt fil (dumpfil i det foregående eksempelet) som inneholder alle dataene som er lagret i depotet ditt i det forespurte området med revisjoner. Legg merke til at svnadmin dump leser revisjonstrær fra depotet akkurat som enhver annen leseprosess ville gjort det (svn checkout, for eksempel), så det er trygt å kjøre denne kommandoen når som helst.

Den andre delkommandoen i dette radarparet, svnadmin load, tolker inndatastrømmen som en Subversiondumpfil og spiller av disse dumpede revisjonene inn i måldepotet for denne operasjonen. Den gir også informativ feedback, denne gangen ved å bruke standard ut-strømmen:

$ svnadmin load newrepos < dumpfile
<<< Started new txn, based on original revision 1
     * adding path : A ... done.
     * adding path : A/B ... done.
     …
------- Committed new rev 1 (loaded from original rev 1) >>>

<<< Started new txn, based on original revision 2
     * editing path : A/mu ... done.
     * editing path : A/D/G/rho ... done.

------- Committed new rev 2 (loaded from original rev 2) >>>

…

<<< Started new txn, based on original revision 25
     * editing path : A/D/gamma ... done.

------- Committed new rev 25 (loaded from original rev 25) >>>

<<< Started new txn, based on original revision 26
     * adding path : A/Z/zeta ... done.
     * editing path : A/mu ... done.

------- Committed new rev 26 (loaded from original rev 26) >>>

Resultatet av en lasting er at nye revisjoner blir lagt til et depot – det samme som skjer når du legger inn revisjoner i depotet fra en vanlig Subversionklient. Og akkurat som i en innlegging kan du bruke påhakningsskript for å utføre oppgaver før og etter hver av innleggingene som blir gjort under en lasteprosess. Ved å angi valgene --use-pre-commit-hook og --use-post-commit-hook sammen med svnadmin load, kan du instruere Subversion til å utføre henholdsvis pre-commit- og post-commit-skriptene for hver lastede revisjon. Du kan for eksempel bruke disse til å forsikre deg om at de lastede revisjonene går gjennom de samme valideringsstegene som vanlige innlegginger går gjennom. Selvfølgelig bør du bruke disse valgene med forsiktighet – hvis post-commit-påhakningen sender epost til en postliste for hver ny revisjon, vil du nok ikke sende ut hundre- eller tusenvis av innleggingsmeldinger i rask rekkefølge til denne listen for hver eneste lastede revisjon! Du kan lese mer om bruken av påhakningsskript i “Påhakningsskript”.

Legg merke til at fordi svnadmin bruker standard inn- og standard ut-strømmer for depotdumpen og lasteprosessen, kan folk som vet hva de driver på med prøve på ting som dette (kanskje til og med bruke forskjellige versjoner av svnadmin på hver side av røret):

$ svnadmin create nyttdepot
$ svnadmin dump mittdepot | svnadmin load nyttdepot

Vanligvis vil dumpfila bli ganske stor – mye større enn selve depotet. Dette er fordi hver eneste versjon av hver fil blir representert som fulltekst i dumpfila. Dette er den raskeste og enkleste oppførselen, og fin hvis du sender dumpdataene gjennom et rør direkte til en annen prosess (som for eksempel et pakkeprogram, filterprogram eller inn i en lasteprosess). Men hvis du lager en dumpfil som er ment for langtidslagring, vil du nok ønske å spare diskplass ved å bruke valget --deltas. Med dette valget vil etterfølgende revisjoner av filer bli generert som pakkede, binære forskjeller – akkurat som filrevisjoner er lagret i et depot. Dette valget er langsommere, men resulterer i en dumpfil mer lik størrelsen til det originale depotet.

Vi nevnte tidligere at svnadmin dump sender en rekke revisjoner til standard ut. Bruk --revision-valget for å spesifisere en enkelt revisjon som skal dumpes, eller et område med revisjoner. Hvis du utelater dette valget, vil alle eksisterende depotrevisjoner bli dumpet.

$ svnadmin dump mittdepot --revision 23 > rev-23.dumpfil
$ svnadmin dump mittdepot --revision 100:200 > rev-100-200.dumpfil

Når Subversion dumper hver ny revisjon, lagres akkurat nok informasjon til at et framtidig lasteprogram kan gjenskape denne revisjonen basert på en tidligere revisjon. Med andre ord, for enhver gitt revisjon i dumpfila vil bare de elementene som ble forandret i den revisjonen havne i dumpen. Det eneste unntaket fra denne regelen er den første revisjonen som blir dumpet med den nåværende svnadmin dump-kommandoen.

Vanligvis vil Subversion ikke uttrykke den første dumpede revisjonen bare som forskjeller som skal legges til den forrige revisjonen. En grunn til dette er at det ikke er noen tidligere revisjon i dumpfila! For det andre kan ikke Subversion vite tilstanden til depotet som dumpdataene vil bli lastet inn i (hvis det i det hele tatt noen gang blir et). For å garantere at utdataene etter hver kjøring av svnadmin dump er selvforsynt, er den første dumpede revisjonen vanligvis en full representasjon av hver katalog, fil og egenskap i denne revisjonen i depotet.

Denne standardoppførselen kan du imidlertid forandre. Hvis du legger til --incremental-valget når du dumper depotet ditt, vil svnadmin sammenligne den første dumpede revisjonen mot den forrige revisjonen i depotet, på den samme måten som den behandler alle andre revisjoner som blir dumpet. Programmet vil deretter generere den første revisjonen nøyaktig som det gjør med resten av revisjonene i dumpområdet – det tar bare med de forandringene som oppsto i den revisjonen. Fordelen med dette er at du kan lage flere små dumpfiler som kan bli lastet etter hverandre istedenfor en stor fil. Dette gjøres på denne måten:

$ svnadmin dump mittdepot --revision 0:1000 > dumpfil1
$ svnadmin dump mittdepot --revision 1001:2000 --incremental > dumpfil2
$ svnadmin dump mittdepot --revision 2001:3000 --incremental > dumpfil3

Disse dumpfilene kan så bli lastet inn i et nytt depot med den følgende kommandosekvensen:

$ svnadmin load nyttdepot < dumpfil1
$ svnadmin load nyttdepot < dumpfil2
$ svnadmin load nyttdepot < dumpfil3

Et annet lurt triks du kan utføre med dette --incremental-valget går ut å legge til en rekke revisjoner til en eksisterende dumpfil. For eksempel kan du ha en post-commit-påhakning som rett og slett legger til depotdumpen av den spesifikke revisjonen som utførte påhakningsskriptet. Eller du kan ha et skript som kjøres om natten for å legge til dumpdata for alle revisjonene som ble lagt til depotet siden forrige gang skriptet ble kjørt. Brukt på denne måten kan dump- og load-kommandoen til svnadmin tilby verdifull hjelp med å ta sikkerhetskopi av forandringer i depotet over tid i tilfelle systemkrasj eller andre katastrofer.

Dumpformatet kan også brukes til å flette innholdet av flere forskjellige depot inn i et enkelt depot. Ved å bruke valget --parent-dir når du kjører svnadmin load, kan du spesifisere en ny virtuell rotkatalog for lasteprosessen. Dette betyr at hvis du har dumpfiler for tre depoter, la oss si tekst-dumpfil, kalender-dumpfil og regneark-dumpfil, kan du først opprette et nytt depot som skal inneholde alle sammen:

$ svnadmin create /sti/til/prosjekter
$

Deretter, lag nye kataloger i depotet som vil pakke inn innholdet av hver av de tre foregående depotene:

$ svn mkdir -m "Opprettet røtter for prosjektene" \
      file:///sti/til/prosjekter/tekst \
      file:///sti/til/prosjekter/kalender \
      file:///sti/til/prosjekter/regneark
Committed revision 1.
$

Til sist, last de individuelle dumpfilene inn i deres respektive plasseringer i det nye depotet:

$ svnadmin load /sti/til/prosjekter --parent-dir tekst < tekst-dumpfil
…
$ svnadmin load /sti/til/prosjekter --parent-dir kalender < kalender-dumpfil
…
$ svnadmin load /sti/til/prosjekter --parent-dir regneark < regneark-dumpfil
…
$

Vi vil nevne en siste måte å bruke depotdumpformatet i Subversion på – konvertering fra en annen lagringsmekanisme eller et annen versjonskontrollsystem. Fordi dumpfilformatet for det meste er lesbart for mennesker,[32] skulle det være relativt enkelt å beskrive generelle sett med forandringer – der hver av dem blir behandlet som en ny revisjon – ved å bruke dette filformatet. Faktisk bruker programmet cvs2svn (se “Konvertere et depot fra CVS til Subversion”) dumpformatet for å representere innholdet i et CVS-depot så dette innholdet kan bli kopiert inn i et Subversiondepot.

Sikkerhetskopi av depotet

Tross utallige forbedringer i teknologien siden den moderne datamaskinen ble født, gjør fortsatt en ting seg sterkt gjeldende – noen ganger går ting forferdelig galt. Strømbrudd, nettverksbrudd, ødelagte minnebrikker og krasjede harddisker er bare en forsmak på ondskapen som Skjebnen er troende til å øse over selv den mest samvittighetsfulle administrator. Vi lander derfor på et meget viktig tema – hvordan du tar sikkerhetskopier av depotdataene dine.

Det er generelt sett to backupmetoder som er tilgjengelig for administratorer av Subversiondepot – inkrementell og fullstendig. Vi diskuterte i en tidligere seksjon i dette kapittelet hvordan svnadmin dump --incremental kan brukes til å utføre en inkrementell backup (se “Flytte et depot”). Essensen i idéen er at på det punktet kopien lages blir kun forandringene i depotet siden forrige backup tatt med.

En fullstendig kopi av depotet er bokstavelig talt en duplisering av hele depotkatalogen (som inkluderer enten en Berkeley-database eller et FSFS-miljø). Hvis du nå tar en kopi uten å midlertidig sperre all tilgang til depotet, vil det å bare ta en rekursiv katalogkopi kanskje føre til at det blir feil i kopien, siden noen kan skrive til databasen på samme tidspunkt.

I tilfellet med Berkeley DB beskriver dokumenter laget av Sleepycat en viss rekkefølge databasefiler kan kopieres i som vil garantere en gyldig sikkerhetskopi. Og en lignende rekkefølge eksisterer for FSFS-data. Enda bedre, du trenger ikke selv å implementere disse algoritmene fordi det er allerede gjort av Subversionutviklerne. Skriptet hot-backup.py ligger i tools/backup/-katalogen i den distribuerte Subversionkildekoden. Ved å gi en depotsti og en backupplassering til hot-backup.py – som egentlig bare er en mer intelligent innpakning rundt svnadmin hotcopy-kommandoen – vil den utføre de nødvendige stegene for å ta backup av det aktive depotet ditt – uten at du må sperre den offentlige tilgangen – og vil deretter rense bort de døde Berkeleyloggfilene fra det aktive depotet.

Selv om du også har en inkrementell backup, vil du sannsynligvis ville kjøre dette programmet med jevne mellomrom. For eksempel vil du kanskje vurdere å legge til hot-backup.py til en automatisk programkjøring (som cron på Unix-systemer). Eller, hvis du foretrekker finjusterte backupløsninger, kan du sette post-commit-skriptet til å kalle hot-backup.py (se “Påhakningsskript”), som vil lage en ny kopi av depotet for hver ny revisjon som er opprettet. Bare legg det følgende inn i hook/post-commit-skriptet i katalogen til det aktive depotet:

(cd /sti/til/påhakningsskript; \
 ./hot-backup.py ${REPOS} /sti/til/sikkerhetskopier &)

Den resulterende backupen er et fullstendig fungerende Subversiondepot som du kan legge inn som en erstatning for det aktive depotet i tilfelle noe skulle gå forferdelig galt.

Det er fordeler med begge backupmetodene. Den letteste er helt klart å ta en full sikkerhetskopi, som alltid vil resultere i en fullstendig funksjonell duplikat av depotet ditt. Dette betyr igjen at hvis noe stygt skulle skje med det aktive depotet, kan du hente det tilbake fra sikkerhetskopien med en enkel rekursiv katalogkopiering. Uheldigvis, hvis du har flere kopier av depotet, vil disse fullstendige kopiene spise opp like mye diskplass som det aktive depotet.

Inkrementelle backuper som bruker depotdumpformatet er utmerket å ha for hånden hvis oppbygningen av databasen forandrer seg mellom versjonene av selve Subversion. Siden en komplett depotdump og depotlasting vanligvis er nødvendig for å oppgradere depotet ditt til det nye formatet, er det veldig enkelt å allerede ha halvparten av denne prosessen (dumpdelen) overstått. Uheldigvis tar opprettelsen av – og gjenoppretting fra – inkrementelle backuper lengre tid, fordi hver innlegging enten blir spilt av inn i dumpfila eller depotet.

I begge disse backupscenariene må depotadminstratorer være oppmerksom på hvordan forandringer i uversjonerte revisjonsegenskaper påvirker sikkerhetskopiene. Siden disse forandringene ikke selv lager nye revisjoner, vil de ikke aktivisere post-commit-påhakninger, og kanskje heller ikke aktivisere pre-revprop-change- og post-revprop-change-skriptene.[33] Og siden du kan forandre revisjonsegenskaper som går på tvers av den kronolgiske rekkefølgen – du kan forandre enhver egenskap for en revisjon når som helst – vil en inkrementell backup av de seneste få revisjonene kanskje ikke fange opp en egenskapsforandring i en revisjon som ble inkludert som del av en tidligere backup.

Vanligvis vil bare den helt paranoide trenge å ta backup av hele depotet, la oss si, hver gang en innlegging skjer. Imidlertid, hvis vi antar at et gitt depot har noen ganske finjusterte mekanismer på plass (som utsending av epost for hver innlegging), vil en varm backup av databasen være noe som en depotadministrator vil ønske å inkludere som del av en nattlig systembackup. For de fleste depot vil arkiverte eposter alene gi nok informasjon som gjenopprettelseskilde, i hvert fall for de siste få innleggingene. Men det er dine data – beskytt dem i den grad du vil.

Ofte er den beste tilnærmingsmåten til kopier av depotet delt. Du kan sette opp kombinasjoner av fullstendige og inkrementelle backuper, pluss et arkiv med innleggingsmeldinger. Subversionutviklerne tar for eksempel backup av kildekodedepotet etter hver ny revisjon som opprettes, og tar vare på et arkiv med alle eposter som varsler om innlegginger og forandringer i revisjoner og egenskaper. Løsningen din kan være noe lignende, men bør tilpasses dine behov og følge den fine linjen mellom bekvemmelighet og paranoia. Og selv om dette ikke vil redde hardwaren din fra Skjebnens jernhånd, vil det helt sikkert hjelpe deg å komme deg på fote igjen etter harde tider som dette.

Legge til prosjekter

Når depotet ditt er opprettet og konfigurert, er alt som gjenstår å begynne å bruke det. Hvis du har en samling med eksisterende data som er klar til å bli plassert under versjonskontroll, vil du mest sannsynlig bruke svn-klientens import-delkommando for å gjøre dette. Men før du setter i gang bør du gå nøye gjennom planene for depotet på lang sikt. I denne seksjonen vil vi gi noen råd om hvordan du planlegger oppbygningen av depotet, og hvordan du får lagt inn dataene dine i dette oppsettet.

Velge en depot-layout

Selv om Subversion lar deg flytte rundt versjonerte filer og kataloger uten tap av informasjon, kan det forstyrre arbeidsflyten til de som ofte aksesserer depotet og forventer at ting er på sine respektive plasser. Prøv å se litt inn i fremtiden; planlegg på forhånd før du plasserer dataene dine under versjonskontroll. Ved å sette opp strukturen på innholdet i depotene dine på en effektiv måte den første gangen, kan du forhindre en drøss med fremtidige hodepiner.

Det er noen få ting å tenke over når du setter opp Subversiondepoter. La oss anta at som depotadministrator, vil du være ansvarlig for å vedlikeholde versjonskontrollsystemet for flere prosjekter. Det første du må bestemme deg for er om du vil bruke et enkelt depot for flere prosjekter, om du vil gi hvert prosjekt sitt eget depot, eller en kombinasjon av disse løsningene.

Det er fordeler med å bruke et enkelt depot for flere prosjekter, først og fremst at du slipper duplisert vedlikehold. Et enkelt depot betyr at det er ett sett med påhakningsskript, én ting å ta backup av, én ting å dumpe og laste hvis Subversion kommer i en ny inkompatibel versjon og så videre. I tillegg kan du lett flytte data mellom prosjekter uten å miste historisk versjonsinformasjon.

Bakdelen med å bruke et enkelt depot er at forskjellige prosjekter kan ha forskjellige postlister eller forskjellige autentiserings- og autorisasjonskrav. Husk også at Subversion bruker globale revisjonsnumre i depotet. Noen liker ikke at selv om ingen forandringer er blitt gjort i deres prosjekt den senere tid, fortsetter likevel det yngste revisjonsnummeret å øke fordi andre prosjekter legger til nye revisjoner.

En kompromissløsning kan også bli brukt. For eksemel kan prosjekter bli gruppert sammen etter hvor relaterte de er til hverandre. Du kan ha noen få depoter med en håndfull prosjekter i hvert av dem. På denne måten kan prosjekter som kan komme til å dele data gjøre dette ganske enkelt, og etterhvert som nye revisjoner blir lagt til depotet, vet utviklerne at disse nye revisjonene ihvertfall er fjernt relaterte på en eller annen måte til alle som bruker dette depotet.

Etter å ha avgjort hvordan du vil organisere prosjektene i henhold til depotene, vil du kanskje tenke over kataloghierarkier i selve depotene. Fordi Subversion bruker vanlige katalogkopier til forgrening og merking (se Kapittel 4, Forgrening og fletting), anbefaler Subversionmiljløet at du velger en katalogplassering for hver prosjektrot – den øverste katalogen som inneholder data relatert til det prosjektet – og deretter oppretter tre kataloger under denne roten: trunk som er katalogen der hovedutviklingen av prosjektet foregår; branches som er en katalog som er ment for å lage diverse navngitte grener av hovedutviklingen; tags som er en katalog av grener som er laget, og kanskje ødelagt, men aldri forandret.[34]

For eksempel kan depotet ditt se ut som dette:

/
   calc/
      trunk/
      tags/
      branches/
   calendar/
      trunk/
      tags/
      branches/
   spreadsheet/
      trunk/
      tags/
      branches/
   …

Legg merke til at det har ingenting å si hvor i depotet hver prosjektrot er. Hvis du har bare ett prosjekt per depot, er den logiske plassen å putte hver prosjektrot i roten av det prosjektets respektive depot. Hvis du har flere prosjekter, vil du kanskje ønske å arrangere dem i grupper innenfor depotet, kanskje legge prosjekter med likelydende mål eller delt kode i den samme underkatalogen, eller kanskje rett og slett gruppere dem alfabetisk. Et slikt system kan se ut som dette:

/
   utils/
      calc/
         trunk/
         tags/
         branches/
      calendar/
         trunk/
         tags/
         branches/
      …
   office/
      spreadsheet/
         trunk/
         tags/
         branches/
      …

Legg opp depotet ditt på den måten du synes passer best. Subversion forventer ikke eller påtvinger deg ikke en spesiell layout – hva Subversion angår, er en katalog en katalog en katalog. Ideelt sett skal du kunne velge det depotoppsettet som fyller behovet til folkene som arbeider på prosjektet som bor der.

Opprette layouten og importere grunndataene

Etter at du har bestemt deg for hvordan du vil arrangere prosjektene i depotet ditt, vil du sannsynligvis ønske å fylle depotet med dette oppsettet og de innledende prosjektdataene. Det er et par måter du kan gjøre dette i Subversion. Du kan bruke svn mkdir-kommandoen (se Kapittel 9, Subversion Complete Reference) for å opprette hver katalog i skjelettet av depotlayouten, en etter en. En raskere måte å utføre den samme oppgaven på er å bruke kommandoen svn import (se svn import). Ved å først opprette layouten i en midlertidig plassering på harddisken, kan du importere hele katalogtreet inn i depotet i en enkelt innlegging:

$ mkdir tmpdir
$ cd tmpdir
$ mkdir prosjektA
$ mkdir prosjektA/trunk
$ mkdir prosjektA/branches
$ mkdir prosjektA/tags
$ mkdir prosjektB
$ mkdir prosjektB/trunk
$ mkdir prosjektB/branches
$ mkdir prosjektB/tags
…
$ svn import . file:///sti/til/depot --message "Innledende oppsett av depotet"
Adding         prosjektA
Adding         prosjektA/trunk
Adding         prosjektA/branches
Adding         prosjektA/tags
Adding         prosjektB
Adding         prosjektB/trunk
Adding         prosjektB/branches
Adding         prosjektB/tags
…
Committed revision 1.
$ cd ..
$ rm -rf tmpdir
$

Du kan kontrollere resultatene etter importen ved å kjøre kommandoen svn list:

$ svn list --verbose file:///sti/til/depot
      1 harry               May 08 21:48 prosjektA/
      1 harry               May 08 21:48 prosjektB/
…
$

Når du har skjelettet til oppsettet på plass, kan du begynne å importere selve prosjektdataene inn i depotet ditt, hvis noen slike data allerede eksisterer. Som sagt, det er flere måter å gjøre dette på. Du kan bruuke svn import-kommandoen. Du kan hente ut en arbeidskopi fra det nye depotet ditt, flytte og arrangere prosjektdataene inne i arbeidskopien og bruke svn add- og svn commit-kommandoene. Men når vi begynner å snakke om slike ting snakker vi ikke lengre om depotadministrasjon. Hvis du ikke allerede er kjent med svn-klientprogrammet, se Kapittel 2, Grunnleggende bruk.

Oppsummering

Nå skal du ha fått en grunnleggende forståelse av hvordan du oppretter, konfigurerer og vedlikeholder Subversiondepoter. Vi har introdusert deg for de forskjellige verktøyene som vil hjelpe deg med denne oppgaven. Gjennom kapittelet har vi gjort oppmerksom på noen feller en administrator kan gå i og hvordan disse fellene kan unngås.

Alt som gjenstår nå er å bestemme hvilke spennende data som du vil lagre i depotet ditt, og til sist, hvordan du vil gjøre det tilgjengelig over nettverket. Det neste kapittelet handler kun om nettverk.




[27] Dette kan høres råflott ut, men vi snakker bare om alle som er interesserte i dette mystiske området hvor alles data ligger.

[28] Uttales fuzz-fuzz, hvis Jack Repenning har noe å si angående det.

[29] Og det er forøvrig en funksjonalitet og ikke en feil.

[30] Selv om svnadmin dump har en konsekvent regel om innledende skråstreker – å ikke inkludere dem – kan det være at andre programmer som genererer dumpdata ikke er like konsekvente.

[31] Som for eksempel: Harddisk + kjempemagnet = krise.

[32] Dumpformatet i Subversion ligner et RFC-882-format, den samme typen format som vanligvis brukes i eposter.

[33] svnadmin setlog kan bli kjørt på en måte som går helt utenom påhakningsgrensesnittet.

[34] Trioen trunk, tags og branches blir noen ganger referert til som TTB-katalogene.

Kapittel 6. Serverkonfigurasjon

Et Subversiondepot kan bli aksessert samtidig av klienter som kjører på den samme maskinen der depotet ligger ved å bruke file:///-metoden. Men det typiske Subversionoppsettet involverer en enkelt servermaskin som blir aksessert fra klienter på maskiner over hele kontoret – eller kanskje over hele verden.

Denne seksjonen beskriver hvordan du kan gjøre Subversiondepotet ditt tilgjengelig utenfra servermaskinen så fjerntliggende klienter kan bruke det. Vi vil dekke servermekanismene som Subversion har tilgjengelig og diskutere konfigurasjonen og bruken av hver av disse. Etter å ha lest denne seksjonen vil du være i stand til å avgjøre hvilket nettverksoppsett som er det riktige for dine behov, og forstå hvordan du skal sette dette opp på servermaskinen.

Oversikt

Subversion ble designet med et abstrakt nettverkslag. Dette betyr at et depot kan bli aksessert av alle typer serverprosesser, og klientens API for depottilgangen gir programmerere anledning til å lage programtillegg som forstår relevante nettverksprotokoller. I teorien kan Subversion bruke et uendelig antall nettverksimplementasjoner. I praksis er det for tiden bare to servermodeller tilgjengelig.

Apache er en ekstremt populær webserver. Ved å bruke mod_dav_svn-modulen kan Apache aksessere et depot og gjøre det tilgjengelig for klienter via WebDAV/DeltaV-protokollen, som er en utvidelse av HTTP. I det andre hjørnet er svnserve: Et lite, enkeltstående serverprogram som kommuniserer med klientene ved hjelp av en egendefinert protokoll. Tabell 6.1, “Sammenligning av nettverksservere” viser en sammenligning av de to servermodellene.

Tabell 6.1. Sammenligning av nettverksservere

FunksjonalitetApache + mod_dav_svnsvnserve
Autentiseringsvalgvanlig HTTP(S)-autentisering, X.509-sertifikater, LDAP, NTLM eller enhver annen mekaniske som er tilgjengelig for Apache httpdCRAM-MD5 eller SSH
Valg for brukerkontoerprivat fil med brukerlisteprivat fil med brukerliste eller eksisterende systemkontoer (SSH)
Authorization optionsread/write access can be granted over whole repository, or specified per-path.read/write access can be granted over whole repository, or specified per-path.
Krypteringvia valgfri SSLvia valgfri SSH-tunnel
Loggingfull Apache logs of each HTTP request, with optional high-level logging of general client operationsno logging
Samspillsevnedelvis brukbar for andre WebDAV-klienterKommuniserer bare med svn-klienter
Visning på webbegrenset innebygget støtte, eller via tredjeparts verktøy som for eksempel ViewVCkun via tredjeparts verktøy som for eksempel ViewVC
HastighetNoe langsommereNoe raskere
Innledende oppsettNoe komplekstGanske enkelt


The Apache HTTP Server

How it works:

Install and configure a standard Apache 2.0 server, then activate a special subversion-server module. Clients speak to server via HTTP or HTTPS, using the WebDAV protocol.

Why you might want to use it:
  • Allows Subversion to use any of the numerous authentication systems already integrated with Apache.

  • No need to create system accounts on server.

  • Full Apache logging.

  • Network traffic can be encrypted via SSL.

  • HTTP(S) can usually go through corporate firewalls.

  • Built-in repository browsing via web browser.

  • Repository can be mounted as a network drive for transparent version control. (See “Autoversioning”.)

Why you might want to avoid it:
  • Noticeably slower than svnserve, because HTTP is a stateless protocol and requires more turnarounds.

  • Initial setup can be complex.

The svnserve Server

How it works:

A lightweight serve process which can run either as a persistent daemon, or as something automatically launched by inetd when necessary. Clients authenticate via CRAM-MD5 algorithm and speak a custom network protocol.

Why you might want to use it:
  • Quick and easy to set up.

  • Network protocol is stateful and noticeably faster than WebDAV.

  • No need to create system accounts on server.

  • Password is not passed over the network.

Why you might want to avoid it:
  • Network protocol is not encrypted.

  • Only one choice of authentication method.

  • Password is stored in the clear on the server.

  • No logging of any kind, not even errors.

svnserve over SSH

How it works:

Each client uses an existing SSH (system) account to spawn a temporary svnserve process (running as themselves) on the server machine. The svnserve process accesses the repository, communicates with the client over the SSH tunnel, then dies when the SSH connection is closed. (There is no long-running svnserve process.)

Why you might want to use it:
  • Network protocol is stateful and noticeably faster than WebDAV.

  • You can take advantage of existing ssh accounts and user infrastructure.

  • All network traffic is encrypted.

Why you might want to avoid it:
  • Only one choice of authentication method.

  • No logging of any kind, not even errors.

  • Requires users to be in same system group, or use a shared ssh key.

  • Can lead to file permissions problems.

Choosing the Best Server Configuration

So, which server should you use? Which is best?

Obviously, there's no right answer to that question. Every team has different needs, and the different servers all represent different sets of tradeoffs. The Subversion project itself doesn't endorse one server or another, or consider either server more official than another.

In general, the authors of this book recommend a vanilla svnserve installation for small teams just trying to get started with a Subversion server; it's the simplest to set up, and has the fewest maintenance issues. Remember, you can always switch to a more complex server deployment as your needs change.

Here are some general recommendations, based on years of supporting users:

  • If you're trying to set up the simplest possible server for your group, then a vanilla svnserve installation is the easiest, fastest route. Note, however, that your repository data will be transmitted in the clear over the network. If your deployment is entirely within your company's LAN or VPN, this isn't an issue. If the repository is exposed to the wide-open internet, then you might want to make sure the repository's contents aren't sensitive (e.g. it contains only open-source code.)

  • If you need to integrate with existing identity systems (LDAP, Active Directory, NTLM, X.509, etc.), then an Apache-based server is your only real option. Similarly, if you absolutely need server-side logs of either server errors or client activities, then an Apache-based server is required.

  • If you've decided to use either Apache or stock svnserve, create a single svn user on your system and run the server process as that user. Be sure to make the repository directory wholly owned by the svn user as well. From a security point of view, this keeps the repository data nicely siloed and protected by operating system filesystem permissions, changeable by only the Subversion server process itself.

  • If you have an existing infrastructure heavily based on SSH accounts, and if your users already have system accounts on your server machine, then it makes sense to deploy an svnserve-over-ssh solution. Otherwise, we don't widely recommend this option to the public. It's generally considered safer to have your users access the repository via (imaginary) accounts managed by svnserve or Apache, rather than by full-blown system accounts. If your deep desire for encrypted communication still draws you to this option, we recommend using Apache with SSL instead.

  • Do not be seduced by the simple idea of having all of your users access a repository directly via file:/// URLs. Even if the repository is readily available to everyone via network share, this is a bad idea. It removes any layers of protection between the users and the repository: users can accidentally (or intentionally) corrupt the repository database, it becomes hard to take the repository offline for inspection or upgrade, and it can lead to a mess of file-permissions problems (see “Støtte for flere metoder for tilgang til depotet”.) Note that this is also one of the reasons we warn against accessing repositories via svn+ssh:// URLs — from a security standpoint, it's effectively the same as local users accessing via file:///, and can entail all the same problems if the administrator isn't careful.

svnserve, en tilpasset server

Programmet svnserve er en lettvektsserver som er i stand til å snakke med klienter over TCP/IP ved å bruke en tilpasset, stateful protokoll. Klienter kontakter en svnserve-server ved å bruke URL-er som begynner med svn://- eller svn+ssh://-skjemaet. Denne seksjonen vil forklare de forskjellige måtene å kjøre svnserve på, hvordan klienter autentiserer seg selv ovenfor serveren, og hvordan du setter opp en passende adgangskontroll til depotene dine.

Starte serveren

There are a few different ways to run the svnserve program:

  • Run svnserve as a standalone daemon, listening for requests.

  • Have the Unix inetd daemon temporarily spawn svnserve whenever a request comes in on a certain port.

  • Have SSH invoke a temporary svnserve over an encrypted tunnel.

  • Run svnserve as a Windows service.

svnserve as Daemon

The easiest option is to run svnserve as a standalone daemon process. Use the -d option for this:

$ svnserve -d
$               # svnserve is now running, listening on port 3690

Når svnserve kjøres i daemon-modus, kan du bruke valgene --listen-port= og --listen-host= for å sette den eksakte porten og servernavn som den skal bindes til:

Når svnserve-programmet kjører, gjør det alle depotene på systemet tilgjengelig på nettverket. En klient må spesifisere en absolutt sti i depot-URLen. Hvis for eksempel et depot ligger i /usr/local/depoter/prosjekt1, kan en klient nå det via svn://server.example.com/usr/local/depoter/prosjekt1. For å øke sikkerheten kan du angi -r-valget til svnserve som begrenser den til å kun ekportere depoter som ligger under denne stien. For eksempel:

$ svnserve -d -r /usr/local/depot
…

Bruken av -r-valget forandrer plasseringen av roten som programmet bruker på det fjerntliggende filsystemet. Klienter bruker dermed URLer som har fjernet denne delen av stien, noe som gir mye kortere (og mindre avslørende) URLer:

$ svn checkout svn://server.example.com/prosjekt1
…

svnserve via inetd

If you want inetd launch the process, then you can pass the -i (--inetd) option:

$ svnserve -i
( success ( 1 2 ( ANONYMOUS ) ( edit-pipeline ) ) )

Når programmet blir startet med --inetd-valget, prøver svnserve å snakke med en Subversionklient via standard inn og standard ut ved å bruke en tilpasset protokoll. Dette er den vanlige oppførselen for et program som blir kjørt via inetd. IANA har reservert port 3690 for Subversionprotokollen, så på et Unix-lignende system kan du legge til linjer som dette i /etc/services (hvis de ikke allerede eksisterer):

svn           3690/tcp   # Subversion
svn           3690/udp   # Subversion

Og hvis systemet ditt bruker en klassisk Unix-lignende inetd-daemon, kan du legge denne linjen til /etc/inetd.conf:

svn stream tcp nowait svnbruker /usr/bin/svnserve svnserve -i

Pass på at svnbruker er en bruker som har tilstrekkelige rettigheter til å få tilgang til depotene dine. Når nå en klientforbindelse kommer inn til serveren på port 3690, vil inetd starte en egen svnserve-prosess for å ta seg av den. Du vil selvfølgelig også ønske å legge til -r til konfigurasjonslinja også, for å begrense hvilke depot som eksporteres.

svnserve i en tunnel

En tredje måte å starte svnserve på, er i tunnelmodus, med valget -t. Denne modusen forutsetter at et fjerntjenesteprogram som RSH eller SSH har klart å autentisere som en bruker og nå skal starte en privat svnserve-prosess som denne brukeren. svnserve-programmet oppfører seg normalt (kommuniserer via standard inn og standard ut), og går ut i fra at trafikken blir automatisk omdirigert gjennom en form for tunnel tilbake til klienten. Når svnserve blir startet av en tunnelagent som dette, pass på at den autentiserte brukeren har full skrive- og leseaksess til databasefilene i depotet. Det er hovedsaklig det samme prinsippet som når en lokal bruker får tilgang til depotet via file:///-URLer.

This option is described in much more detail in “Autentisering og autorisasjon via SSH”.

svnserve as Windows Service

If your Windows system is a descendant of Windows NT (2000, 2003, XP, Vista), then you can run svnserve as a standard Windows service. You'll need to define the service using a command-line tool SC.EXE. Much like the inetd configuration line, you must specify an exact invocation of svnserve for Windows to run at start-up time:

C:\> sc create svn
        binpath= "C:\svn\bin\svnserve.exe --service [args]"
        displayname= "Subversion Server"
        depend= Tcpip
        start= auto

This defines a new Windows service named svn, and which executes a particular svnserve.exe command when started. There are a number of caveats in the prior example, however.

First, notice that the svnserve.exe program is always invoked with the --service option. You must always specify this option, and you may not specify other conflicting options such as --daemon, --tunnel, or --inetd. Options such as -r or --listen-port are fine. Second, be careful about spaces when invoking the SC.EXE command: the key= value patterns must have no spaces between key= and exactly one space before the value. Lastly, be careful about spaces in your command-line to be invoked. If a directory name contains spaces (or other characters that need escaping), place the entire inner value of binpath in double-quotes, by escaping them:

C:\> sc create svn
        binpath= "\"C:\program files\svn\bin\svnserve.exe\" --service [args]"
        displayname= "Subversion Server"
        depend= Tcpip
        start= auto

Once the service is defined, it can stopped, started, or queried using standard GUI tools (The Services administrative control panel), or at the command line as well:

C:\> net stop svn
C:\> net start svn

The service can also be uninstalled (i.e. undefined) by deleting its definition: sc delete svn. Just be sure to stop the service first! The SC.EXE program has many other subcommands and options, run sc /? to learn more about it.

Innebygget autentisering og autorisasjon

Når en klient kobler seg til en svnserve-prosess, skjer de følgende tingene:

  • Klienten velger et spesifikt depot.

  • Serveren går gjennom depotets conf/svnserve.conf-fil og begynner å gjennomføre alle autentiserings- og autorisasjonsregler som er definert i den.

  • Avhengig av situasjonen og autorisasjonsreglene,

    • kan klienten få lov til å foreta forespørsler anonymt, uten noen gang å motta en autentiseringsforespørsel, ELLER

    • klienten kan bli spurt etter autentiseringsinfo til enhver tid, ELLER

    • hvis den opererer i tunnelmodus, vil klienten erklære seg selv som å allerede være eksternt autentisert.

Når dette skrives, vet serveren bare hvordan den skal sende en CRAM-MD5[35]-autentiseringsforespørsel. I hovedsak sender serveren litt data til klienten. Klienten bruker MD5-algoritmen for å lage et fingeravtrykk av de kombinerte dataene og passordet og sender fingeravtrykket som svar. Serveren foretar den samme utregningen med det lagrede passordet for å sjekke at resultatet er identisk. Passordet blir ikke på noe tidspunkt sendt over nettverket.

Det er også selvfølgelig mulig for klienten å bli eksternt autentisert via en tunnelagent, som for eksempel SSH. I dette tilfellet sjekker serveren rett og slett bare brukeren den kjører som, og bruker den som det autentiserte brukernavnet. For mer om dette, se “Autentisering og autorisasjon via SSH”.

Som du allerede har gjettet, er svnserve.conf-fila i et depot den sentrale mekanismen for å kontrollere autentiserings- og autorisasjonsregler. Fila har det samme formatet som andre konfigurasjonsfiler (se “Konfigurasjonsområdet for bruk under kjøring”): Seksjonsnavn er markert med klammeparenteser ([ og ]), kommentarer begynner med hashtegn (#), og hver seksjon inneholder spesifikke variabler som kan settes (variabel = verdi). La oss gå gjennom denne fila og lære hvordan vi bruker dem.

Opprette en brukerfil og område

For øyeblikket har [general]-seksjonen i svnserve.conf alle variablene som du trenger. Start ved å definere en fil som inneholder brukernavn og passord, og et autentiseringsområde:

[general]
password-db = brukerfil
realm = eksempelområde

realm er et navn som du definerer. Det forteller klienter hvilket autentiseringsnavnerom de kobler seg til; Subversionklienten viser det når den spør etter autentiseringsinfo, og bruker det som en nøkkel (sammen med serverens vertsnavn og port) for å lagre legitimasjonsinfo på disken (se “Lagring av klientlegitimasjon”). Variabelen password-db peker til en separat fil som inneholder en liste med brukernavn og passord, som bruker det samme kjente formatet. For eksempel:

[users]
harry = foopassord
sally = barpassord

Verdien i password-db kan være en absolutt eller relativ sti til brukerfila. For mange administratorer er det enkelt å lagre fila i conf/-området i depotet, sammen med svnserve.conf. På den annen side er det mulig at du vil ha to eller flere depoter som deler den samme brukerfila; i så tilfelle bør fila kanskje ligge på en mer offentlig plass. Depotene som deler brukerfila bør også settes opp til å ha samme område (realm) siden brukerlista hovedsaklig definerer et autentiseringsområde. Hvor fila enn ligger, pass på å sette lese- og skriverettighetene på den. Hvis du vet hvilke(n) bruker(e) svnserve vil kjøre som, begrens lesetilgangen til brukerfila etter hva som er nødvendig.

Sette tilgangskontroll

Det er to variabler til som må settes i svnserve.conf-fila, de avgjør hva uautentiserte (anonyme) og autentiserte brukere får lov til å gjøre. Variablene anon-access og auth-access kan settes til verdiene none, read eller write. Ved å sette verdien til none begrenses alle typer tilganger; read tillater bare lesing fra depotet, og write gir fullstendig lese/skrive-tilgang til depotet. For eksempel:

[general]
password-db = userfile
realm = example realm

# anonyme brukere kan bare lese depotet
anon-access = read

# autentiserte brukere kan både lese og skrive
auth-access = write

Oppsettet i dette eksempelet viser standardverdiene som variablene har, i tilfelle du glemmer å definere dem. Hvis du vil være enda mer konservativ, kan du blokkere anonym tilgang fullstendig:

[general]
password-db = brukerfil
realm = eksempelområde

# anonyme brukere forbudt
anon-access = none

# autentiserte brukere kan både lese og skrive
auth-access = write

The server process not only understands these blanket access controls to the repository, but also finer-grained access restrictions placed on specific files and directories within the repository. To make use of this feature, you need to define a file containing more detailed rules, and then set the authz-db variable to point to it:

[general]
password-db = userfile
realm = example realm

# Specific access rules for specific locations
authz-db = authzfile

The syntax of the authzfile file is discussed in detail in “Path-Based Authorization”. Note that the authz-db variable isn't mutually exclusive with the anon-access and auth-access variables; if all the variables are defined at once, then all of the rules must be satisfied before access is allowed.

Autentisering og autorisasjon via SSH

svnserves innebyggede autentisering kan være veldig grei å ha med å gjøre, fordi man ikke trenger å opprette virkelige brukerkontoer på systemet. På den annen side har noen administratorer allerede et veletablert rammeverk for SSH-autentisering på plass. I disse situasjonene har alle brukerne på prosjektet allerede systemkontoer og muligheten til å koble seg til via SSH på servermaskinen.

Det er enkelt å bruke SSH sammen med svnserve. Klienten bruker ganske enkelt URL-skjemaet svn+ssh:// for å koble seg til:

$ whoami
harry

$ svn list svn+ssh://server.example.com/repos/prosjekt
harry@server.example.com's password:  *****

foo
bar
baz
…

I dette eksempelet starter Subversionklienten en lokal ssh-prosess, kobler seg opp mot server.example.com, autentiserer seg som brukeren harry, starter en privat svnserve-prosess på den fjerntliggende maskinen som kjører som brukeren harry. svnserve-kommandoen blir startet i tunnelmodus (-t) og nettverksprotokollen som den bruker blir lagt i tunnel over den krypterte forbindelsen via ssh, tunnelagenten. svnserve vet at den kjører som brukeren harry, og hvis klienten foretar en innlegging, vil det autentiserte brukernavnet bli kreditert som forfatteren av den nye revisjonen.

Den viktige tingen å forstå her er at Subversionklienten ikke kobler seg til en kjørende svnserve-daemon. Denne tilkoblingsmetoden krever ingen daemon, og den legger heller ikke merke til om noen slike finnes. Den stoler fullt og helt på evnen til ssh å starte en midlertidig svnserve-prosess, som avsluttes når nettverksforbindelsen lukkes.

Når du bruker svn+ssh://-URLer til å aksessere et depot, husk at det er ssh-programmet som spør etter autentisering, og ikke svn-klienten. Dette betyr at det er ingen automatisk lagring av passord (se “Lagring av klientlegitimasjon”). Subversionklienten foretar ofte flere tilkoblinger til depotet, selv om brukere vanligvis ikke legger merke til dette på grunn av funksjonen som lagrer passord. Men ved bruk av svn+ssh:// kan brukere bli plaget med at ssh spør etter passord for hver eneste utgående tilkobling. Løsningen er å bruke et separat passordlagringssystem for SSH som for eksempel ssh-agent på et Unix-lignende system eller pageant i Windows.

Når tilkobling skjer gjennom en tunnel, blir autorisering for databasefilene i depotet hovedsaklig kontrollert av tilgangsrettigheter i operativsystemet; det er mye det samme som om Harry aksesserer depotet direkte via en file:///-URL. Hvis flere systembrukere skal aksessere depotet direkte, vil du kanskje plassere dem i en felles gruppe, og alt du trenger å tenke på er å være forsiktig med umask. (Pass på å lese “Støtte for flere metoder for tilgang til depotet”.) Men selv i tilfellet med bruk av tunnel kan svnserve.conf bli brukt til å blokkere tilgang ved å sette auth-access = read eller auth-access = none.[36]

Man skulle tro at historien om SSH ender her, men det gjør den ikke. Subversion lar deg opprette tilpasset tunneloppførsel i kjøringsfila config (se “Konfigurasjonsområdet for bruk under kjøring”). I [tunnels]-seksjonen i config-fila kan du enkelt definere det på denne måten:

[tunnels]
rsh = rsh

Og nå kan du bruke denne nye tunneldefinsjonen ved å bruke et URL-skjema som samsvarer med navnet på den nye variabelen: svn+rsh://server/sti. Ved bruk av det nye URL-skjemaet vil Subversionklienten faktisk kjøre kommandoen rsh server svnserve -t i bakgrunnen. Hvis du inkluderer et brukernavn i URLen (for eksempel svn+rsh://brukernavn@server/sti), vil klienten også ta dette med i kommandoen (rsh brukernavn@server svnserve -t). Men du kan definere nye tunnelskjema til å være mye mer avanserte enn som så:

[tunnels]
joessh = $JOESSH /opt/alternate/ssh -p 29934

Dette eksempelet demonstrerer et par ting. For det første viser det hvordan du lar Subversionklienten kjøre en spesifikk binærfil som oppretter tunnelen (den som ligger som /opt/alternate/ssh med spesifikke valg. I dette tilfellet vil det å aksessere en svn+joessh://-URL starte denne SSH-binærfila med -p 29934 som parameter – nyttig hvis du vil at tunnelprogrammet skal koble seg til en ustandard port.

For det andre viser det hvordan en tilpasset miljøvariabel kan overstyre navnet på et tunnelprogram. Det å sette miljøvariabelen SVN_SSH er en behagelig måte å overstyre den vanlige SSH-tunnelagenten. Men hvis du må ha flere forskjellige overstyringer for forskjellige servere, der hver av dem kanskje kontakter en forskjellig port eller sender et annet sett med parametere til SSH, kan du bruke mekanismen som er demonstrert i dette eksempelet. Hvis vi nå setter miljøvariabelen JOESSH til noe, vil innholdet av denne variabelen overstyre hele innholdet av tunnelvariabelen – $JOESSH vil bli kjørt istedenfor /opt/alternate/ssh -p 29934.

Konfigurasjonstriks i SSH

Det er ikke bare mulig å kontrollere måten klienten starter ssh på, men også å kontrollere oppførselen til sshd på servermaskinen. I denne seksjonen vil vi vise hvordan du kontrollerer den eksakte svnserve-kommandoen som blir kjørt av sshd, og også hvordan du får flere brukere til å dele en enkel systemkonto.

Innledende oppsett

Til å begynne med, finn fram til hjemmekatalogen for kontoen som du skal bruke til å kjøre svnserve. Vær sikker på at kontoen har et offentlig/privat SSH-nøkkelpar installert, og at brukeren kan logge inn via autentisering med offentlig nøkkel. Autentisering via passord vil ikke fungere, siden alle de følgende SSH-triksene baserer seg på bruk av authorized_keys-fila som brukes av SSH.

Hvis den ikke allerede finnes, opprett fila authorized_keys (i Unix er den vanligvis kalt ~/.ssh/authorized_keys). Hver linje i denne fila beskriver en offentlig nøkkel som får lov til å koble seg til. Linjene har vanligvis dette formatet:

  ssh-dsa AAAABtce9euch… bruker@example.com

Det første feltet beskriver nøkkeltypen, det andre feltet er selve den uuencodede nøkkelen, og det tredje feltet er en kommentar. En lite kjent funksjonalitet er at hele linjen kan bli innledet av et command-felt:

  command="program" ssh-dsa AAAABtce9euch… bruker@example.com

Når command-feltet er definert, vil SSH-daemonen kjøre det navngitte programmet istedenfor den typiske svnserve -t-prosessen som Subversionklienten spør etter. Dette åpner døra til en rekke triks på serversiden. I de følgende eksemplene forkorter vi linjene i fila som:

  command="program" TYPE NØKKEL KOMMENTAR

Kontrollere den startede kommandoen

Fordi vi kan spesifisere kommandoen som kjøres på serversiden, er det lett å navngi en spesifikk svnserve-binærfil som skal kjøres og levere et ekstra parameter til den:

  command="/sti/til/svnserve -t -r /virtuell/rot" TYPE NØKKEL KOMMENTAR

I dette eksempelet kan /sti/til/svnserve være et spesiallaget innkapslingsskript rundt svnserve som setter umask-verdien (se “Støtte for flere metoder for tilgang til depotet”). Det viser også hvordan svnserve kan forankres i en virtuell rotkatalog akkurat som man ofte gjør når svnserve kjøres som en daemonprosess. Dette kan gjøres enten ved å begrense adgangen til deler av systemet, eller ganske enkelt spare brukeren for å måtte skrive inn en absolutt sti i svn+ssh://-URLen.

Det er også mulig å la flere brukere dele en enkel konto. Istedenfor å lage en egen systemkonto for hver bruker, lag et offentlig/privat nøkkelpar for hver person. Legg deretter hver offentlig nøkkel inn i authorized_users-fila, en per linje, og bruk valget --tunnel-user:

  command="svnserve -t --tunnel-user=harry" TYPE1 NØKKEL1 harry@example.com
  command="svnserve -t --tunnel-user=sally" TYPE2 NØKKEL2 sally@example.com

Dette eksempelet lar både Harry og Sally få koble seg til den samme kontoen via offentlig nøkkel-autentisering. Hver av dem har en spesiallaget kommando som vil bli kjørt; valget --tunnel-user ber svnserve -t om å gå ut i fra at den spesifiserte verdien er den autentiserte brukeren. Uten --tunnel-user vil det se ut som om alle innlegginger kommer fra en delt systemkonto.

En siste advarsel: Det å gi en bruker tilgang til serveren via en offentlig nøkkel på en delt konto kan fortsatt gi andre former for SSH-tilgang, selv om du har definert command-verdien i authorized_keys. Brukeren kan for eksempel fortsatt få kommandolinjetilgang via SSH, eller være i stand til å utføre X11- eller generell port-forwarding gjennom serveren. For å gi brukeren så lite rettigheter som mulig, vil du kanskje spesifisere et antall begrensningsvalg like etter command:

  command="svnserve -t --tunnel-user=harry",no-port-forwarding,\
           no-agent-forwarding,no-X11-forwarding,no-pty \
           TYPE1 NØKKEL1 harry@example.com

HTTP-serveren Apache (httpd)

HTTP-serveren Apache er en nettverksserver i tungvektsklassen som Subversion kan bruke. Ved hjelp av en spesiallaget modul gjør httpd Subversiondepoter tilgjengelig for klienter via WebDAV/DeltaV-protokollen, som er en utvidelse av HTTP 1.1 (se http://www.webdav.org/ for mer informasjon). Denne protokollen tar HTTP-protokollen som vi finner over alt, kjernen av World Wide Web, og legger til muligheter for skriving – mer spesifikt, versjonert skriving. Resultatet er et standardisert, robust system som går godt sammen med Apache 2.0-programvaren, støttet av et stort antall operativsystemer og tredjeparts programvare. Og systemadministratorer trenger ikke å åpne enda en port på systemet.[37] En Apache/Subversion-server har større funksjonalitet enn svnserve, men er også vanskeligere å sette opp. Med fleksibilitet kommer det ofte mer kompleksitet med på kjøpet.

Mye av den følgende diskusjonen inneholder referanser til konfigurasjonsdirektiver for Apache. Selv om noen eksempler inneholder bruk av disse direktivene, er det å beskrive dem i full detalj utenfor det som dette kapittelet dekker. Utviklerne bak Apache vedlikeholder fortreffelig dokumentasjon, offentlig tilgjengelig på hjemmesiden http://httpd.apache.org. En generell oversikt over konfigurasjonsdirektivene er for eksempel tilgjengelig på http://httpd.apache.org/docs-2.0/mod/directives.html.

I tillegg, etter hvert som du gjør forandringer til Apacheoppsettet, kan det skje at en feil blir gjort på veien. Hvis du ikke allerede kjenner til Apaches loggesystem, bør du bli kjent med det. I httpd.conf-fila di er det direktiver som spesifiserer plasseringer på disken av aksess- og feilmeldingsloggene som genereres av Apache (henholdsvis direktivene CustomLog og ErrorLog). Subversions mod_dav_svn bruker også Apaches logging av feilmeldinger. Du kan alltids gå gjennom innholdet av disse filene etter informasjon som kan vise kilden til et problem som ellers ikke er lett å få øye på.

Systemkrav

For å få depotet ditt på nettverk over HTTP, trenger du hovedsaklig fire komponenter, tilgjengelig i to pakker. Du trenger Apache httpd 2.0, DAV-modulen mod_dav som følger med Apache, Subversion og filsystemmodulen mod_dav_svn som kommer sammen med Subversion. Når du har alle disse komponentene er prosessen å få depotet på nett så enkel som å:

  • få httpd 2.0 opp og kjøre med mod_dav-modulen,

  • installere programtillegget mod_dav_svn til mod_dav, som bruker Subversions biblioteker til å aksessere depotet, og

  • konfigurere httpd.conf-fila di til å eksportere (eller vise) depotet.

Du kan sette opp de første to elementene enten ved å kompilere httpd og Subversion fra kildekode eller ved å installere ferdigbygde pakker med dem på systemet. For den mest oppdaterte informasjonen om hvordan du kompilerer Subversion for bruk sammen med Apache HTTP-serveren og hvordan kompilere og sette opp selve Apache for dette, se INSTALL-fila på toppnivået av kildekodetreet til Subversion.

Grunnleggende oppsett av Apache

Når du har alle de nødvendige komponentene installert på systemet ditt, er alt som gjenstår å konfigurere Apache ved hjelp av httpd.conf-fila. Få Apache til å laste mod_dav_svn-modulen ved å bruke LoadModule-direktivet. Dette direktivet må komme foran alle andre Subversion-relaterte elementer. Hvis Apache ble installert med standard filplasseringer, er mod_dav_svn-modulen plassert i modules-katalogen der Apache er installert (ofte /usr/local/apache2). LoadModule-direktivet har en enkel syntaks som kobler en navngitt modul til plasseringen av et delt bibliotek på disken:

LoadModule dav_svn_module     modules/mod_dav_svn.so

Legg merke til at hvis mod_dav ble kompilert som et delt objekt (istedenfor å bli statisk linket direkte til binærfila httpd) vil du også trenge en tilsvarende LoadModule-linje for dette. Pass på at den kommer før mod_dav_svn-linjen:

LoadModule dav_module         modules/mod_dav.so
LoadModule dav_svn_module     modules/mod_dav_svn.so

På en senere plassering i konfigurasjonsfila må du fortelle Apache hvor du har lagt Subversiondepotet (eller depotene). Location-direktivet har en XML-lignende notasjon som starter med et åpningselement og slutter med et sluttelement med diverse andre konfigurasjonsdirektiver i midten. Formålet med Location-direktivet er å instruere Apache til å gjøre noe spesielt når den behandler forespørsler som går til en gitt URL eller et av dens barn. I tilfellet med Subversion vil du at Apache gir støtte for URLer som peker til en versjonert ressurs i DAV-laget. Du kan instruere Apache til å delegere håndteringen av alle URLer der en del av stien (den delen av URLen som kommer etter servernavnet og det valgfrie portnummeret) som begynner med /repos/ til en DAV-tjeneste som har depotet plassert som /absolutt/sti/til/depotet ved å bruke den følgende httpd.conf-syntaksen:

<Location /repos>
  DAV svn
  SVNPath /absolutt/sti/til/depotet
</Location>

Hvis du planlegger å ha flere Subversiondepoter som vil ligge i den samme foreldrekatalogen på en lokal disk, kan du bruke et alternativt direktiv, SVNParentPath-direktivet, for å indikere denne felles foreldrekatalogen. Hvis du for eksempel vet at du vil opprette flere Subversiondepoter i katalogen /usr/local/svn som vil bli aksessert vie URLer som http://min.server.com/svn/depot1, http://min.server.com/svn/depot2 og så videre, kan du bruke httpd.conf-konfigurasjonssyntaksen i det følgende eksempelet:

<Location /svn>
  DAV svn

  # alle "/svn/foo"-URLer vil kobles til katalogen /usr/local/svn/foo
  SVNParentPath /usr/local/svn
</Location>

Ved å bruke den foregående syntaksen vil Apache delegere håndteringen av alle URLer der stien begynner med /svn/ til DAV-tjenesten for Subversion som deretter vil gå ut i fra at alle elementer i katalogen spesifisert med SVNParentPath-direktivet faktisk er Subversiondepoter. Dette er en spesielt lettvint syntaks fordi i motsetning til bruken av SVNPath-direktivet trenger du ikke å starte Apache på nytt for å opprette nye depoter og få dem på nett.

Pass på at den nye Location-defineringen ikke overlapper med andre eksporterte plasseringer. For eksempel, hvis hovedplasseringen av DocumentRoot eksporteres til /www, ikke eksporter et Subversiondepot med <Location /www/repos>. Hvis en forespørsel kommer for URIen /www/repos/foo.c, vet ikke Apache om den skal se etter fila repos/foo.c i DocumentRoot eller om den skal delegere jobben til mod_dav_svn for å returnere foo.c fra Subversiondepotet.

På dette steget bør du sterkt vurdere spørsmålet angående rettigheter. Hvis du har kjørt Apache en stund som din vanlige webserver, har du sannsynligvis en samling med innhold – hjemmesider, skript og lignende. Disse elementene er allerede blitt satt opp med et sett rettigheter som gjør at de fungerer med Apache, eller rettere sagt, som gjør at Apache virker med disse filene. Når Apache brukes som en Subversionserver vil den også trenge de riktige rettighetene for å lese og skrive til Subversiondepotet.

Du må finne fram til et oppsett for rettighetssystemet som tilfredsstiller Subversions krav uten å rote til noen av de nettsidene eller skriptene som er installert fra før. Dette kan bety å forandre rettighetene på Subversiondepotet til å samsvare med de som brukes av andre ting som Apache håndterer for deg, eller det kan innebære å bruke direktivene User og Group i httpd.conf for å spesifisere at Apache må kjøre som den brukeren og gruppen som eier Subversiondepotet. Det er ingen enkelt universalløsning for å sette opp rettighetene, og hver administrator vil ha forskjellige grunner for å gjøre ting på en spesiell måte. Bare husk at rettighetsrelaterte problemer kanskje er det som oftest blir oversett når et Subversiondepot settes opp for bruk med Apache.

Autentiseringsvalg

På dette punktet, hvis du satte opp httpd.conf til å inneholde noe som

<Location /svn>
  DAV svn
  SVNParentPath /usr/local/svn
</Location>

…er depotet ditt anonymt tilgjengelig for hele verden. Inntil du setter opp regler for autentisering og autorisasjon, vil Subversiondepotene som du gjør tilgjengelig via Location-direktivet generelt være tilgjengelig for alle. Med andre ord,

  • alle kan bruke Subversionklienten sin til å hente ut e arbeidskopi av en URL i depotet (eller enhver underkatalog under det),

  • alle kan interaktivt bla igjennom depotets seneste revisjon ved å bare gå til depot-URLen med nettleseren, og

  • alle kan foreta innlegginger i depotet.

Enkel HTTP-autentisering

Den enkleste måten å autentisere en klient er via den grunnleggende HTTP-autentiseringsmekanismen som rett og slett bruker et brukernavn og passord for å kontrollere at en bruker er den som hun sier at hun er. Apache har et program kalt htpasswd for å vedlikeholde listen med akseptable brukernavn og passord for de som du vil gi spesialtilgang til Subversiondepotet ditt. La oss gi Sally og Harry tilgang til å legge inn forandringer i depotet. Først må vi legge dem til passordfila.

$ ### Første gang: Bruk -c for å opprette fila
$ ### Bruk -m for å bruke MD5-kryptering av passordet, noe som er sikrere
$ htpasswd -cm /etc/svn-passord-fil harry
New password: ***** 
Re-type new password: *****
Adding password for user harry
$ htpasswd -m /etc/svn-passord-fil sally
New password: *******
Re-type new password: *******
Adding password for user sally
$

Det neste som du må gjøre er å legge til noen flere httpd.conf-direktiver inne i Location-blokken for å fortelle Apache hva den skal gjøre med den nye passordfila. AuthType-direktivet spesifiserer hvilken type autentiseringssystem som skal brukes. I dette tilfellet vil vi spesifisere Basic-autentiseringssystemet. AuthName er et vilkårlig navn som du angir for autentiseringsområdet. De fleste nettleserne vil vise dette navnet i et oppsprettsvindu når nettleseren spør brukeren etter navn og passord. Til sist, bruk AuthUserFile-direktivet for å angi plasseringen til passordfila som du opprettet ved å bruke htpasswd.

Etter at du har lagt til disse tre direktivene, skal <Location>-blokken din se ut omtrent som dette:

<Location /svn>
  DAV svn
  SVNParentPath /usr/local/svn
  AuthType Basic
  AuthName "Subversiondepot"
  AuthUserFile /etc/svn-passord-fil
</Location>

Denne <Location>-blokken er ikke komplett enda, og vil ikke gjøre noe nyttig. Den forteller bare Apache at hver gang det kreves autorisasjon skal Apache hente et brukernavn og passord fra Subversionklienten. Det som mangler her er direktiver som forteller Apache hvilke typer klientforespørsler som krever autorisasjon. Der autorisasjon kreves, vil Apache også forlange autentisering. Den enkleste tingen er å beskytte alle forespørsler. Ved å legge til Require valid-user forteller vi Apache at alle forespørsler må komme fra en autentisert bruker:

<Location /svn>
  DAV svn
  SVNParentPath /usr/local/svn
  AuthType Basic
  AuthName "Subversiondepot"
  AuthUserFile /etc/svn-passord-fil
  Require valid-user
</Location>

Pass på å lese den neste seksjonen (“Autorisasjonsvalg”) for flere detaljer om Require-direktivet og andre måter å sette opp autorisasjonsregler på.

En advarsel: HTTP Basic Auth-passord blir sendt omtrent i klartekst over nettverket, og er derfor ekstremt usikkert. Hvis du er bekymret for passordsniffing, er det best å bruke en form for SSL-kryptering, så klienter autentiserer via https:// istedenfor http://; som et minimum kan du sette opp Apache til å bruke et selvsignert sertifikat.[38] Konsulter Apaches dokumentasjon (og dokmentasjon om OpenSSL) om hvordan det gjøres.

Håndtering av SSL-sertifikater

Forretninger som har behov for å utsette depotene for tilgang fra utsiden av firmabrannveggen bør være bevisst på muligheten for at uautoriserte parter kan sniffe nettverkstrafikken deres. SSL minsker sjansen for at denne formen for uønsket oppmerksomhet resulterer i sensitive datalekkasjer.

Hvis en Subversionklient er kompilert for å kunne bruke OpenSSL, gir det muligheten til å snakke til en Apacheserver via http://-URLer. Neon-biblioteket som brukes av Subversionklienten er ikke bare i stand til å kontrollere serversertifikater, men kan også oppgi klientsertifikater når den blir spurt om det. Når klienten og serveren har vekslet SSL-sertifikater og klart å autentisere hverandre, vil all videre kommunikasjon bli kryptert med en sesjonsnøkkel.

Det er utenfor temaet for denne boka å beskrive hvordan man lager klient- og serversertifikater, og hvordan Apache settes opp for å bruke dem. Mange andre bøker, inkludert Apaches egen dokumentasjon, beskriver denne oppgaven. Men det som kan bli dekket her er hvordan man vedlikeholder server- og klientsertifikater fra en vanlig Subversionklient.

Mens det snakkes med Apache via https:// kan en Subversionklient motta to typer informasjon:

  • et serversertifikat

  • krav om et klientsertifikat

Hvis klienten mottar et serversertifikat, må den sjekke at den stoler på sertifikatet – er serveren virkelig den som den påstår at den er? OpenSSL-biblioteket gjør dette ved å undersøke signatøren av serversertifikatet eller godkjenningsinstansencertifying authority (CA). Hvis OpenSSL ikke er i stand til å automatisk stole på godkjenningsinstansen, eller hvis et annet problem oppstår (som et utgått sertifikat eller at servernavnet ikke stemmer), vil Subversionkommandolinjeklienten vil spørre deg om du vil stole på serversertifikatet uansett:

$ svn list https://server.example.com/repos/prosjekt

Error validating server certificate for 'https://server.example.com:443':
 - The certificate is not issued by a trusted authority. Use the
   fingerprint to validate the certificate manually!
Certificate information:
 - Hostname: server.example.com
 - Valid: from Jan 30 19:23:56 2004 GMT until Jan 30 19:23:56 2006 GMT
 - Issuer: CA, example.com, Sometown, California, US
 - Fingerprint: 7d:e1:a9:34:33:39:ba:6a:e9:a5:c4:22:98:7b:76:5c:92:a0:9c:7b

(R)eject, accept (t)emporarily or accept (p)ermanently?

Denne dialogen skulle se kjent ut, det er hovedsaklig det samme spørsmålet som du har sett i nettleseren din (som jo bare er en annen HTTP-klient lik Subversion!). Hvis du velger det (p)ermanente valget, vil serversertifikatet bli lagret i ditt private auth/-område som brukes under kjøring på omtrent den samme måten som brukernavnet og passordet ditt blir lagret (se “Lagring av klientlegitimasjon”). Hvis det blir lagret, vil Subversion automatisk huske dette sertifikatet i framtidige forhandlinger.

servers-fila som brukes under kjøring gir deg også muligheten til å la Subversionklienten automatisk stole på spesifikke godkjenningsinstanser, enten globalt eller på en per server-basis. Sett ganske enkelt variabelen ssl-authority-files til en semikolonseparert liste med PEM-kodede sertifikater:

[global]
ssl-authority-files = /sti/til/CAcert1.pem;/sti/til/CAcert2.pem

Mange OpenSSL-installasjoner har også et forhåndsdefinert sett av standardiserte godkjenningsinstanser som det stoles omtrent universelt på. Får å få Subversionklienten til å automatisk stole på disse standardautoritetene, sett variabelen ssl-trust-default-ca til true.

Mens den snakker med Apache, kan en Subversionklient også motta et krav om et klientsertifikat. Apache spør klienten om å identifisere seg selv: Er klienten virkelig den som den sier at den er? Hvis alt går riktig for seg, sender Subversionklienten tilbake et privat sertifikat signert av en godkjenningsinstans som Apache stoler på. Et klientsertifikat blir vanligvis lagret på disken i et kryptert format, beskyttet av et lokalt passord. Når Subversion mottar denne forespørselen, vil den spørre deg etter både en sti til sertifikatet og passordet som beskytter det:

$ svn list https://server.example.com/repos/prosjekt

Authentication realm: https://server.example.com:443
Client certificate filename: /sti/til/mitt/cert.p12
Passphrase for '/sti/til/mitt/cert.p12':  ********
…

Legg merke til at klientsertifikatet er en p12-fil. For å bruke et klientsertifikat med Subversion, må det være i PKCS#12-format som er en portabel standard. De fleste nettlesere klarer allerede å importere og eksportere sertifikater i dette formatet. En annen mulighet er å bruke kommandolinjeverktøyene i OpenSSL for å konvertere eksisterende sertifikater til PKCS#12.

servers-fila som brukes under kjøring lar deg automatisere denne forespørselen på en per-server-basis. En av eller begge delene informasjon kan bli beskrevet med kjørevariabler:

[groups]
examplehost = server.example.com

[examplehost]
ssl-client-cert-file = /sti/til/mitt/cert.p12
ssl-client-cert-password = etellerannetpassord

Når du har satt variablene ssl-client-cert-file og ssl-client-cert-password, kan Subversionklienten automatisk svare på en klientsertifikatforespørsel uten å spørre deg.[39]

Autorisasjonsvalg

På dette punktet har du konfigurert autentisering, men ikke autorisasjon. Apache er i stand til å foreta spørring mot klienter og godkjenne identiteter, men er ikke blitt fortalt hvordan adgangen skal begrenses eller hva disse klientene som har disse identitetene skal få lov til. Denne seksjonen beskriver to strategier for å kontrollere tilgangen til depotene dine.

Adgangskontroll for hele depotet

Den enkleste formen for adgangskontroll er å autorisere visse brukere enten for leseaksess til et depot eller lese/skrive-tilgang til et depot.

Du kan begrense tilgangen til alle depotoperasjoner ved å legge til Require valid-user-direktivet i <Location>-blokken. Ved å bruke det foregående eksempelet vil dette bety at bare klienter som påstår å være enten harry eller sally og som oppga korrekt passord for de respektive brukernavnene vil få tilgang til å gjøre noe med Subversiondepotet:

<Location /svn>
  DAV svn
  SVNParentPath /usr/local/svn

  # hvordan brukeren autentiseres
  AuthType Basic
  AuthName "Subversiondepot"
  AuthUserFile /sti/til/brukerfil

  # bare autentiserte brukere får tilgang til depotet
  Require valid-user
</Location>

Noen ganger trenger du ikke å ha en like streng adgangskontroll. Depotet til Subversions kildekodedepot på http://svn.collab.net/repos/svn tillater alle i verden å utføre leseoperasjoner i depotet (som å hente ut arbeidskopier og bla gjennom depotet med en nettleser), men begrenser alle skriveoperasjoner til autentiserte brukere. For å få til denne typen selektiv begrensning kan du bruke konfigurasjonsdirektivene Limit og LimitExcept. I likhet med Location-direktivet har disse blokkene start- og sluttelementer, og du legger dem inn i <Location>-blokken.

Parametrene som brukes sammen med direktivene Limit og LimitExcept er typer av HTTP-forespørsler som blir påvirket av den blokken. Hvis du for eksempel vil forby all tilgang til depotet unntatt de foreløpig støttede leseoperasjonene, vil du bruke LimitExcept-direktivet sammen med forespørselstypene GET, PROPFIND, OPTIONS og REPORT. Deretter plasseres det tidligere nevnte direktivet Require valid-user inne i <LimitExcept>-blokken istedenfor bare inne i <Location>-blokken.

<Location /svn>
  DAV svn
  SVNParentPath /usr/local/svn

  # hvordan brukeren skal autentiseres
  AuthType Basic
  AuthName "Subversiondepot"
  AuthUserFile /sti/til/brukerfil

  # For alle andre operasjoner enn disse kreves en autentisert bruker.
  <LimitExcept GET PROPFIND OPTIONS REPORT>
    Require valid-user
  </LimitExcept>
</Location>

Dette er bare noen få enkle eksempler. For informasjon som går mer i dybden om Apaches adgangskontroll og Require-direktivet, ta en kikk på Security-seksjonen i dokmentasjonssamlingen for Apache på http://httpd.apache.org/docs-2.0/misc/tutorials.html.

Adgangskontroll på katalognivå

Det er mulig å sette opp mer finjusterte rettigheter ved å bruke en annen Apache httpd-modul, mod_authz_svn. Denne modulen tar for seg de forskjellige uklare URLene som blir sendt fra klienten til serveren, spør mod_dav_svn om å dekode dem og avgjør etter dette om forespørsler skal nektes, basert på tilgangsregler som er definert i en konfigurasjonsfil.

Hvis du har bygget Subversion fra kildekode, blir mod_authz_svn automatisk bygget og installert sammen med mod_dav_svn. Mange binærdistribusjoner installerer den også automatisk. For å kontrollere at den er riktig installert, pass på at den kommer rett etter mod_dav_svns LoadModule-direktiv i httpd.conf:

LoadModule dav_module         modules/mod_dav.so
LoadModule dav_svn_module     modules/mod_dav_svn.so
LoadModule authz_svn_module   modules/mod_authz_svn.so

For å aktivere denne modulen må du sette opp Location-blokken til å bruke AuthSVNAccessFile-direktivet, som spesifiserer en fil som inneholder regler for rettigheter til stier i depotene dine. (Vil vil diskutere formatet på denne fila om et øyeblikk.)

Apache er fleksibel, så du har muligheten til å sette opp blokken etter ett av tre generelle mønstre. For å begynne, velg ett av disse grunnleggende konfigurasjonsmønstrene. (Eksemplene nedenfor er veldig enkle; se på Apaches egen dokumentasjon for mange flere detaljer om autentiserings- og autorisasjonsvalg i Apache.)

Den enkleste blokken gir tilgang til alle. I dette scenariet sender Apache aldri autentiseringsforespørsler, så alle brukerne blir behandlet som anonyme.

Eksempel 6.1. Et eksempel på oppsett for anonym tilgang.

<Location /repos>
  DAV svn
  SVNParentPath /usr/local/svn

  # våre regler for tilgang
  AuthzSVNAccessFile /sti/til/aksessfil
</Location>
          


I den andre enden av paranoiaskalaen kan du sette opp blokken din til å forlange autentisering av alle. Alle klienter må oppgi legitimasjon for å identifisere seg. Blokken krever betingelsesløst autentisering via Require valid-user-direktivet og definerer en autentiseringsmåte.

Eksempel 6.2. Eksempel på oppsett for autentisert tilgang.

<Location /repos>
  DAV svn
  SVNParentPath /usr/local/svn

  # våre regler for tilgang
  AuthzSVNAccessFile /sti/til/aksessfil

  # kun autentiserte brukere får tilgang til depotet
  Require valid-user

  # hvordan brukeren skal autentiseres
  AuthType Basic
  AuthName "Subversiondepot"
  AuthUserFile /sti/til/brukerfil
</Location>
          


Et tredje, meget populært mønster er å tillate en kombinasjon av autentisert og anonym tilgang. For eksempel ønsker mange administratorer å tillate alle anonyme brukere å lese visse depotkataloger, men vil at kun autentiserte brukere kan lese (eller skrive til) mer sensitive områder. Med dette oppsettet starter alle brukerne med å aksessere depotet anonymt. Hvis reglene for adgangskontrollen på et eller annet punkt krever et brukernavn, vil Apache forlange autentisering av klienten. For å gjøre dette, bruker du både Satisfy Any og Require Valid-user-direktivene sammen.

Eksempel 6.3. Eksempel på oppsett for blandet autentisert/anonym tilgang.

<Location /repos>
  DAV svn
  SVNParentPath /usr/local/svn

  # våre regler for tilgang
  AuthzSVNAccessFile /sti/til/aksessfil

  # prøv først anononym tilgang og fall tilbake på skikkelig 
  # autentisering hvis det er nødvendig.
  Satisfy Any
  Require valid-user

  # hvordan brukeren skal autentiseres
  AuthType Basic
  AuthName "Subversiondepot"
  AuthUserFile /sti/til/brukerfil
</Location>
          


Once you've settled on one of these three basic httpd.conf templates, you need to create your file containing access rules for particular paths within the repository. This is described in “Path-Based Authorization”.

Slå av stibaserte kontroller

mod_dav_svn-modulen går gjennom en masse arbeid for å forsikre seg om at dataene som du har markert som uleselig ikke blir lekket ved en ulykke. Dette betyr at den må passe nøye på alle stiene og filinnhold som blir returnert av kommandoer som svn checkout eller svn update. Hvis disse kommandoene kommer over en sti som ikke er lesbar i følge en eller annen autorisasjonsregel, blir stien vanligvis totalt utelatt. Når det gjelder tråling av historien og navneskifter – for eksempel å kjøre en kommando som svn cat -r GAMMELREV foo.c på en fil som skiftet navn for lenge siden – vil trålingen av navneskiftet ganske enkelt stoppe hvis et av objektets tidligere navn blir anslått til å være beskyttet mot lesing.

Alle disse kontrollene av stier kan noen ganger være ganske dyrekjøpte, spesielt i tilfellet med svn log. Når det hentes en liste med revisjoner, ser serveren på alle stier som har forandret seg i hver revisjon og sjekker om stien er leselig. Hvis en uleselig sti blir funnet, utelates den fra listen med forandrede stier i revisjonen (som man vanligvis ser med --verbose-valget), og hele loggmeldingen blir utelatt. Dette kan føre til at mye tid blir brukt på revisjoner som påvirker et stort antall filer. Dette er prisen for sikkerhet: Selv om du ikke har satt opp en modul som mod_authz_svn i det hele tatt, ber mod_dav_svn-modulen fortsatt Apache httpd om å kjøre autorisasjonssjekker på hver eneste sti. mod_dav_svn-modulen har ingen formening om hvilke autorisasjonsmoduler som er installert, så alt den kan gjøre er å be Apache om å utføre alle som kan eksistere.

På den annen side finnes det en slags nødløsning for dette, en som lar deg bytte sikkerhetsfunksjonalitet mot hastighet. Hvis du ikke gjennomfører noen form for katalogbasert autorisasjon (det vil si at mod_authz_svn eller en lignende modul ikke brukes) kan du slå av alt av stikontroller. Bruk SVNPathAuthz-direktivet i httpd.conf-fila:

Eksempel 6.4. Slå av alle filstikontroller

<Location /repos>
  DAV svn
  SVNParentPath /usr/local/svn

  SVNPathAuthz off
</Location>
          


SVNPathAuthz-direktivet er on (aktivt) som standard. Når det settes til off, slås all stibasert autorisasjonskontroll av; mod_dav_svn lar være å utføre autorisasjonssjekker på hver sti som den finner.

Flere lure ting

Vi har dekket mesteparten av autentiserings- og autorisasjonsvalg for Apache og mod_dav_svn. Men det er noen andre fine ting som Apache tilbyr.

Bla gjennom depotet

En av de nyttigste fordelene med å bruke et Apache/WebDAV-oppsett for Subversiondepotet ditt er at de yngste revisjonene av de versjonerte filene og katalogene er øyeblikkelig tilgjengelig for visning gjennom en vanlig nettleser. Siden Subversion bruker URLer til å identifisere versjonerte ressurser, kan disse URLene for HTTP-basert depottilgang bli skrevet direkte inn i en nettleser. Nettleseren vil foreta en HTTP GET-forespørsel for denne URLen, og avhengig om denne URLen representerer en versjonert katalog eller fil vil mod_dav_svn svare med en katalogutlisting eller innholdet av en fil.

Siden URLene ikke inneholder noen informasjon om hvilken versjon av ressursen du ønsker å se, vil mod_dav_svn alltid svare med den yngste versjonen. Denne funksjonaliteten har den ytterst stilfulle bieffekten at du kan sende Subversion-URLer til mottakere som referanser til dokumenter, og disse URLene vil alltid peke til den nyeste versjonen av dette dokumentet. Du kan selvfølgelig også til og med bruke URLene som hyperlinker fra andre hjemmesider.

Proper MIME Type

When browsing a Subversion repository, the web browser gets a clue about how to render a file's contents by looking at the Content-Type: header returned in Apache's response to the HTTP GET request. The value of this header is some sort of MIME type. By default, Apache will tell the web browsers that all repository files are of the default MIME type, typically text/plain. This can be frustrating, however, if a user wishes repository files to render as something more meaningful — for example, it might be nice to have a foo.html file in the repository actually render as HTML when browsing.

To make this happen, you only need to make sure that your files have the proper svn:mime-type set. This is discussed in more detail in “File Content Type”, and you can even configure your client to automatically attach proper svn:mime-type properties to files entering the repository for the first time; see “Automatic Property Setting”.

So in our example, if one were to set the svn:mime-type property to text/html on file foo.html, then Apache would properly tell your web browser to render the file as HTML. One could also attach proper image/* mime-type properties to images, and by doing this, ultimately get an entire web site to be viewable directly from a repository! There's generalyl no problem with doing this, as long as the website doesn't contain any dynamically-generated content.

Forandre utseendet

Vanligvis vil du få mer ut av URLer til versjonerte filer – det er jo der alt det interessante innholdet har for vane å ligge. Men noen ganger må du bla direkte gjennom en katalogliste i Subversion, og da legger du merke til at den genererte HTML-en som brukes i utlistingen er ganske enkel, og i hvertfall ikke ment å være en nytelse for øyet. For å gjøre det mulig å tilpasse disse katalogvisningene, har Subversion en XML-basert innholdsfunksjonalitet. Et enkelt SVNIndexXSLT-direktiv i depotets Location-blokk i httpd.conf vil instruere mod_dav_svn til å generere XML-data når den viser en katalogutlisting og referere til XSLT-stilsettet som du har valgt:

<Location /svn>
  DAV svn
  SVNParentPath /usr/local/svn
  SVNIndexXSLT "/svnindex.xsl"
  …
</Location>

Ved å bruke SVNIndexXSLT-direktivet og et kreativt XSLT-stilsett, kan du få katalogutlistingene til å følge fargevalgene og utseendet til andre deler av hjemmesiden din. Eller du kan bruke eksempelstilsettene som ligger i Subversionkildekodens tools/xslt-katalog. Husk på at stien som gis til SVNIndexXSLT-direktivet egentlig er en URL — nettlesere må være i stand til å lese stilsettene dine for å kunne bruke dem!

Listing Repositories

If you're serving a colllection of repositories from a single URL via the SVNParentPath directive, then it's also possible to have Apache display all available repositories to a web browser. Just activate the SVNListParentPath directive:

<Location /svn>
  DAV svn
  SVNParentPath /usr/local/svn
  SVNListParentPath on
  …
</Location>

If a user now points her web browser to the URL http://host.example.com/svn/, she'll see list of all Subversion repositories sitting in /usr/local/svn. Obviously, this can be a security problem, so this feature is turned off by default.

Apache Logging

Because Apache is an HTTP server at heart, it contains fantastically flexible logging feature. It's beyond the scope of this book to discuss all ways logging can be configured, but we should point out that even the most generic httpd.conf file will cause Apache to produce two logs: error_log and access_log. These logs may appear in different places, but are typically created in the logging area of your Apache installation. (On Unix, they often live in /usr/local/apache2/logs/.)

The error_log describes any interal errors that Apache runs into as it works. The access_log file records every incoming HTTP request received by Apache. This makes it easy to see, for example, which IP addresses Subversion clients are coming from, how often particular clients use the server, which users are authenticating properly, and which requests succeed or fail.

Unfortunately, because HTTP is a stateless protocol, even the simplest Subversion client operation generates multiple network requests. It's very difficult to look at the access_log and deduce what the client was doing — most operations look like a series of cryptic PROPPATCH, GET, PUT, and REPORT requests. To make things worse, many client operations send nearly-identical series of requests, so it's even harder to tell them apart.

mod_dav_svn, however, can come to your aid. By activating an operational logging feature, you can ask mod_dav_svn to create a separate log file describing what sort of high-level operations your clients are performing.

To do this, you need to make use of Apache's CustomLog directive (which is explained in more detail in Apache's own documentation). Be sure to invoke this directive outside of your Subversion Location block:

<Location /svn>
  DAV svn
  …
</Location>

CustomLog logs/svn_logfile "%t %u %{SVN-ACTION}e" env=SVN-ACTION

In this example, we're asking Apache to create a special logfile svn_logfile in the standard Apache logs directory. The %t and %u variables are replaced by the time and username of the request, respectively. The really important part are the two instances of SVN-ACTION. When Apache sees that variable, it substitutes the value of the SVN-ACTION environment variable, which is automatically set by mod_dav_svn whenever it detects a high-level client action.

So instead of having to interpret a traditional access_log like this:

[26/Jan/2007:22:25:29 -0600] "PROPFIND /svn/calc/!svn/vcc/default HTTP/1.1" 207 398
[26/Jan/2007:22:25:29 -0600] "PROPFIND /svn/calc/!svn/bln/59 HTTP/1.1" 207 449
[26/Jan/2007:22:25:29 -0600] "PROPFIND /svn/calc HTTP/1.1" 207 647
[26/Jan/2007:22:25:29 -0600] "REPORT /svn/calc/!svn/vcc/default HTTP/1.1" 200 607
[26/Jan/2007:22:25:31 -0600] "OPTIONS /svn/calc HTTP/1.1" 200 188
[26/Jan/2007:22:25:31 -0600] "MKACTIVITY /svn/calc/!svn/act/e6035ef7-5df0-4ac0-b811-4be7c823f998 HTTP/1.1" 201 227
…

… you can instead peruse a much more intelligible svn_logfile like this:

[26/Jan/2007:22:24:20 -0600] - list-dir '/'
[26/Jan/2007:22:24:27 -0600] - update '/'
[26/Jan/2007:22:25:29 -0600] - remote-status '/'
[26/Jan/2007:22:25:31 -0600] sally commit r60

Annen funksjonalitet

Mye av funksjonaliteten som Apache tilbyr i sin rolle som en robust webserver kan i tillegg bli satt opp for økt funksjonalitet eller sikkerhet i Subversion. Subversion kommuniserer med Apache ved bruk av Neon, som er et generelt HTTP/WebDAV-bibliotek med støtte for mekanismer som SSL (Secure Socket Layer, som tidligere diskutert). Hvis Subversionklienten din er bygget med støtte for SSL, kan den aksessere Apacheservere via https://.

Like nyttige funksjonaliteter i forholdet mellom Apache og Subversion er muligheten til å spesifisere en spesiell port (istedenfor den vanlige HTTP-porten 80) eller virtuelle domenenavn som Subversiondepoter skal aksesseres via, eller muligheten til å aksessere depotet gjennom en HTTP-mellomserver. Alle disse tingene støttes av Neon, så denne støtten får Subversion helt gratis.

Til sist, fordi mod_dav_svn forstår et utvalg av WebDAV/DeltaV-protokollen, er det mulig å aksessere depotet vie tredjeparts DAV-klienter. De fleste moderne operativsystemer (Win32, OS X og Linux) har muligheten til å montere en DAV-server som en standard delt ressurs på nettverket. Dette er et komplisert tema; for detaljer, les Tillegg C, WebDAV and Autoversioning.

Path-Based Authorization

Both Apache and svnserve are capable of granting (or denying) permissions to users. Typically this is done over the entire repository: a user can read the repository (or not), and she can write to the repository (or not). It's also possible, however, to define finer-grained access rules. One set of users may have permssion to write to a certain directory in the repository, but not others; another directory might not even be readable by all but a few special people.

Both servers use a common file format to describe these path-based access rules. In the case of Apache, one needs to load the mod_authz_svn module and then add the AuthzSVNAccessFile directive (within the httpd.conf file) pointing to your own rules-file. (For a full explanation, see “Adgangskontroll på katalognivå”.) If you're using svnserve, then you need to make the authz-db variable (within svnserve.conf) point to your rules-file.

Once your server knows where to find your rules-file, it's time to define the rules.

Syntaksen til fila er den samme kjente som brukes av svnserve.conf og konfigurasjonsfilene som brukes under kjøring. Linjer som starter med en hash (#) ignoreres. I sin enkleste form navngir hver seksjon et depot og en sti i det, og de autentiserte brukernavnene er valgnavnene innenfor hver seksjon. Verdien til hvert valg beskriver brukerens adgangsnivå til depotstien: Enten r (kun lesing) eller rw (både skriving og lesing). Hvis brukeren ikke nevnes i det hele tatt, gis ingen tilgang i det hele tatt.

For å være mer spesifikk: Verdien til seksjonsnavnene er enten på formen [depotnavn:sti] eller på formen [sti]. Hvis du bruker SVNParentPath-direktivet, er det viktig å spesifisere depotnavnet i seksjonene dine. Hvis du utelater dem, vil en seksjon som [en/katalog] samsvare med stien en/katalog i hvert eneste depot. Hvis du bruker imidlertid bruker SVNPath-direktivet, er det greit å bare definere stier i seksjonene dine — når alt kommer til alt, finnes det bare ett depot.

[calc:/branches/calc/bug-142]
harry = rw
sally = r

I dette første eksempelet har brukeren harry full lese- og skrivetilgang i katalogen /branches/calc/big-142 i calc-depotet, men brukeren sally har kun lesetilgang. Alle andre brukere nektes tilgang til depotet.

Alle tilganger arves selvfølgelig fra foreldrekataloger til underkataloger. Dette betyr at vi kan spesifisere en underkatalog med en forskjellig adgangsregel for Sally:

[calc:/branches/calc/bug-142]
harry = rw
sally = r

# gi sally skrivetilgang kun til underkatalogen «testing»
[calc:/branches/calc/bug-142/testing]
sally = rw

Nå kan Sally skrive til underkatalogen testing på grenen, men kan fortsatt bare lese andre deler. Imens fortsetter Harry å ha både lese- og skrivetilgang til hele grenen.

Det er også mulig å eksplisitt nekte adgang til noen ved hjelp av arveregler, ved å sette brukernavnvariabelen til ingenting:

[calc:/branches/calc/bug-142]
harry = rw
sally = r

[calc:/branches/calc/bug-142/hemmelig]
harry =

I dette eksempelet har Harry både lese- og skrivetilgang til hele bug-142-treet, men har absolutt ingen tilgang i det hele tatt til underkatalogen hemmelig innenfor det.

Tingen å huske på er at den mest spesifikke stien alltid samsvarer først. Serveren prøver å få selve stien til å stemme, deretter forelderen til stien, så forelderen til den, og så videre. Netteffekten er at det å nevne en spesifikk sti i aksessfila alltid vil overstyre alle rettigheter som er arvet fra foreldrekataloger.

Som standard har ingen noen tilgang til depotet i det hele tatt. Det betyr at hvis du starter med en tom fil, vil du sannsynligvis ønske å i det minste gi leserettigheter til alle brukere ved roten av depotet. Du kan gjøre dette ved å bruke asteriskvariabelen (*), som betyr alle brukere:

[/]
* = r

Dette er et vanlig oppsett; legg merke til at det ikke nevnes noen depotnavn i seksjonsnavnet. Dette gjør alle depotene fullstendig lesbare for alle brukerne. Når alle brukerne har lesetilgang til depotene, kan du gi eksplisitt lese/skrive-rettigheter til visse brukere i spesifikke underkataloger inne i spesifikke depoter.

Asteriskvariabelen (*) er også verdt litt spesiell omtale her: Det er det eneste mønsteret som samsvarer med en anonym bruker. Hvis du har satt opp serverblokken din til å tillate en blanding av anonym og autentisert tilgang, starter alle brukere med å kommunisere anonymt. Serveren ser etter en *-verdi for stien som blir aksessert; hvis den ikke finner noen, forlanger den skikkelig autentisering fra klienten.

Aksessfila lar deg også definere hele grupper med brukere, ganske likt /etc/group på Unix-systemer:

[groups]
calc-utviklere = harry, sally, joe
paint-utviklere = frank, sally, jane
alle = harry, sally, joe, frank, sally, jane

Grupper kan bli gitt tilgang akkurat som brukere. Skill mellom dem ved å sette en krøllalfa (@) foran gruppenavnet:

[calc:/prosjekter/calc]
@calc-utviklere = rw

[paint:/prosjekter/paint]
@paint-utviklere = rw
jane = r 

Grupper kan også bli definert til å inneholde andre grupper:

[groups]
calc-utviklere = harry, sally, joe
paint-utviklere = frank, sally, jane
alle = @calc-utviklere, @paint-utviklere

…og det er omtrent det som er å si om den saken.

Støtte for flere metoder for tilgang til depotet

Du har sett hvordan et depot kan bli aksessert på mange forskjellige måter. Men er det mulig – eller trygt – for depotet å bli aksessert på flere forskjellige måter samtidig?

Til enhver tid kan disse prosessene kreve lese- og skriveaksess til depotet:

  • vanlige brukere som bruker en Subversionklient (som seg selv) for å aksessere depotet direkte via file:///-URLer,

  • vanlige brukere som kobler seg til private SSH-startede svnserve-prosesser (som kjører som brukeren selv) som aksesserer depotet,

  • en svnserve-prosess – enten en daemon eller en startet av inetd – som kjører som en spesiell bruker,

  • en Apache httpd-process, som kjører som en spesiell bruker.

Det vanligste problemer administratorer får med å gjøre er eierskap og rettigheter for depotene. Har alle prosesser (og brukere) i den forrige listen rettigheter til å lese og skrive til Berkeley DB-filene? Hvis du har et Unix-lignende operativsystem er en grei måte å plassere hver eneste potensiell depotbruker i en ny svn-gruppe og gjøre denne gruppen til eier av hele depotet. Men til og med dette er ikke nok, fordi en prosess kan skrive til databasefilene med en utrivelig umask – en som forbyr tilgang for andre brukere.

Så det neste steget etter å sette opp en felles gruppe for depotbrukerne er å tvinge alle prosesser som aksesserer depotet til å bruke en fornuftig umask. For brukere som aksesserer depotet direkte kan du kapsle svn-programmet inn i et skript som først setter umask 002 og deretter kjører det egentlige svn-programmet. Du kan skrive et lignende innkapslingsskript for svnserve-programmet, og legge til en umask 002 til Apaches eget oppstartsskript apachectl. For eksempel:

$ cat /usr/bin/svn

#!/bin/sh

umask 002
/usr/bin/svn-real "$@"

Et annet vanlig problem oppstår ofte på Unix-lignende systemer. Når et depot blir brukt, lager Berkeley DB noen ganger nye loggfiler for å journalføre det som den gjør. Selv om hele depotet eies av svn-gruppen, vil ikke disse nye filene nødvendigvis eies av den samme gruppen, som i sin tur fører til flere rettighetsproblemer for brukerne. En grei måte å ordne dette på er å sette gruppens SUID-bit på db-katalogen i depotet. Dette gjør at alle nyopprettede loggfiler tilhører den samme gruppen som foreldrekatalogen.

Når du har gjort alt dette, skal depotet være tilgjengelig for alle de nødvendige prosessene. Det kan se rotete og komplisert ut, men problemene med å ha flere brukere som skal dele skrivetilgang til vanlige filer er klassiske og må løses på måter som ikke er spesielt elegante.

Heldigvis vil de fleste administratorer ikke ha behov for et slikt komplisert oppsett. Brukere som ønsker tilgang til depoter som er på den samme maskinen er ikke begrenset til å bruke URLer av file://-typen, de kan vanligvis kontakte Apache HTTP-serveren eller svnserve ved å bruke localhost som servernavnet i http://- og svn://-URLene. Og det å vedlikeholde flere serverprosesser for Subversiondepotene har en tendens til å skaffe mer hodebry enn nødvendig. Vi anbefaler at du velger den serveren som passer best til dine behov og holder deg til den!




[35] Se RFC 2195.

[36] Note that using any sort of svnserve-enforced access control at all is a bit pointless; the user already has direct access to the repository database.

[37] Det er noe som de virkelig hater.

[38] Selv om selvsignerte serversertifikater også er sårbare for mann-i-midten-angrep, vil et slikt angrep for en vanlig observatør være mye vanskeligere å få til, sammenlignet med å sniffe ubeskyttede passord

[39] Mer sikkerhetsbevisste folk vil kanskje ikke lagre klientsertifikatpassordet i kjørefila servers.

[40] På den tiden ble den kalt ViewCVS.

[41] A common theme in this book!

Kapittel 7. Tilpasse Subversion til din smak

### TODO: Chapter opening ###

### TODO: Gut the runtime config stuff like I did the property stuff, making larger topical sections to which the runtime config stuff generally refers. Like already exists for external diff/diff3, add, for example, a section on external editors. ###

Konfigurasjonsområdet for bruk under kjøring

Subversion inneholder mange valg for å modifisere oppførselen under kjøring, og dette kan kontrolleres av brukeren. Mange av disse valgene er av typen som en bruker ønsker å bruke ved alle Subversionoperasjoner. Så, istedenfor å tvinge brukere til å huske kommandolinjeargumenter for å spesifisere disse valgene, og å bruke dem for hver eneste operasjon som utføres, bruker Subversion konfigurasjonsfiler som er lagt for seg selv i et eget konfigurasjonsområde.

Subversions konfigurasjonsområde er et to-lags hierarki med valgnavn og deres verdier. Vanligvis koker dette ned til en spesiell katalog som inneholder konfigurasjonsfiler (første lag) som er rene tekstfiler i standard INI-format (med seksjoner som er det andre laget). Disse filene kan enkelt redigeres med favoritt-tekstbehandleren din (som for eksempel Emacs eller vi), og inneholder direktiver som leses av klienten for å anslå hvilken av de valgfrie oppførslene brukeren foretrekker.

Oppbygningen av konfigurasjonsområdet

Den første gangen kommandolinjeklienten svn kjøres, lages et eget konfigurasjonsområde for brukeren. På Unix-lignende systemer opptrer dette området som en katalog kalt .subversion i brukerens hjemmekatalog. På Win32-systemer oppretter Subversion en katalog kalt Subversion, vanligvis i Application Data-området til brukerens profilkatalog (som forresten er en skjult katalog). På denne plattformen varierer imidlertid den eksakte plasseringen fra system til system, og bestemmes av registryen.[42] Vi vil referere til brukerkonfigurasjonsområdet ved å bruke navnet som brukes under Unix, .subversion.

I tillegg til konfigurasjonsområdet som brukes på brukernivå, kjenner også Subversion til eksistensen av et konfigurasjonsområde som gjelder for hele systemet på maskinen. Dette gir systemadministratorer muligheten til å opprette standardinnstillinger for alle brukerne på en gitt maskin. Legg merke til at det felles konfigurasjonsområdet på maskinen ikke alene bestemmer standardoppførselen – oppsettet i konfigurasjonsområdet for brukeren overstyrer de som er i området som er felles for alle brukerne, og kommandolinjeargumenter som gis til svn-programmet har det siste ordet hva oppførsel angår. På Unix-lignende plattformer forventes det at konfigurasjonsområdet som er felles for alle brukerne er i katalogen /etc/subversion; på MS Windows-maskiner letes det etter en Subversion-katalog i det felles Application Data-området (og igjen, som spesifisert i Windowsregistryen). Ulikt med det brukerbaserte tilfellet, vil ikke svn-klienten prøve å opprette et nytt maskinkonfigurasjonsområde.

Konfigurasjonsområdet for hver bruker inneholder for tiden tre filer – to konfigurasjonsfiler (config og servers) og en README.txt-fil som beskriver INI-formatet. På tidspunktet de ble laget, inneholder filene standardverdier for alle valgene som Subversion støtter. For det meste er de kommentert ut og gruppert sammen med beskrivelser om hvordan verdiene påvirker oppførselen til Subversion. For å forandre en viss oppførsel, trenger du bare å forandre verdien til et valg med en vanlig teksteditor. Hvis du en eller annen gang du vil ha tilbake standardinnstillingene, kan du fjerne (eller skifte navn på) katalogen med konfigurasjonsfilene og deretter kjøre noen uskyldige svn-kommandoer som for eksempel svn --version som oppretter en ny konfigurasjonskatalog som inneholder standardinnstillingene.

Brukerkonfigurasjonsområdet inneholder også et lager med autentiseringsdata. auth-katalogen inneholder et sett med underkataloger som inneholder deler av lagret informasjon som brukes av Subversions forskjellige autentiseringsmetoder. Denne katalogen er laget på en måte som gjør at kun den ene brukeren har tillatelse til å lese innholdet.

Konfigurasjon og Windows-registryen

I tillegg til det vanlige INI-baserte konfigurasjonsområdet, kan Subversionklienter som kjører på MS Windows-plattformer også bruke registryen til å lagre konfigurasjonsdataene. Valgnavnene og deres verdier er de samme som i INI-filene. fil/seksjon-hierarkiet blir også tatt vare på, selv om det noteres på en litt annen måte – i dette skjemaet er filer og seksjoner kun nivåer i nøkkeltreet i registryen.

Subversion ser etter konfigurasjonsverdier for hele systemet under nøkkelen HKEY_LOCAL_MACHINE\Software\Tigris.org\Subversion. For eksempel, valget global-ignores som er i miscellany-seksjonen i config-fila finnes i HKEY_LOCAL_MACHINE\Software\Tigris.org\Subversion\Config\Miscellany\global-ignores. Konfigurasjonsverdier for hver enkelt bruker bør lagres under HKEY_CURRENT_USER\Software\Tigris.org\Subversion.

Registry-based configuration options are parsed before their file-based counterparts, so are overridden by values found in the configuration files. Med andre ord er dette rekkefølgen konfigurasjonen blir prioritert på et MS Windows-system:

  1. Valg på kommandolinja

  2. Brukerbaserte INI-filer

  3. Brukerbaserte verdier i registryen

  4. INI-filer som gjelder for hele systemet

  5. Registry-verdier for hele systemet

I tillegg støtter ikke Windows-registryen at noe kan kommenteres ut. Subversion vil imidlertid ignorere valg der navnet begynner med et hash-tegn (#), Dette lar deg kommentere bort et Subversionvalg uten å slette hele nøkkelen fra registryen, noe som selvfølgelig gjør det lettere å hente tilbake dette valget.

Kommandolinjeklienten svn vil aldri prøve å skrive til Windowsregistryen, og vil ikke prøve å lage et område der. Du kan lage nøklene du trenger ved å bruke REGEDIT-programmet. Alternativt kan du lage en .reg-fil og deretter dobbeltklikke på denne fila i Utforskeren, noe som vil flette dataene inn i registryen.

Eksempel 7.1. Eksempel på registryposter i ei .reg-fil.

REGEDIT4

[HKEY_LOCAL_MACHINE\Software\Tigris.org\Subversion\Servers\groups]

[HKEY_LOCAL_MACHINE\Software\Tigris.org\Subversion\Servers\global]
"#http-proxy-host"=""
"#http-proxy-port"=""
"#http-proxy-username"=""
"#http-proxy-password"=""
"#http-proxy-exceptions"=""
"#http-timeout"="0"
"#http-compression"="yes"
"#neon-debug-mask"=""
"#ssl-authority-files"=""
"#ssl-trust-default-ca"=""
"#ssl-client-cert-file"=""
"#ssl-client-cert-password"=""

[HKEY_CURRENT_USER\Software\Tigris.org\Subversion\Config\auth]
"#store-passwords"="yes"
"#store-auth-creds"="yes"

[HKEY_CURRENT_USER\Software\Tigris.org\Subversion\Config\helpers]
"#editor-cmd"="notepad"
"#diff-cmd"=""
"#diff3-cmd"=""
"#diff3-has-program-arg"=""

[HKEY_CURRENT_USER\Software\Tigris.org\Subversion\Config\tunnels]

[HKEY_CURRENT_USER\Software\Tigris.org\Subversion\Config\miscellany]
"#global-ignores"="*.o *.lo *.la #*# .*.rej *.rej .*~ *~ .#* .DS_Store"
"#log-encoding"=""
"#use-commit-times"=""
"#no-unlock"=""
"#enable-auto-props"=""

[HKEY_CURRENT_USER\Software\Tigris.org\Subversion\Config\auto-props]



Det foregående eksemplet viser innholdet av ei .reg-fil som inneholder noen av de mest brukte konfigurasjonsvalgene og deres standardverdier. Legg merke til tilstedeværelsen av både valg som gjelder for hele systemet (for valg relatert til mellomservere i nettverket og innstillinger for hver enkelt bruker (tekstbehandlingsprogrammer og lagring av passord, blant annet). Legg også merke til at alle valgene er kommentert ut. Du trenger bare å fjerne hash-tegnet (#) fra begynnelsen av valgnavnene og sette inn de verdiene du vil.

Konfigurasjonsvalg

### TODO: Rework and move this section to the Reference ###

I denne seksjonen vil vi diskutere de spesifikke konfigurasjonsvalgene som brukes av Subversion under kjøring.

Servere

servers-fila inneholder valg for konfigurering av Subversion og som er relatert til nettverkslag. Det er to spesielle seksjonsnavn i denne fila – groups og global. groups-seksjonen er hovedsaklig en tabell med kryssreferanser. Nøklene i denne seksjonen er navnene til andre seksjoner i fila; verdiene deres er globs – tekstbaserte nøkkelord som kan inneholde jokertegn — som blir sammenlignet med servernavnene til maskinen som det sendes Subversionforespørsler til.

[groups]
beanie-babies = *.red-bean.com
collabnet = svn.collab.net

[beanie-babies]
…

[collabnet]
…

Når Subversion brukes over nettverket, forsøker den å matche navnet til serveren som den prøver å nå med et gruppenavn under groups-seksjonen. Hvis dette stemmer, ser Subversion etter en seksjon i servers-fila som stemmer med navnet i den samsvarende gruppens navn. Fra denne seksjonen leser den det faktiske nettverksoppsettet.

global-seksjonen inneholder innstillingene som er ment for alle serverne som ikke samsvarer med en av søkestrengene i groups-seksjonen. Valgene som er tilgjengelig i denne seksjonen er nøyaktig de samme som de som er gyldig for de andre serverseksjonene i fila (selvfølgelig unntatt den spesielle groups-seksjonen), og er som følger:

http-proxy-host

Dette spesifiserer servernavnet til mellomserveren som de HTTP-baserte Subversionforespørslene som du foretar må gå gjennom. Standardverdien er en tom verdi, noe som betyr at Subversion ikke vil prøve å rute HTTP-forespørsler gjennom en mellomserver og vil istedenfor prøve å kontakte målmaskinen direkte.

http-proxy-port

Dette spesifiserer hvilket portnummer som skal brukes på mellomserveren. Standardverdien er en tom verdi.

http-proxy-username

Spesifiserer brukernavnet som oppgis til mellomserveren. Standardverdien er tom.

http-proxy-password

Spesifiserer passordet som oppgis til mellomserveren. Standardverdien er tom.

http-timeout

Dette spesifiserer antall sekunder det ventes på respons fra serveren. Hvis du opplever problemer med en sen nettvorksforbindelse som fører til at Subversionoperasjoner blir avbrutt, bør du øke verdien for dette valget. Standardverdien er 0, som ber det underliggende HTTP-biblioteket, Neon, til å bruke standardverdien for tidsavbrudd.

http-compression

Dette spesifiserer om Subversion skal prøve å komprimere nettverksforespørsler som blir gjort til servere som er klargjort for DAV. Srandardverdien er yes (selv om komprimering bare vil utføres hvis denne muligheten er kompilert inn i nettverkslaget). Sett denne til no for å unngå komprimering, for eksempel når nettverkstrafikken skal analyseres under debugging.

neon-debug-mask

Dette er en heltallsmaske som det underliggende HTTP-biblioteket, Neon, bruker for å velge hvilke debuggingsmeldinger som skal vises. Standardverdien er 0, som vil forhindre visning av alle debuggingsdata. For mer informasjon om hvordan Subversion gjør bruk av Neon, se Kapittel 8, Developer Information.

ssl-authority-files

Dette er en semikolon-separert liste over stier til filer som inneholder sertifikater fra sertifikatutstedere som aksepteres av Subversionklienten under aksessering av depotet over HTTPS.

ssl-trust-default-ca

Sett denne variabelen til yes hvis du vil at Subversion skal automatisk stole på settet med standard sertifikatutstedere som leveres med OpenSSL.

ssl-client-cert-file

Hvis en server (eller et sett av servere) krever et SSL-klientsertifikat, vil du normalt bli spurt etter en sti til sertifikatet ditt. Ved å sette denne variabelen til den samme stien, vil Subversion være i stand til å finne klientsertifikatet automatisk uten å spørre. Det finnes ingen standard plass der sertifikatene blir lagret på disken; Subversion vil hente det fra enhver sti som du spesifiserer.

ssl-client-cert-password

Hvis fila med SSL-klientsertifikatet er kryptert med et passord, vil Subversion be deg om passordet hver gang sertifikatet brukes. Hvis du synes dette er irriterende (og synes det er greit at passordet lagres i servers-fila), kan du sette denne variabelen til passordet for for sertifikatet. Etter dette blir du ikke bedt om å skrive det flere ganger.

Konfigurasjon

config-fila inneholder resten av de kjørevalgene som for øyeblikket er tilgjengelig i Subversion og ikke er relatert til nettverk. Det er bare noen få valg som er i bruk nå, men de er gruppert i seksjoner med tanke på framtidige utvidelser.

auth-seksjonen inneholder innstillinger relatert til Subversions autentisering og autorisasjon i depotet. Den inneholder:

store-passwords

Dette ber Subversion om å lagre, eller ikke lagre, passord som blir skrevet av brukeren som respons til autentiseringskrav fra servere. Standardverdien er yes. Sett dette til no for å forhindre lagring av passord på disken. Du kan overstyre dette valget for en enkeltstående svn-kjøring ved å bruke kommanolinjevalget --no-auth-cache sammen med de delkommandoene som støtter det. For mer informasjon, se “Lagring av klientlegitimasjon”.

store-auth-creds

Denne valget er det samme som store-passwords, unntatt at det slår av/på disklagring av all autentiseringsinformasjon: Brukernavn, passord, serversertifikater og alle andre typer lagringsbar legitimasjon.

helpers-seksjonen kontrollerer hvilke eksterne programmer Subversion bruker for å utføre oppgavene sine. Gyldige valig i denne seksjonen er:

editor-cmd

Dette spesifiserer hvilket program Subversion vil kjøre når brukeren skal skrive inn en loggmelding under en innleggingsoperasjon, som for eksempel ved bruk av svn commit uten valgene --message (-m) og --file (-F). Dette programmet brukes også sammen med kommandoen svn propedit – en midlertidig fil blir fylt med den nåværende verdien til egenskapen brukeren vil redigere, og redigeringen skjer i tekstbehandleren (se “Egenskaper”). Standardverdien til dette valget er tom. Prioriteringsrekkefølgen som brukes for å avgjøre hvilken kommando for tekstbehandleren som skal brukes, er:

  1. Kommandolinjevalget --editor-cmd

  2. Miljøvariabelen SVN_EDITOR

  3. Konfigurasjonsvalget editor-cmd

  4. Miljøvariabelen VISUAL

  5. Miljøvariabelen EDITOR

  6. Muligens en standardverdi som er bygget inn i Subversion (ikke lagt inn i de offisielle versjonene)

Verdien til alle disse valgene eller variablene er (i motsetning til diff-cmd) begynnelsen av en kommandolinje som kjøres av skallet. Subversion legger til et mellomrom og stien til den midlertidige fila som skal redigeres. Denne midlertidige fila redigeres med tekstbehandleren som returnerer en avslutningskode med verdien 0 for å indikere at operasjonen var vellykket.

diff-cmd

Dette spesifiserer den absolutte stien til et diff-program (viser forskjeller mellom filer) som blir brukt når Subversion lager diff-data (som når svn diff-kommandoen brukes). Vanligvis bruker Subversion et internt diff-bibliotek, men ved å sette dette valget brukes et eksternt program. Se “Using External Differencing Tools” for flere detaljer om bruk av sånne programmer.

diff3-cmd

Her spesifiseres den absolutte stien til et treveis diff-program. Subversion bruker dette programmet til å flette forandringer gjort av brukeren sammen med de som mottas fra depotet. Vanligvis bruker Subversion et internt diff-bibliotek, men ved å sette dette valget brukes et eksternt program. Se “Using External Differencing Tools” for flere detaljer om bruk av sånne programmer.

diff3-has-program-arg

Dette flagget bør settes til true hvis programmet spesifisert i diff3-cmd-valget aksepterer et --diff-program-parameter på kommandolinja.

tunnels-seksjonen lar deg definere nye tunnelskjemaer for bruk sammen med svnserve og klienttilkoblinger med svn://. For flere detaljer, se “Autentisering og autorisasjon via SSH”.

miscellany-seksjonen er der alt som ikke hører hjemme andre steder ender opp. I denne seksjonen finner du:

global-ignores

Ved kjøring av svn status-kommandoen lister Subversion uversjonerte filer og kataloger sammen med de versjonerte og merker dem med et ?-tegn (se svn status). Noen ganger kan det være plagsomt å se uinteressante, uversjonerte elementer – for eksempel objektfiler som ligger igjen etter at et program er kompilert – i denne visningen. Valget global-ignores er en liste med blanktegn-separerte strenger som beskriver navn på filer og kataloger som Subversion ikke skal vise unntatt hvis de er versjonert. Standardverdien er *.o *.lo *.la #*# .*.rej *.rej .*~ *~ .#* .DS_Store.

I likhet med svn status ignorerer svn add- og svn import-kommandoen filer som samsvarer med listen når de tråler en katalog. Du kan overstyre denne oppførselen for en enkelt kjøring av alle disse kommandoene ved å spesifisere filnavnet eller ved å bruke kommandolinjevalget --no-ignore.

For informasjon om mer finkontroll av ignorerte elementer, se “Ignoring Unversioned Items”.

enable-auto-props

Dette ber Subversion om å automatisk sette egenskaper på nye filer som legges til eller importeres. Standardverdien er no, så sett denne til yes for å slå på autoegenskaper. Seksjonen auto-props i denne fila spesifiserer hvilke egenskaper som skal settes på hvilke filer.

log-encoding

Denne variabelen setter standardtegnsettet for loggmeldinger ved innlegging. Det er en permanent form av --encoding-valget (se svn Switches”). Subversiondepotet lagrer loggmeldinger i UTF-8, og går ut i fra at loggmeldingene dine er skrevet med operativsystemets lokale tegnsett. Du bør spesifisere en annen koding hvis loggmeldingene dine skrives med et annet tegnsett.

use-commit-times

Normalt har filene i arbeidskopien din fildatoer som viser forrige gang de ble rørt av en prosess, enten det er tekstbehandleren din eller av en eller annen delkommando i svn. Det er vanligvis praktisk for folk som utvikler programvare, fordi byggesystemer ofte ser på fildatoer som en måte å bestemme hvilke filer som trenger en ny kompilering.

I andre situasjoner, derimot, er det greit å la filene i arbeidskopien ha fildatoen satt til tidspunktet de sist ble forandret i depotet. Kommandoen svn export setter alltid disse tidspunktene for siste innlegging på trær som den produserer. Ved å sette denne konfigurasjonsvariabelen til yes, vil kommandoene svn checkout, svn update, svn switch og svn revert også sette fildatoen på filer som berøres til forrige gangen de ble lagt inn i depotet.

Seksjonen auto-props kontrollerer Subversionklientens mulighet til å automatisk sette egenskaper på filer når de legges til eller importeres. Den inneholder et vilkårlig antall nøkkel/verdi-par på formatet MØNSTER = EGENSKAPSNAVN=EGENSKAPSVERDI der MØNSTER er en filnavnsøkestreng som passer med et sett av filnavn og resten av linja er egenskapen og dens verdi. Flere samsvar på en fil vil resultere i flere egenskapsforandringer for denne fila; imidlertid er det ingen garanti at autoegenskaper vil bli lagt til i den rekkefølgen som de listes i konfigurasjonsfila. Du kan derfor ikke la en regel overstyre en annen. Du kan finne flere eksempler på bruk av autoegenskaper i config-fila. Til sist, ikke glem å sette enable-auto-props til yes i miscellany-seksjonen hvis du vil at autoegenskaper skal brukes.

Localization

Localization is the act of making programs behave in a region-specific way. When a program formats numbers or dates in a way specific to your part of the world, or prints messages (or accepts input) in your native language, the program is said to be localized. This section describes steps Subversion has made towards localization.

Understanding locales

Most modern operating systems have a notion of the current locale—that is, the region or country whose localization conventions are honored. These conventions—typically chosen by some runtime configuration mechanism on the computer—affect the way in which programs present data to the user, as well as the way in which they accept user input.

On Unix-like systems, you can check the values of the locale-related runtime configuration options by running the locale command:

$ locale
LANG=
LC_COLLATE="C"
LC_CTYPE="C"
LC_MESSAGES="C"
LC_MONETARY="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_ALL="C"

The output is a list of locale-related environment variables and their current values. In this example, the variables are all set to the default C locale, but users can set these variables to specific country/language code combinations. For example, if one were to set the LC_TIME variable to fr_CA, then programs would know to present time and date information formatted according a French-speaking Canadian's expectations. And if one were to set the LC_MESSAGES variable to zh_TW, then programs would know to present human-readable messages in Traditional Chinese. Setting the LC_ALL variable has the effect of changing every locale variable to the same value. The value of LANG is used as a default value for any locale variable that is unset. To see the list of available locales on a Unix system, run the command locale -a.

On Windows, locale configuration is done via the Regional and Language Options control panel item. There you can view and select the values of individual settings from the available locales, and even customize (at a sickening level of detail) several of the display formatting conventions.

Subversion's use of locales

The Subversion client, svn, honors the current locale configuration in two ways. First, it notices the value of the LC_MESSAGES variable and attempts to print all messages in the specified language. For example:

$ export LC_MESSAGES=de_DE
$ svn help cat
cat: Gibt den Inhalt der angegebenen Dateien oder URLs aus.
Aufruf: cat ZIEL[@REV]...
…

This behavior works identically on both Unix and Windows systems. Note, though, that while your operating system might have support for a certain locale, the Subversion client still may not be able to speak the particular language. In order to produce localized messages, human volunteers must provide translations for each language. The translations are written using the GNU gettext package, which results in translation modules that end with the .mo filename extension. For example, the German translation file is named de.mo. These translation files are installed somewhere on your system. On Unix, they typically live in /usr/share/locale/, while on Windows they're often found in the \share\locale\ folder in Subversion's installation area. Once installed, a module is named after the program it provides translations for. For example, the de.mo file may ultimately end up installed as /usr/share/locale/de/LC_MESSAGES/subversion.mo. By browsing the installed .mo files, you can see which languages the Subversion client is able to speak.

The second way in which the locale is honored involves how svn interprets your input. The repository stores all paths, filenames, and log messages in Unicode, encoded as UTF-8. In that sense, the repository is internationalized—that is, the repository is ready to accept input in any human language. This means, however, that the Subversion client is responsible for sending only UTF-8 filenames and log messages into the repository. In order to do this, it must convert the data from the native locale into UTF-8.

For example, suppose you create a file named caffè.txt, and then when committing the file, you write the log message as Adesso il caffè è più forte. Both the filename and log message contain non-ASCII characters, but because your locale is set to it_IT, the Subversion client knows to interpret them as Italian. It uses an Italian character set to convert the data to UTF-8 before sending them off to the repository.

Note that while the repository demands UTF-8 filenames and log messages, it does not pay attention to file contents. Subversion treats file contents as opaque strings of bytes, and neither client nor server makes an attempt to understand the character set or encoding of the contents.

Using External Differencing Tools

The presence of --diff-cmd and --diff3-cmd options, and similarly named runtime configuration parameters (see “Konfigurasjon”), can lead to a false notion of how easy it is to use external differencing (or diff) and merge tools with Subversion. While Subversion can use most of popular such tools available, the effort invested in setting this up often turns out to be non-trivial.

The interface between Subversion and external diff and merge tools harkens back to a time when Subversion's only contextual differencing capabilities were built around invocations of the GNU diffutils toolchain, specifically the diff and diff3 utilities. To get the kind of behavior Subversion needed, it called these utilities with more than a handful of options and parameters, most of which were quite specific to the utilities. Some time later, Subversion grew its own internal differencing library, and as a failover mechanism, [43] the --diff-cmd and --diff3-cmd options were added to the Subversion command-line client so users could more easily indicate that they preferred to use the GNU diff and diff3 utilities instead of the newfangled internal diff library. If those options were used, Subversion would simply ignore the internal diff library, and fall back to running those external programs, lengthy argument lists and all. And that's where things remain today.

It didn't take long for folks to realize that having such easy configuration mechanisms for specifying that Subversion should use the external GNU diff and diff3 utilities located at a particular place on the system could be applied toward the use of other diff and merge tools, too. After all, Subversion didn't actually verify that the things it was being told to run were members of the GNU diffutils toolchain. But the only configurable aspect of using those external tools is their location on the system—not the option set, parameter order, etc. Subversion continues throwing all those GNU utility options at your external diff tool regardless of whether or not that program can understand those options. And that's where things get unintuitive for most users.

The key to using external diff and merge tools (other than GNU diff and diff3, of course) with Subversion is to use wrapper scripts which convert the input from Subversion into something that your differencing tool can understand, and then to convert the output of your tool back into a format which Subversion expects—the format that the GNU tools would have used. The following sections cover the specifics of those expectations.

[Notat]Notat

The decision on when to fire off a contextual diff or merge as part of a larger Subversion operation is made entirely by Subversion, and is affected by, among other things, whether or not the files being operated on are human-readable as determined by their svn:mime-type property. This means, for example, that even if you had the niftiest Microsoft Word-aware differencing or merging tool in the Universe, it would never be invoked by Subversion so long as your versioned Word documents had a configured MIME type that denoted that they were not human-readable (such as application/msword). For more about MIME type settings, see “File Content Type”

External diff

Subversion calls external diff programs with parameters suitable for the GNU diff utility, and expects only that the external program return with a successful error code. For most alternative diff program, only the sixth and seventh arguments, the paths of the files which represent the left and right sides of the diff, respectively, are of interest. Note that Subversion runs the diff program once per modified file covered by the Subversion operation, so if your program runs in an asynchronous fashion (or backgrounded), you might have several instances of it all running simultaneously. Finally, Subversion expects that your program return an errorcode of 1 if your program detected differences, or 0 if it did not—any other errorcode is considered a fatal error. [44]

Eksempel 7.2, “diffwrap.sh” and Eksempel 7.3, “diffwrap.bat” are templates for external diff tool wrappers in the Bourne shell and Windows batch scripting languages, respectively.

Eksempel 7.2. diffwrap.sh

#!/bin/sh

# Configure your favorite diff program here.
DIFF="/usr/local/bin/my-diff-tool"

# Subversion provides the paths we need as the sixth and seventh 
# parameters.
LEFT=${6}
RIGHT=${7}

# Call the diff command (change the following line to make sense for
# your merge program).
$DIFF --left $LEFT --right $RIGHT

# Return an errorcode of 0 if no differences were detected, 1 if some were.
# Any other errorcode will be treated as fatal.


Eksempel 7.3. diffwrap.bat

@ECHO OFF

REM Configure your favorite diff program here.
SET DIFF="C:\Program Files\Funky Stuff\My Diff Tool.exe"

REM Subversion provides the paths we need as the sixth and seventh 
REM parameters.
SET LEFT=%6
SET RIGHT=%7

REM Call the diff command (change the following line to make sense for
REM your merge program).
%DIFF% --left %LEFT% --right %RIGHT%

REM Return an errorcode of 0 if no differences were detected, 1 if some were.
REM Any other errorcode will be treated as fatal.


External diff3

Subversion calls external merge programs with parameters suitable for the GNU diff3 utility, expecting that the external program return with a successful error code and that the full file contents which result from the completed merge operation are printed on the standard output stream (so that Subversion can redirect them into the appropriate version controlled file). For most alternative merge programs, only the ninth, tenth, and eleventh arguments, the paths of the files which represent the mine, older, and yours inputs, respectively, are of interest. Note that because Subversion depends on the output of your merge program, you wrapper script must not exit before that output has been delivered to Subversion. When it finally does exit, it should return an errorcode of 0 if the merge was successful, or 1 if unresolved conflicts remain in the output—any other errorcode is considered a fatal error.

Eksempel 7.4, “diff3wrap.sh” and Eksempel 7.5, “diff3wrap.bat” are templates for external merge tool wrappers in the Bourne shell and Windows batch scripting languages, respectively.

Eksempel 7.4. diff3wrap.sh

#!/bin/sh

# Configure your favorite diff3/merge program here.
DIFF3="/usr/local/bin/my-merge-tool"

# Subversion provides the paths we need as the ninth, tenth, and eleventh 
# parameters.
MINE=${9}
OLDER=${10}
YOURS=${11}

# Call the merge command (change the following line to make sense for
# your merge program).
$DIFF3 --older $OLDER --mine $MINE --yours $YOURS

# After performing the merge, this script needs to print the contents
# of the merged file to stdout.  Do that in whatever way you see fit.
# Return an errorcode of 0 on successful merge, 1 if unresolved conflicts
# remain in the result.  Any other errorcode will be treated as fatal.


Eksempel 7.5. diff3wrap.bat

@ECHO OFF

REM Configure your favorite diff3/merge program here.
SET DIFF3="C:\Program Files\Funky Stuff\My Merge Tool.exe"

REM Subversion provides the paths we need as the ninth, tenth, and eleventh 
REM parameters.  But we only have access to nine parameters at a time, so we
REM shift our nine-parameter window twice to let us get to what we need.
SHIFT
SHIFT
SET MINE=%7
SET OLDER=%8
SET YOURS=%9

REM Call the merge command (change the following line to make sense for
REM your merge program).
%DIFF3% --older %OLDER% --mine %MINE% --yours %YOURS%

REM After performing the merge, this script needs to print the contents
REM of the merged file to stdout.  Do that in whatever way you see fit.
REM Return an errorcode of 0 on successful merge, 1 if unresolved conflicts
REM remain in the result.  Any other errorcode will be treated as fatal.





[42] Miljøvariabelen APPDATA peker til Application Data-området, så du kan alltids henvise til denne katalogen som %APPDATA%\Subversion.

[43] Subversion developers are good, but even the best make mistakes.

[44] The GNU diff manual page puts it this way: An exit status of 0 means no differences were found, 1 means some differences were found, and 2 means trouble.

Kapittel 8. Developer Information

Subversion has a modular design, implemented as a collection of C libraries. Each library has a well-defined purpose and interface, and those interfaces are available not only for Subversion itself to use, but for any software that wishes to embed or otherwise programmatically control Subversion. Most of those interfaces are available not only in C, but also in higher-level languages such as Python or Java.

This chapter is for those who wish to interact with Subversion through its public Application Programming Interface (API) or various language bindings. If you wish to write robust wrapper scripts around Subversion functionality to simplify your own life, are trying to develop more complex integrations between Subversion and other pieces of software, or just have an interest in Subversion's various library modules and what they offer, this chapter is for you. If, however, you don't foresee yourself participating with Subversion at such a level, feel free to skip this chapter with the confidence that your experience as a Subversion user will not be affected.

Layered Library Design

Each of Subversion's core libraries can be said to exist in one of three main layers—the Repository Layer, the Repository Access (RA) Layer, or the Client Layer. We will examine these layers shortly, but first, see our brief inventory of Subversion's libraries in Tabell 8.1, “A Brief Inventory of the Subversion Libraries”. For the sake of consistency, we will refer to the libraries by their extensionless Unix library names (e.g.: libsvn_fs, libsvn_wc, mod_dav_svn).

Tabell 8.1. A Brief Inventory of the Subversion Libraries

LibraryDescription
libsvn_clientPrimary interface for client programs
libsvn_deltaTree and byte-stream differencing routines
libsvn_diffContextual differencing and merging routines
libsvn_fsFilesystem commons and module loader
libsvn_fs_baseThe Berkeley DB filesystem back-end
libsvn_fs_fsThe native filesystem (FSFS) back-end
libsvn_raRepository Access commons and module loader
libsvn_ra_davThe WebDAV Repository Access module
libsvn_ra_localThe local Repository Access module
libsvn_ra_svnThe custom protocol Repository Access module
libsvn_reposRepository interface
libsvn_subrMiscellaneous helpful subroutines
libsvn_wcThe working copy management library
mod_authz_svnApache authorization module for Subversion repositories access via WebDAV
mod_dav_svnApache module for mapping WebDAV operations to Subversion ones


The fact that the word miscellaneous only appears once in Tabell 8.1, “A Brief Inventory of the Subversion Libraries” is a good sign. The Subversion development team is serious about making sure that functionality lives in the right layer and libraries. Perhaps the greatest advantage of the modular design is its lack of complexity from a developer's point of view. As a developer, you can quickly formulate that kind of big picture that allows you to pinpoint the location of certain pieces of functionality with relative ease.

Another benefit of modularity is the ability to replace a given module with a whole new library that implements the same API without affecting the rest of the code base. In some sense, this happens within Subversion already. The libsvn_ra_dav, libsvn_ra_local, and libsvn_ra_svn all implement the same interface. And all three communicate with the Repository Layer—libsvn_ra_dav and libsvn_ra_svn do so across a network, and libsvn_ra_local connects to it directly. The libsvn_fs_base and libsvn_fs_fs libraries are another example of this.

The client itself also highlights modularity in the Subversion design. While Subversion itself comes with only a command-line client program, there are several third party programs which provide various forms of client GUI. These GUIs use the same APIs that the stock command-line client does. Subversion's libsvn_client library is the one-stop shop for most of the functionality necessary for designing a working Subversion client (see “Client Layer”).

Repository Layer

When referring to Subversion's Repository Layer, we're generally talking about two libraries—the repository library, and the filesystem library. These libraries provide the storage and reporting mechanisms for the various revisions of your version-controlled data. This layer is connected to the Client Layer via the Repository Access Layer, and is, from the perspective of the Subversion user, the stuff at the other end of the line.

The Subversion Filesystem is accessed via the libsvn_fs API, and is not a kernel-level filesystem that one would install in an operating system (like the Linux ext2 or NTFS), but a virtual filesystem. Rather than storing files and directories as real files and directories (as in, the kind you can navigate through using your favorite shell program), it uses one of two available abstract storage backends—either a Berkeley DB database environment, or a flat-file representation. (To learn more about the two repository back-ends, see “Datalagring i depotet”.) However, there has been considerable interest by the development community in giving future releases of Subversion the ability to use other back-end database systems, perhaps through a mechanism such as Open Database Connectivity (ODBC).

The filesystem API exported by libsvn_fs contains the kinds of functionality you would expect from any other filesystem API: you can create and remove files and directories, copy and move them around, modify file contents, and so on. It also has features that are not quite as common, such as the ability to add, modify, and remove metadata (properties) on each file or directory. Furthermore, the Subversion Filesystem is a versioning filesystem, which means that as you make changes to your directory tree, Subversion remembers what your tree looked like before those changes. And before the previous changes. And the previous ones. And so on, all the way back through versioning time to (and just beyond) the moment you first started adding things to the filesystem.

All the modifications you make to your tree are done within the context of a Subversion transaction. The following is a simplified general routine for modifying your filesystem:

  1. Begin a Subversion transaction.

  2. Make your changes (adds, deletes, property modifications, etc.).

  3. Commit your transaction.

Once you have committed your transaction, your filesystem modifications are permanently stored as historical artifacts. Each of these cycles generates a single new revision of your tree, and each revision is forever accessible as an immutable snapshot of the way things were.

Most of the functionality provided by the filesystem interface comes as an action that occurs on a filesystem path. That is, from outside of the filesystem, the primary mechanism for describing and accessing the individual revisions of files and directories comes through the use of path strings like /foo/bar, just as if you were addressing files and directories through your favorite shell program. You add new files and directories by passing their paths-to-be to the right API functions. You query for information about them by the same mechanism.

Unlike most filesystems, though, a path alone is not enough information to identify a file or directory in Subversion. Think of a directory tree as a two-dimensional system, where a node's siblings represent a sort of left-and-right motion, and descending into subdirectories a downward motion. Figur 8.1, “Files and directories in two dimensions” shows a typical representation of a tree as exactly that.

Figur 8.1. Files and directories in two dimensions

Files and directories in two dimensions


Of course, the Subversion filesystem has a nifty third dimension that most filesystems do not have—Time! [45] In the filesystem interface, nearly every function that has a path argument also expects a root argument. This svn_fs_root_t argument describes either a revision or a Subversion transaction (which is usually just a revision-to-be), and provides that third-dimensional context needed to understand the difference between /foo/bar in revision 32, and the same path as it exists in revision 98. Figur 8.2, “Versioning time—the third dimension!” shows revision history as an added dimension to the Subversion filesystem universe.

Figur 8.2. Versioning time—the third dimension!

Versioning time—the third dimension!


As we mentioned earlier, the libsvn_fs API looks and feels like any other filesystem, except that it has this wonderful versioning capability. It was designed to be usable by any program interested in a versioning filesystem. Not coincidentally, Subversion itself is interested in that functionality. But while the filesystem API should be sufficient for basic file and directory versioning support, Subversion wants more—and that is where libsvn_repos comes in.

The Subversion repository library (libsvn_repos) is basically a wrapper library around the filesystem functionality. This library is responsible for creating the repository layout, making sure that the underlying filesystem is initialized, and so on. Libsvn_repos also implements a set of hooks—scripts that are executed by the repository code when certain actions take place. These scripts are useful for notification, authorization, or whatever purposes the repository administrator desires. This type of functionality, and other utilities provided by the repository library, are not strictly related to implementing a versioning filesystem, which is why it was placed into its own library.

Developers who wish to use the libsvn_repos API will find that it is not a complete wrapper around the filesystem interface. That is, only certain major events in the general cycle of filesystem activity are wrapped by the repository interface. Some of these include the creation and commit of Subversion transactions, and the modification of revision properties. These particular events are wrapped by the repository layer because they have hooks associated with them. In the future, other events may be wrapped by the repository API. All of the remaining filesystem interaction will continue to occur directly via the libsvn_fs API, though.

For example, here is a code segment that illustrates the use of both the repository and filesystem interfaces to create a new revision of the filesystem in which a directory is added. Note that in this example, the SVN_ERR() macro simply checks for a non-successful error return from the function it wraps, and returns that error if it exists.

Eksempel 8.1. Using the Repository Layer

/* Create a new directory at the path NEW_DIRECTORY in the Subversion
   repository located at REPOS_PATH.  Perform all memory allocation in
   POOL.  This function will create a new revision for the addition of
   NEW_DIRECTORY.  */
static svn_error_t *
make_new_directory (const char *repos_path,
                    const char *new_directory,
                    apr_pool_t *pool)
{
  svn_error_t *err;
  svn_repos_t *repos;
  svn_fs_t *fs;
  svn_revnum_t youngest_rev;
  svn_fs_txn_t *txn;
  svn_fs_root_t *txn_root;
  const char *conflict_str;

  /* Open the repository located at REPOS_PATH.  */
  SVN_ERR (svn_repos_open (&repos, repos_path, pool));

  /* Get a pointer to the filesystem object that is stored in
     REPOS.  */
  fs = svn_repos_fs (repos);

  /* Ask the filesystem to tell us the youngest revision that
     currently exists.  */
  SVN_ERR (svn_fs_youngest_rev (&youngest_rev, fs, pool));

  /* Begin a new transaction that is based on YOUNGEST_REV.  We are
     less likely to have our later commit rejected as conflicting if we
     always try to make our changes against a copy of the latest snapshot
     of the filesystem tree.  */
  SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, pool));

  /* Now that we have started a new Subversion transaction, get a root
     object that represents that transaction.  */
  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
  
  /* Create our new directory under the transaction root, at the path
     NEW_DIRECTORY.  */
  SVN_ERR (svn_fs_make_dir (txn_root, new_directory, pool));

  /* Commit the transaction, creating a new revision of the filesystem
     which includes our added directory path.  */
  err = svn_repos_fs_commit_txn (&conflict_str, repos, 
                                 &youngest_rev, txn, pool);
  if (! err)
    {
      /* No error?  Excellent!  Print a brief report of our success.  */
      printf ("Directory '%s' was successfully added as new revision "
              "'%ld'.\n", new_directory, youngest_rev);
    }
  else if (err->apr_err == SVN_ERR_FS_CONFLICT)
    {
      /* Uh-oh.  Our commit failed as the result of a conflict
         (someone else seems to have made changes to the same area 
         of the filesystem that we tried to modify).  Print an error
         message.  */
      printf ("A conflict occurred at path '%s' while attempting "
              "to add directory '%s' to the repository at '%s'.\n", 
              conflict_str, new_directory, repos_path);
    }
  else
    {
      /* Some other error has occurred.  Print an error message.  */
      printf ("An error occurred while attempting to add directory '%s' "
              "to the repository at '%s'.\n", 
              new_directory, repos_path);
    }

  /* Return the result of the attempted commit to our caller.  */
  return err;
} 


In the previous code segment, calls were made to both the repository and filesystem interfaces. We could just as easily have committed the transaction using svn_fs_commit_txn(). But the filesystem API knows nothing about the repository library's hook mechanism. If you want your Subversion repository to automatically perform some set of non-Subversion tasks every time you commit a transaction (like, for example, sending an email that describes all the changes made in that transaction to your developer mailing list), you need to use the libsvn_repos-wrapped version of that function—svn_repos_fs_commit_txn(). This function will actually first run the pre-commit hook script if one exists, then commit the transaction, and finally will run a post-commit hook script. The hooks provide a special kind of reporting mechanism that does not really belong in the core filesystem library itself. (For more information regarding Subversion's repository hooks, see “Påhakningsskript”.)

The hook mechanism requirement is but one of the reasons for the abstraction of a separate repository library from the rest of the filesystem code. The libsvn_repos API provides several other important utilities to Subversion. These include the abilities to:

  1. create, open, destroy, and perform recovery steps on a Subversion repository and the filesystem included in that repository.

  2. describe the differences between two filesystem trees.

  3. query for the commit log messages associated with all (or some) of the revisions in which a set of files was modified in the filesystem.

  4. generate a human-readable dump of the filesystem, a complete representation of the revisions in the filesystem.

  5. parse that dump format, loading the dumped revisions into a different Subversion repository.

As Subversion continues to evolve, the repository library will grow with the filesystem library to offer increased functionality and configurable option support.

Repository Access Layer

If the Subversion Repository Layer is at the other end of the line, the Repository Access Layer is the line itself. Charged with marshalling data between the client libraries and the repository, this layer includes the libsvn_ra module loader library, the RA modules themselves (which currently includes libsvn_ra_dav, libsvn_ra_local, and libsvn_ra_svn), and any additional libraries needed by one or more of those RA modules, such as the mod_dav_svn Apache module with which libsvn_ra_dav communicates or libsvn_ra_svn's server, svnserve.

Since Subversion uses URLs to identify its repository resources, the protocol portion of the URL schema (usually file:, http:, https:, or svn:) is used to determine which RA module will handle the communications. Each module registers a list of the protocols it knows how to speak so that the RA loader can, at runtime, determine which module to use for the task at hand. You can determine which RA modules are available to the Subversion command-line client, and what protocols they claim to support, by running svn --version:

$ svn --version
svn, version 1.2.3 (r15833)
   compiled Sep 13 2005, 22:45:22

Copyright (C) 2000-2005 CollabNet.
Subversion is open source software, see http://subversion.tigris.org/
This product includes software developed by CollabNet (http://www.Collab.Net/).

The following repository access (RA) modules are available:

* ra_dav : Module for accessing a repository via WebDAV (DeltaV) protocol.
  - handles 'http' scheme
  - handles 'https' scheme
* ra_svn : Module for accessing a repository using the svn network protocol.
  - handles 'svn' scheme
* ra_local : Module for accessing a repository on local disk.
  - handles 'file' scheme

RA-DAV (Repository Access Using HTTP/DAV)

The libsvn_ra_dav library is designed for use by clients that are being run on different machines than the servers with which they communicating, specifically servers reached using URLs that contain the http: or https: protocol portions. To understand how this module works, we should first mention a couple of other key components in this particular configuration of the Repository Access Layer—the powerful Apache HTTP Server, and the Neon HTTP/WebDAV client library.

Subversion's primary network server is the Apache HTTP Server. Apache is a time-tested, extensible open-source server process that is ready for serious use. It can sustain a high network load and runs on many platforms. The Apache server supports a number of different standard authentication protocols, and can be extended through the use of modules to support many others. It also supports optimizations like network pipelining and caching. By using Apache as a server, Subversion gets all of these features for free. And since most firewalls already allow HTTP traffic to pass through, system administrators typically don't even have to change their firewall configurations to allow Subversion to work.

Subversion uses HTTP and WebDAV (with DeltaV) to communicate with an Apache server. You can read more about this in the WebDAV section of this chapter, but in short, WebDAV and DeltaV are extensions to the standard HTTP 1.1 protocol that enable sharing and versioning of files over the web. Apache 2.0 and later versions come with mod_dav, an Apache module that understands the DAV extensions to HTTP. Subversion itself supplies mod_dav_svn, though, which is another Apache module that works in conjunction with (really, as a back-end to) mod_dav to provide Subversion's specific implementations of WebDAV and DeltaV.

When communicating with a repository over HTTP, the RA loader library chooses libsvn_ra_dav as the proper access module. The Subversion client makes calls into the generic RA interface, and libsvn_ra_dav maps those calls (which embody rather large-scale Subversion actions) to a set of HTTP/WebDAV requests. Using the Neon library, libsvn_ra_dav transmits those requests to the Apache server. Apache receives these requests (exactly as it does generic HTTP requests that your web browser might make), notices that the requests are directed at a URL that is configured as a DAV location (using the <Location> directive in httpd.conf), and hands the request off to its own mod_dav module. When properly configured, mod_dav knows to use Subversion's mod_dav_svn for any filesystem-related needs, as opposed to the generic mod_dav_fs that comes with Apache. So ultimately, the client is communicating with mod_dav_svn, which binds directly to the Subversion Repository Layer.

That was a simplified description of the actual exchanges taking place, though. For example, the Subversion repository might be protected by Apache's authorization directives. This could result in initial attempts to communicate with the repository being rejected by Apache on authorization grounds. At this point, libsvn_ra_dav gets back the notice from Apache that insufficient identification was supplied, and calls back into the Client Layer to get some updated authentication data. If the data is supplied correctly, and the user has the permissions that Apache seeks, libsvn_ra_dav's next automatic attempt at performing the original operation will be granted, and all will be well. If sufficient authentication information cannot be supplied, the request will ultimately fail, and the client will report the failure to the user.

By using Neon and Apache, Subversion gets free functionality in several other complex areas, too. For example, if Neon finds the OpenSSL libraries, it allows the Subversion client to attempt to use SSL-encrypted communications with the Apache server (whose own mod_ssl can speak the language). Also, both Neon itself and Apache's mod_deflate can understand the deflate algorithm (the same one used by the PKZIP and gzip programs), so requests can be sent in smaller, compressed chunks across the wire. Other complex features that Subversion hopes to support in the future include the ability to automatically handle server-specified redirects (for example, when a repository has been moved to a new canonical URL) and taking advantage of HTTP pipelining.

RA-SVN (Custom Protocol Repository Access)

In addition to the standard HTTP/WebDAV protocol, Subversion also provides an RA implementation that uses a custom protocol. The libsvn_ra_svn module implements its own network socket connectivity, and communicates with a stand-alone server—the svnserve program—on the machine that hosts the repository. Clients access the repository using the svn:// schema.

This RA implementation lacks most of the advantages of Apache mentioned in the previous section; however, it may be appealing to some system administrators nonetheless. It is dramatically easier to configure and run; setting up an svnserve process is nearly instantaneous. It is also much smaller (in terms of lines of code) than Apache, making it much easier to audit, for security reasons or otherwise. Furthermore, some system administrators may already have an SSH security infrastructure in place, and want Subversion to use it. Clients using ra_svn can easily tunnel the protocol over SSH.

RA-Local (Direct Repository Access)

Not all communications with a Subversion repository require a powerhouse server process and a network layer. For users who simply wish to access the repositories on their local disk, they may do so using file: URLs and the functionality provided by libsvn_ra_local. This RA module binds directly with the repository and filesystem libraries, so no network communication is required at all.

Subversion requires that the server name included as part of the file: URL be either localhost or empty, and that there be no port specification. In other words, your URLs should look like either file://localhost/path/to/repos or file:///path/to/repos.

Also, be aware that Subversion's file: URLs cannot be used in a regular web browser the way typical file: URLs can. When you attempt to view a file: URL in a regular web browser, it reads and displays the contents of the file at that location by examining the filesystem directly. However, Subversion's resources exist in a virtual filesystem (see “Repository Layer”), and your browser will not understand how to read that filesystem.

Your RA Library Here

For those who wish to access a Subversion repository using still another protocol, that is precisely why the Repository Access Layer is modularized! Developers can simply write a new library that implements the RA interface on one side and communicates with the repository on the other. Your new library can use existing network protocols, or you can invent your own. You could use inter-process communication (IPC) calls, or—let's get crazy, shall we?—you could even implement an email-based protocol. Subversion supplies the APIs; you supply the creativity.

Client Layer

On the client side, the Subversion working copy is where all the action takes place. The bulk of functionality implemented by the client-side libraries exists for the sole purpose of managing working copies—directories full of files and other subdirectories which serve as a sort of local, editable reflection of one or more repository locations—and propagating changes to and from the Repository Access layer.

Subversion's working copy library, libsvn_wc, is directly responsible for managing the data in the working copies. To accomplish this, the library stores administrative information about each working copy directory within a special subdirectory. This subdirectory, named .svn, is present in each working copy directory and contains various other files and directories which record state and provide a private workspace for administrative action. For those familiar with CVS, this .svn subdirectory is similar in purpose to the CVS administrative directories found in CVS working copies. For more information about the .svn administrative area, see “Inside the Working Copy Administration Area”in this chapter.

The Subversion client library, libsvn_client, has the broadest responsibility; its job is to mingle the functionality of the working copy library with that of the Repository Access Layer, and then to provide the highest-level API to any application that wishes to perform general revision control actions. For example, the function svn_client_checkout() takes a URL as an argument. It passes this URL to the RA layer and opens an authenticated session with a particular repository. It then asks the repository for a certain tree, and sends this tree into the working copy library, which then writes a full working copy to disk (.svn directories and all).

The client library is designed to be used by any application. While the Subversion source code includes a standard command-line client, it should be very easy to write any number of GUI clients on top of the client library. New GUIs (or any new client, really) for Subversion need not be clunky wrappers around the included command-line client—they have full access via the libsvn_client API to same functionality, data, and callback mechanisms that the command-line client uses.

Using the APIs

Developing applications against the Subversion library APIs is fairly straightforward. All of the public header files live in the subversion/include directory of the source tree. These headers are copied into your system locations when you build and install Subversion itself from source. These headers represent the entirety of the functions and types meant to be accessible by users of the Subversion libraries.

The first thing you might notice is that Subversion's datatypes and functions are namespace protected. Every public Subversion symbol name begins with svn_, followed by a short code for the library in which the symbol is defined (such as wc, client, fs, etc.), followed by a single underscore (_) and then the rest of the symbol name. Semi-public functions (used among source files of a given library but not by code outside that library, and found inside the library directories themselves) differ from this naming scheme in that instead of a single underscore after the library code, they use a double underscore (__). Functions that are private to a given source file have no special prefixing, and are declared static. Of course, a compiler isn't interested in these naming conventions, but they help to clarify the scope of a given function or datatype.

The Apache Portable Runtime Library

Along with Subversion's own datatypes, you will see many references to datatypes that begin with apr_—symbols from the Apache Portable Runtime (APR) library. APR is Apache's portability library, originally carved out of its server code as an attempt to separate the OS-specific bits from the OS-independent portions of the code. The result was a library that provides a generic API for performing operations that differ mildly—or wildly—from OS to OS. While the Apache HTTP Server was obviously the first user of the APR library, the Subversion developers immediately recognized the value of using APR as well. This means that there are practically no OS-specific code portions in Subversion itself. Also, it means that the Subversion client compiles and runs anywhere that the server does. Currently this list includes all flavors of Unix, Win32, BeOS, OS/2, and Mac OS X.

In addition to providing consistent implementations of system calls that differ across operating systems, [46] APR gives Subversion immediate access to many custom datatypes, such as dynamic arrays and hash tables. Subversion uses these types extensively throughout the codebase. But perhaps the most pervasive APR datatype, found in nearly every Subversion API prototype, is the apr_pool_t—the APR memory pool. Subversion uses pools internally for all its memory allocation needs (unless an external library requires a different memory management schema for data passed through its API), [47] and while a person coding against the Subversion APIs is not required to do the same, they are required to provide pools to the API functions that need them. This means that users of the Subversion API must also link against APR, must call apr_initialize() to initialize the APR subsystem, and then must create and manage pools for use with Subversion API calls, typically by using svn_pool_create(), svn_pool_clear(), and svn_pool_destroy().

URL and Path Requirements

With remote version control operation as the whole point of Subversion's existence, it makes sense that some attention has been paid to internationalization (i18n) support. After all, while remote might mean across the office, it could just as well mean across the globe. To facilitate this, all of Subversion's public interfaces that accept path arguments expect those paths to be canonicalized, and encoded in UTF-8. This means, for example, that any new client binary that drives the libsvn_client interface needs to first convert paths from the locale-specific encoding to UTF-8 before passing those paths to the Subversion libraries, and then re-convert any resultant output paths from Subversion back into the locale's encoding before using those paths for non-Subversion purposes. Fortunately, Subversion provides a suite of functions (see subversion/include/svn_utf.h) that can be used by any program to do these conversions.

Also, Subversion APIs require all URL parameters to be properly URI-encoded. So, instead of passing file:///home/username/My File.txt as the URL of a file named My File.txt, you need to pass file:///home/username/My%20File.txt. Again, Subversion supplies helper functions that your application can use—svn_path_uri_encode() and svn_path_uri_decode(), for URI encoding and decoding, respectively.

Using Languages Other than C and C++

If you are interested in using the Subversion libraries in conjunction with something other than a C program—say a Python or Perl script—Subversion has some support for this via the Simplified Wrapper and Interface Generator (SWIG). The SWIG bindings for Subversion are located in subversion/bindings/swig and whilst still maturing, they are in a usable state. These bindings allow you to call Subversion API functions indirectly, using wrappers that translate the datatypes native to your scripting language into the datatypes needed by Subversion's C libraries.

There is an obvious benefit to accessing the Subversion APIs via a language binding—simplicity. Generally speaking, languages such as Python and Perl are much more flexible and easy to use than C or C++. The sort of high-level datatypes and context-driven type checking provided by these languages are often better at handling information that comes from users. As you know, humans are proficient at botching up input to a program, and scripting languages tend to handle that misinformation more gracefully. Of course, often that flexibility comes at the cost of performance. That is why using a tightly-optimized, C-based interface and library suite, combined with a powerful, flexible binding language, is so appealing.

Let's look at a sample program that uses Subversion's Python SWIG bindings to recursively crawl the youngest repository revision, and print the various paths reached during the crawl.

Eksempel 8.2. Using the Repository Layer with Python

#!/usr/bin/python

"""Crawl a repository, printing versioned object path names."""

import sys
import os.path
import svn.fs, svn.core, svn.repos

def crawl_filesystem_dir(root, directory, pool):
    """Recursively crawl DIRECTORY under ROOT in the filesystem, and return
    a list of all the paths at or below DIRECTORY.  Use POOL for all 
    allocations."""

    # Print the name of this path.
    print directory + "/"
    
    # Get the directory entries for DIRECTORY.
    entries = svn.fs.svn_fs_dir_entries(root, directory, pool)

    # Use an iteration subpool.
    subpool = svn.core.svn_pool_create(pool)

    # Loop over the entries.
    names = entries.keys()
    for name in names:
        # Clear the iteration subpool.
        svn.core.svn_pool_clear(subpool)

        # Calculate the entry's full path.
        full_path = directory + '/' + name

        # If the entry is a directory, recurse.  The recursion will return
        # a list with the entry and all its children, which we will add to
        # our running list of paths.
        if svn.fs.svn_fs_is_dir(root, full_path, subpool):
            crawl_filesystem_dir(root, full_path, subpool)
        else:
            # Else it's a file, so print its path here.
            print full_path

    # Destroy the iteration subpool.
    svn.core.svn_pool_destroy(subpool)

def crawl_youngest(pool, repos_path):
    """Open the repository at REPOS_PATH, and recursively crawl its
    youngest revision."""
    
    # Open the repository at REPOS_PATH, and get a reference to its
    # versioning filesystem.
    repos_obj = svn.repos.svn_repos_open(repos_path, pool)
    fs_obj = svn.repos.svn_repos_fs(repos_obj)

    # Query the current youngest revision.
    youngest_rev = svn.fs.svn_fs_youngest_rev(fs_obj, pool)
    
    # Open a root object representing the youngest (HEAD) revision.
    root_obj = svn.fs.svn_fs_revision_root(fs_obj, youngest_rev, pool)

    # Do the recursive crawl.
    crawl_filesystem_dir(root_obj, "", pool)
    
if __name__ == "__main__":
    # Check for sane usage.
    if len(sys.argv) != 2:
        sys.stderr.write("Usage: %s REPOS_PATH\n"
                         % (os.path.basename(sys.argv[0])))
        sys.exit(1)

    # Canonicalize (enough for Subversion, at least) the repository path.
    repos_path = os.path.normpath(sys.argv[1])
    if repos_path == '.': 
        repos_path = ''

    # Call the app-wrapper, which takes care of APR initialization/shutdown
    # and the creation and cleanup of our top-level memory pool.
    svn.core.run_app(crawl_youngest, repos_path)


This same program in C would need to deal with custom datatypes (such as those provided by the APR library) for representing the hash of entries and the list of paths, but Python has hashes (called dictionaries) and lists as built-in datatypes, and provides a rich collection of functions for operating on those types. So SWIG (with the help of some customizations in Subversion's language bindings layer) takes care of mapping those custom datatypes into the native datatypes of the target language. This provides a more intuitive interface for users of that language.

The Subversion Python bindings can be used for working copy operations, too. In the previous section of this chapter, we mentioned the libsvn_client interface, and how it exists for the sole purpose of simplifying the process of writing a Subversion client. The following is a brief example of how that library can be accessed via the SWIG bindings to recreate a scaled-down version of the svn status command.

Eksempel 8.3. A Python Status Crawler

#!/usr/bin/env python

"""Crawl a working copy directory, printing status information."""

import sys
import os.path
import getopt
import svn.core, svn.client, svn.wc

def generate_status_code(status):
    """Translate a status value into a single-character status code,
    using the same logic as the Subversion command-line client."""

    if status == svn.wc.svn_wc_status_none:
        return ' '
    if status == svn.wc.svn_wc_status_normal:
        return ' '
    if status == svn.wc.svn_wc_status_added:
        return 'A'
    if status == svn.wc.svn_wc_status_missing:
        return '!'
    if status == svn.wc.svn_wc_status_incomplete:
        return '!'
    if status == svn.wc.svn_wc_status_deleted:
        return 'D'
    if status == svn.wc.svn_wc_status_replaced:
        return 'R'
    if status == svn.wc.svn_wc_status_modified:
        return 'M'
    if status == svn.wc.svn_wc_status_merged:
        return 'G'
    if status == svn.wc.svn_wc_status_conflicted:
        return 'C'
    if status == svn.wc.svn_wc_status_obstructed:
        return '~'
    if status == svn.wc.svn_wc_status_ignored:
        return 'I'
    if status == svn.wc.svn_wc_status_external:
        return 'X'
    if status == svn.wc.svn_wc_status_unversioned:
        return '?'
    return '?'

def do_status(pool, wc_path, verbose):
    # Calculate the length of the input working copy path.
    wc_path_len = len(wc_path)

    # Build a client context baton.
    ctx = svn.client.svn_client_ctx_t()

    def _status_callback(path, status, root_path_len=wc_path_len):
        """A callback function for svn_client_status."""

        # Print the path, minus the bit that overlaps with the root of
        # the status crawl
        text_status = generate_status_code(status.text_status)
        prop_status = generate_status_code(status.prop_status)
        print '%s%s  %s' % (text_status, prop_status, path[wc_path_len + 1:])
        
    # Do the status crawl, using _status_callback() as our callback function.
    svn.client.svn_client_status(wc_path, None, _status_callback,
                                 1, verbose, 0, 0, ctx, pool)

def usage_and_exit(errorcode):
    """Print usage message, and exit with ERRORCODE."""
    stream = errorcode and sys.stderr or sys.stdout
    stream.write("""Usage: %s OPTIONS WC-PATH
Options:
  --help, -h    : Show this usage message
  --verbose, -v : Show all statuses, even uninteresting ones
""" % (os.path.basename(sys.argv[0])))
    sys.exit(errorcode)
    
if __name__ == '__main__':
    # Parse command-line options.
    try:
        opts, args = getopt.getopt(sys.argv[1:], "hv", ["help", "verbose"])
    except getopt.GetoptError:
        usage_and_exit(1)
    verbose = 0
    for opt, arg in opts:
        if opt in ("-h", "--help"):
            usage_and_exit(0)
        if opt in ("-v", "--verbose"):
            verbose = 1
    if len(args) != 1:
        usage_and_exit(2)
            
    # Canonicalize (enough for Subversion, at least) the working copy path.
    wc_path = os.path.normpath(args[0])
    if wc_path == '.': 
        wc_path = ''

    # Call the app-wrapper, which takes care of APR initialization/shutdown
    # and the creation and cleanup of our top-level memory pool.
    svn.core.run_app(do_status, wc_path, verbose)


Subversion's language bindings unfortunately tend to lack the level of attention given to the core Subversion modules. However, there have been significant efforts towards creating functional bindings for Python, Perl, and Ruby. To some extent, the work done preparing the SWIG interface files for these languages is reusable in efforts to generate bindings for other languages supported by SWIG (which includes versions of C#, Guile, Java, MzScheme, OCaml, PHP, Tcl, and others). However, some extra programming is required to compensate for complex APIs that SWIG needs some help interfacing with. For more information on SWIG itself, see the project's website at http://www.swig.org/.

Inside the Working Copy Administration Area

As we mentioned earlier, each directory of a Subversion working copy contains a special subdirectory called .svn which houses administrative data about that working copy directory. Subversion uses the information in .svn to keep track of things like:

  • Which repository location(s) are represented by the files and subdirectories in the working copy directory.

  • What revision of each of those files and directories are currently present in the working copy.

  • Any user-defined properties that might be attached to those files and directories.

  • Pristine (un-edited) copies of the working copy files.

While there are several other bits of data stored in the .svn directory, we will examine only a couple of the most important items.

The Entries File

Perhaps the single most important file in the .svn directory is the entries file. The entries file is an XML document which contains the bulk of the administrative information about a versioned resource in a working copy directory. It is this one file which tracks the repository URLs, pristine revision, file checksums, pristine text and property timestamps, scheduling and conflict state information, last-known commit information (author, revision, timestamp), local copy history—practically everything that a Subversion client is interested in knowing about a versioned (or to-be-versioned) resource!

The following is an example of an actual entries file:

Eksempel 8.4. Contents of a Typical .svn/entries File

<?xml version="1.0" encoding="utf-8"?>
<wc-entries
   xmlns="svn:">
<entry
   committed-rev="1"
   name=""
   committed-date="2005-04-04T13:32:28.526873Z"
   url="http://svn.red-bean.com/repos/greek-tree/A/D"
   last-author="jrandom"
   kind="dir"
   uuid="4e820d15-a807-0410-81d5-aa59edf69161"
   revision="1"/>
<entry
   name="lambda"
   copied="true"
   kind="file"
   copyfrom-rev="1"
   schedule="add"
   copyfrom-url="http://svn.red-bean.com/repos/greek-tree/A/B/lambda"/>
<entry
   committed-rev="1"
   name="gamma"
   text-time="2005-12-11T16:32:46.000000Z"
   committed-date="2005-04-04T13:32:28.526873Z"
   checksum="ada10d942b1964d359e048dbacff3460"
   last-author="jrandom"
   kind="file"
   prop-time="2005-12-11T16:32:45.000000Z"/>
<entry
   name="zeta"
   kind="file"
   schedule="add"
   revision="0"/>
<entry
   name="G"
   kind="dir"/>
<entry
   name="H"
   kind="dir"
   schedule="delete"/>
</wc-entries>


As you can see, the entries file is essentially a list of entries. Each entry tag represents one of three things: the working copy directory itself (called the this directory entry, and noted as having an empty value for its name attribute), a file in that working copy directory (noted by having its kind attribute set to "file"), or a subdirectory in that working copy (kind here is set to "dir"). The files and subdirectories whose entries are stored in this file are either already under version control, or (as in the case of the file named zeta above) are scheduled to be added to version control when the user next commits this working copy directory's changes. Each entry has a unique name, and each entry has a node kind.

Developers should be aware of some special rules that Subversion uses when reading and writing its entries files. While each entry has a revision and URL associated with it, note that not every entry tag in the sample file has explicit revision or url attributes attached to it. Subversion allows entries to not explicitly store those two attributes when their values are the same as (in the revision case) or trivially calculable from [48] (in the url case) the data stored in the this directory entry. Note also that for subdirectory entries, Subversion stores only the crucial attributes—name, kind, url, revision, and schedule. In an effort to reduce duplicated information, Subversion dictates that the method for determining the full set of information about a subdirectory is to traverse down into that subdirectory, and read the this directory entry from its own .svn/entries file. However, a reference to the subdirectory is kept in its parent's entries file, with enough information to permit basic versioning operations in the event that the subdirectory itself is actually missing from disk.

Pristine Copies and Property Files

As mentioned before, the .svn directory also holds the pristine text-base versions of files. Those can be found in .svn/text-base. The benefits of these pristine copies are multiple—network-free checks for local modifications and difference reporting, network-free reversion of modified or missing files, smaller transmission of changes to the server—but comes at the cost of having each versioned file stored at least twice on disk. These days, this seems to be a negligible penalty for most files. However, the situation gets uglier as the size of your versioned files grows. Some attention is being given to making the presence of the text-base an option. Ironically though, it is as your versioned files' sizes get larger that the existence of the text-base becomes more crucial—who wants to transmit a huge file across a network just because they want to commit a tiny change to it?

Similar in purpose to the text-base files are the property files and their pristine prop-base copies, located in .svn/props and .svn/prop-base respectively. Since directories can have properties, too, there are also .svn/dir-props and .svn/dir-prop-base files. Each of these property files (working and base versions) uses a simple hash-on-disk file format for storing the property names and values.

WebDAV

WebDAV (shorthand for Web-based Distributed Authoring and Versioning) is an extension of the standard HTTP protocol designed to make the web into a read/write medium, instead of the basically read-only medium that exists today. The theory is that directories and files can be shared—as both readable and writable objects—over the web. RFCs 2518 and 3253 describe the WebDAV/DeltaV extensions to HTTP, and are available (along with a lot of other useful information) at http://www.webdav.org/.

A number of operating system file browsers are already able to mount networked directories using WebDAV. On Win32, the Windows Explorer can browse what it calls Web Folders (which are just WebDAV-ready network locations) as if they were regular shared folders. Mac OS X also has this capability, as do the Nautilus and Konqueror browsers (under GNOME and KDE, respectively).

How does all of this apply to Subversion? The mod_dav_svn Apache module uses HTTP, extended by WebDAV and DeltaV, as one of its network protocols. Subversion uses mod_dav_svn to map between Subversion's versioning concepts and those of RFCs 2518 and 3253.

For a more thorough discussion of WebDAV, how it works, and how Subversion uses it, see Tillegg C, WebDAV and Autoversioning. Among other things, that appendix discusses the degree to which Subversion adheres to the generic WebDAV specification, and how that affects interoperability with generic WebDAV clients.




[45] We understand that this may come as a shock to sci-fi fans who have long been under the impression that Time was actually the fourth dimension, and we apologize for any emotional trauma induced by our assertion of a different theory.

[46] Subversion uses ANSI system calls and datatypes as much as possible.

[47] Neon and Berkeley DB are examples of such libraries.

[48] That is, the URL for the entry is the same as the concatenation of the parent directory's URL and the entry's name.

Kapittel 9. Subversion Complete Reference

This chapter is intended to be a complete reference to using Subversion. This includes the command line client (svn) and all its subcommands, as well as the repository administration programs (svnadmin and svnlook) and their respective subcommands.

The Subversion Command Line Client: svn

To use the command line client, you type svn, the subcommand you wish to use [49], and any switches or targets that you wish to operate on—there is no specific order that the subcommand and the switches must appear in. For example, all of the following are valid ways to use svn status:

$ svn -v status
$ svn status -v 
$ svn status -v myfile

You can find many more examples of how to use most client commands in Kapittel 2, Grunnleggende bruk and commands for managing properties in “Egenskaper”.

svn Switches

While Subversion has different switches for its subcommands, all switches are global—that is, each switch is guaranteed to mean the same thing regardless of the subcommand you use it with. For example, --verbose (-v) always means verbose output, regardless of the subcommand you use it with.

--auto-props

Enables auto-props, overriding the enable-auto-props directive in the config file.

--config-dir DIR

Instructs Subversion to read configuration information from the specified directory instead of the default location (.subversion in the user's home directory).

--diff-cmd CMD

Specifies an external program to use to show differences between files. When svn diff is invoked, it uses Subversion's internal diff engine, which provides unified diffs by default. If you want to use an external diff program, use --diff-cmd. You can pass switches to the diff program with the --extensions switch (more on that later in this section).

--diff3-cmd CMD

Specifies an external program to use to merge files.

--dry-run

Goes through all the motions of running a command, but makes no actual changes—either on disk or in the repository.

--editor-cmd CMD

Specifies an external program to use to edit a log message or a property value. See the editor-cmd section in “Konfigurasjon” for ways to specify a default editor.

--encoding ENC

Tells Subversion that your commit message is encoded in the charset provided. The default is your operating system's native locale, and you should specify the encoding if your commit message is in any other encoding.

--extensions (-x) ARGS

Specifies an argument or arguments that Subversion should pass to an external diff command when providing differences between files. If you wish to pass multiple arguments, you must enclose all of them in quotes (for example, svn diff --diff-cmd /usr/bin/diff -x "-b -E"). This switch can only be used if you also pass the --diff-cmd switch.

--file (-F) FILENAME

Uses the contents of the file passed as an argument to this switch for the specified subcommand.

--force

Forces a particular command or operation to run. There are some operations that Subversion will prevent you from doing in normal usage, but you can pass the force switch to tell Subversion I know what I'm doing as well as the possible repercussions of doing it, so let me at 'em. This switch is the programmatic equivalent of doing your own electrical work with the power on—if you don't know what you're doing, you're likely to get a nasty shock.

--force-log

Forces a suspicious parameter passed to the --message (-m) or --file (-F) options to be accepted as valid. By default, Subversion will produce an error if parameters to these options look like they might instead be targets of the subcommand. For example, if you pass a versioned file's path to the --file (-F) option, Subversion will assume you've made a mistake, that the path was instead intended as the target of the operation, and that you simply failed to provide some other—unversioned—file as the source of your log message. To assert your intent and override these types of errors, pass the --force-log option to subcommands that accept log messages.

--help (-h or -?)

If used with one or more subcommands, shows the built-in help text for each subcommand. If used alone, it displays the general client help text.

--ignore-ancestry

Tells Subversion to ignore ancestry when calculating differences (rely on path contents alone).

--ignore-externals

Tells Subversion to ignore external definitions and the external working copies managed by them.

--incremental

Prints output in a format suitable for concatenation.

--limit NUM

Show only the first NUM log messages.

--message (-m) MESSAGE

Indicates that you will specify a commit message on the command line, following this switch. For example:

$ svn commit -m "They don't make Sunday."
--new ARG

Uses ARG as the newer target.

--no-auth-cache

Prevents caching of authentication information (e.g. username and password) in the Subversion administrative directories.

--no-auto-props

Disables auto-props, overriding the enable-auto-props directive in the config file.

--no-diff-added

Prevents Subversion from printing differences for added files. The default behavior when you add a file is for svn diff to print the same differences that you would see if you had added the entire contents of an existing (empty) file.

--no-diff-deleted

Prevents Subversion from printing differences for deleted files. The default behavior when you remove a file is for svn diff to print the same differences that you would see if you had left the file but removed all the content.

--no-ignore

Shows files in the status listing that would normally be omitted since they match a pattern in the global-ignores configuration option or the svn:ignore property. See “Konfigurasjon” and “Ignoring Unversioned Items” for more information.

--no-unlock

Don't automatically unlock files (the default commit behavior is to unlock all files listed as part of the commit). See “Locking” for more information.

--non-interactive

In the case of an authentication failure, or insufficient credentials, prevents prompting for credentials (e.g. username or password). This is useful if you're running Subversion inside of an automated script and it's more appropriate to have Subversion fail than to prompt for more information.

--non-recursive (-N)

Stops a subcommand from recursing into subdirectories. Most subcommands recurse by default, but some subcommands—usually those that have the potential to remove or undo your local modifications—do not.

--notice-ancestry

Pay attention to ancestry when calculating differences.

--old ARG

Uses ARG as the older target.

--password PASS

Indicates that you are providing your password for authentication on the command line—otherwise, if it is needed, Subversion will prompt you for it.

--quiet (-q)

Requests that the client print only essential information while performing an operation.

--recursive (-R)

Makes a subcommand recurse into subdirectories. Most subcommands recurse by default.

--relocate FROM TO [PATH...]

Used with the svn switch subcommand, changes the location of the repository that your working copy references. This is useful if the location of your repository changes and you have an existing working copy that you'd like to continue to use. See svn switch for an example.

--revision (-r) REV

Indicates that you're going to supply a revision (or range of revisions) for a particular operation. You can provide revision numbers, revision keywords or dates (in curly braces), as arguments to the revision switch. If you wish to provide a range of revisions, you can provide two revisions separated by a colon. For example:

$ svn log -r 1729
$ svn log -r 1729:HEAD
$ svn log -r 1729:1744
$ svn log -r {2001-12-04}:{2002-02-17}
$ svn log -r 1729:{2002-02-17}

See “Nøkkelord for revisjoner” for more information.

--revprop

Operates on a revision property instead of a Subversion property specific to a file or directory. This switch requires that you also pass a revision with the --revision (-r) switch. See “Uversjonerte egenskaper” for more details on unversioned properties.

--show-updates (-u)

Causes the client to display information about which files in your working copy are out-of-date. This doesn't actually update any of your files—it just shows you which files will be updated if you run svn update.

--stop-on-copy

Causes a Subversion subcommand which is traversing the history of a versioned resource to stop harvesting that historical information when a copy—that is, a location in history where that resource was copied from another location in the repository—is encountered.

--strict

Causes Subversion to use strict semantics, a notion which is rather vague unless talking about specific subcommands.

--targets FILENAME

Tells Subversion to get the list of files that you wish to operate on from the filename you provide instead of listing all the files on the command line.

--username NAME

Indicates that you are providing your username for authentication on the command line—otherwise, if it is needed, Subversion will prompt you for it.

--verbose (-v)

Requests that the client print out as much information as it can while running any subcommand. This may result in Subversion printing out additional fields, detailed information about every file, or additional information regarding its actions.

--version

Prints the client version info. This information not only includes the version number of the client, but also a listing of all repository access modules that the client can use to access a Subversion repository. With --quiet (-q) it prints only the version number in a compact form.

--xml

Prints output in XML format.

svn Subcommands

Navn

svn add — Add files, directories, or symbolic links.

Synopsis

svn add PATH...

Description

Add files, directories, or symbolic links to your working copy and schedule them for addition to the repository. They will be uploaded and added to the repository on your next commit. If you add something and change your mind before committing, you can unschedule the addition using svn revert.

Alternate Names

None

Changes

Working Copy

Accesses Repository

No

Switches

--targets FILENAME
--non-recursive (-N)
--quiet (-q)
--config-dir DIR
--auto-props
--no-auto-props
--force

Examples

To add a file to your working copy:

$ svn add foo.c 
A         foo.c

When adding a directory, the default behavior of svn add is to recurse:

$ svn add testdir
A         testdir
A         testdir/a
A         testdir/b
A         testdir/c
A         testdir/d

You can add a directory without adding its contents:

$ svn add --non-recursive otherdir
A         otherdir

Normally, the command svn add * will skip over any directories that are already under version control. Sometimes, however, you may want to add every unversioned object in your working copy, including those hiding deeper down. Passing the --force option makes svn add recurse into versioned directories:

$ svn add * --force
A         foo.c
A         somedir/bar.c
A         otherdir/docs/baz.doc
…

Navn

svn blame — Show author and revision information in-line for the specified files or URLs.

Synopsis

svn blame TARGET[@REV]...

Description

Show author and revision information in-line for the specified files or URLs. Each line of text is annotated at the beginning with the author (username) and the revision number for the last change to that line.

Alternate Names

praise, annotate, ann

Changes

Nothing

Accesses Repository

Yes

Switches

--revision (-r) REV
--username USER
--password PASS
--no-auth-cache
--non-interactive
--config-dir DIR
--verbose (-v)

Examples

If you want to see blame annotated source for readme.txt in your test repository:

$ svn blame http://svn.red-bean.com/repos/test/readme.txt
     3      sally This is a README file.
     5      harry You should read this.

Navn

svn cat — Output the contents of the specified files or URLs.

Synopsis

svn cat TARGET[@REV]...

Description

Output the contents of the specified files or URLs. For listing the contents of directories, see svn list.

Alternate Names

None

Changes

Nothing

Accesses Repository

Yes

Switches

--revision (-r) REV
--username USER
--password PASS
--no-auth-cache
--non-interactive
--config-dir DIR

Examples

If you want to view readme.txt in your repository without checking it out:

$ svn cat http://svn.red-bean.com/repos/test/readme.txt
This is a README file.
You should read this.
[Tips]Tips

If your working copy is out of date (or you have local modifications) and you want to see the HEAD revision of a file in your working copy, svn cat will automatically fetch the HEAD revision when you give it a path:

$ cat foo.c
This file is in my local working copy 
and has changes that I've made.

$ svn cat foo.c
Latest revision fresh from the repository!

Navn

svn checkout — Check out a working copy from a repository.

Synopsis

svn checkout URL[@REV]... [PATH]

Description

Check out a working copy from a repository. If PATH is omitted, the basename of the URL will be used as the destination. If multiple URLs are given each will be checked out into a subdirectory of PATH, with the name of the subdirectory being the basename of the URL.

Alternate Names

co

Changes

Creates a working copy.

Accesses Repository

Yes

Switches

--revision (-r) REV
--quiet (-q)
--non-recursive (-N)
--username USER
--password PASS
--no-auth-cache
--non-interactive
--ignore-externals
--config-dir DIR

Examples

Check out a working copy into a directory called mine:

$ svn checkout file:///tmp/repos/test mine
A  mine/a
A  mine/b
Checked out revision 2.
$ ls
mine

Check out 2 different directories into two separate working copies:

$ svn checkout file:///tmp/repos/test  file:///tmp/repos/quiz
A  test/a
A  test/b
Checked out revision 2.
A  quiz/l
A  quiz/m
Checked out revision 2.
$ ls
quiz  test

Check out 2 different directories into two separate working copies, but place both into a directory called working-copies:

$ svn checkout file:///tmp/repos/test  file:///tmp/repos/quiz working-copies
A  working-copies/test/a
A  working-copies/test/b
Checked out revision 2.
A  working-copies/quiz/l
A  working-copies/quiz/m
Checked out revision 2.
$ ls
working-copies

If you interrupt a checkout (or something else interrupts your checkout like loss of connectivity, etc.), you can restart it either by issuing the identical checkout command again, or by updating the incomplete working copy:

$ svn checkout file:///tmp/repos/test test
A  test/a
A  test/b
^C
svn: The operation was interrupted
svn: caught SIGINT

$ svn checkout file:///tmp/repos/test test
A  test/c
A  test/d
^C
svn: The operation was interrupted
svn: caught SIGINT

$ cd test
$ svn update
A  test/e
A  test/f
Updated to revision 3.

Navn

svn cleanup — Recursively clean up the working copy.

Synopsis

svn cleanup [PATH...]

Description

Recursively clean up the working copy, removing working copy locks and resuming unfinished operations. If you ever get a working copy locked error, run this command to remove stale locks and get your working copy into a usable state again.

If, for some reason, an svn update fails due to a problem running an external diff program (e.g. user input or network failure), pass the --diff3-cmd to allow cleanup to complete any merging with your external diff program. You can also specify any configuration directory with the --config-dir switch, but you should need these switches extremely infrequently.

Alternate Names

None

Changes

Working copy

Accesses Repository

No

Switches

--diff3-cmd CMD
--config-dir DIR

Examples

Well, there's not much to the examples here as svn cleanup generates no output. If you pass no PATH, . is used.

$ svn cleanup

$ svn cleanup /path/to/working-copy

Navn

svn commit — Send changes from your working copy to the repository.

Synopsis

svn commit [PATH...]

Description

Send changes from your working copy to the repository. If you do not supply a log message with your commit by using either the --file or --message switch, svn will launch your editor for you to compose a commit message. See the editor-cmd section in “Konfigurasjon”.

svn commit will send found lock tokens and release locks on all PATHS committed (recursively) unless --no-unlock is passed.

[Tips]Tips

If you begin a commit and Subversion launches your editor to compose the commit message, you can still abort without committing your changes. If you want to cancel your commit, just quit your editor without saving your commit message and Subversion will prompt you to either abort the commit, continue with no message, or edit the message again.

Alternate Names

ci (short for check in; not co, which is short for checkout)

Changes

Working copy, repository

Accesses Repository

Yes

Switches

--message (-m) TEXT
--file (-F) FILE
--quiet (-q)
--no-unlock
--non-recursive (-N)
--targets FILENAME
--force-log
--username USER
--password PASS
--no-auth-cache
--non-interactive
--encoding ENC
--config-dir DIR

Examples

Commit a simple modification to a file with the commit message on the command line and an implicit target of your current directory (.):

$ svn commit -m "added howto section."
Sending        a
Transmitting file data .
Committed revision 3.

Commit a modification to the file foo.c (explicitly specified on the command line) with the commit message in a file named msg:

$ svn commit -F msg foo.c
Sending        foo.c
Transmitting file data .
Committed revision 5.

If you want to use a file that's under version control for your commit message with --file, you need to pass the --force-log switch:

$ svn commit --file file_under_vc.txt foo.c
svn: The log message file is under version control
svn: Log message file is a versioned file; use '--force-log' to override

$ svn commit --force-log --file file_under_vc.txt foo.c
Sending        foo.c
Transmitting file data .
Committed revision 6.

To commit a file scheduled for deletion:

$ svn commit -m "removed file 'c'."
Deleting       c

Committed revision 7.

Navn

svn copy — Copy a file or directory in a working copy or in the repository.

Synopsis

svn copy SRC DST

Description

Copy a file in a working copy or in the repository. SRC and DST can each be either a working copy (WC) path or URL:

WC -> WC

Copy and schedule an item for addition (with history).

WC -> URL

Immediately commit a copy of WC to URL.

URL -> WC

Check out URL into WC, and schedule it for addition.

URL -> URL

Complete server-side copy. This is usually used to branch and tag.

[Notat]Notat

You can only copy files within a single repository. Subversion does not support cross-repository copying.

Alternate Names

cp

Changes

Repository if destination is a URL.

Working copy if destination is a WC path.

Accesses Repository

If source or destination is in the repository, or if needed to look up the source revision number.

Switches

--message (-m) TEXT
--file (-F) FILE
--revision (-r) REV
--quiet (-q)
--username USER
--password PASS
--no-auth-cache
--non-interactive
--force-log
--editor-cmd EDITOR
--encoding ENC
--config-dir DIR

Examples

Copy an item within your working copy (just schedules the copy—nothing goes into the repository until you commit):

$ svn copy foo.txt bar.txt
A         bar.txt
$ svn status
A  +   bar.txt

Copy an item in your working copy to a URL in the repository (an immediate commit, so you must supply a commit message):

$ svn copy near.txt file:///tmp/repos/test/far-away.txt -m "Remote copy."

Committed revision 8.

Copy an item from the repository to your working copy (just schedules the copy—nothing goes into the repository until you commit):

[Tips]Tips

This is the recommended way to resurrect a dead file in your repository!

$ svn copy file:///tmp/repos/test/far-away near-here
A         near-here

And finally, copying between two URLs:

$ svn copy file:///tmp/repos/test/far-away file:///tmp/repos/test/over-there -m "remote copy."

Committed revision 9.
[Tips]Tips

This is the easiest way to tag a revision in your repository—just svn copy that revision (usually HEAD) into your tags directory.

$ svn copy file:///tmp/repos/test/trunk file:///tmp/repos/test/tags/0.6.32-prerelease -m "tag tree"

Committed revision 12.

And don't worry if you forgot to tag—you can always specify an older revision and tag anytime:

$ svn copy -r 11 file:///tmp/repos/test/trunk file:///tmp/repos/test/tags/0.6.32-prerelease -m "Forgot to tag at rev 11"

Committed revision 13.

Navn

svn delete — Delete an item from a working copy or the repository.

Synopsis

svn delete PATH...
svn delete URL...

Description

Items specified by PATH are scheduled for deletion upon the next commit. Files (and directories that have not been committed) are immediately removed from the working copy. The command will not remove any unversioned or modified items; use the --force switch to override this behavior.

Items specified by URL are deleted from the repository via an immediate commit. Multiple URLs are committed atomically.

Alternate Names

del, remove, rm

Changes

Working copy if operating on files, Repository if operating on URLs

Accesses Repository

Only if operating on URLs

Switches

--force
--force-log
--message (-m) TEXT
--file (-F) FILE
--quiet (-q)
--targets FILENAME
--username USER
--password PASS
--no-auth-cache
--non-interactive
--editor-cmd EDITOR
--encoding ENC
--config-dir DIR

Examples

Using svn to delete a file from your working copy merely schedules it to be deleted. When you commit, the file is deleted in the repository.

$ svn delete myfile
D         myfile

$ svn commit -m "Deleted file 'myfile'."
Deleting       myfile
Transmitting file data .
Committed revision 14.

Deleting a URL, however, is immediate, so you have to supply a log message:

$ svn delete -m "Deleting file 'yourfile'" file:///tmp/repos/test/yourfile

Committed revision 15.

Here's an example of how to force deletion of a file that has local mods:

$ svn delete over-there 
svn: Attempting restricted operation for modified resource
svn: Use --force to override this restriction
svn: 'over-there' has local modifications

$ svn delete --force over-there 
D         over-there

Navn

svn diff — Display the differences between two paths.

Synopsis

diff [-r N[:M]] [TARGET[@REV]...]
diff [-r N[:M]] --old OLD-TGT[@OLDREV] [--new NEW-TGT[@NEWREV]] [PATH...]
diff OLD-URL[@OLDREV] NEW-URL[@NEWREV]

Description

Display the differences between two paths. The three different ways you can use svn diff are:

svn diff [-r N[:M]] [--old OLD-TGT] [--new NEW-TGT] [PATH...] displays the differences between OLD-TGT and NEW-TGT. If PATHs are given, they are treated as relative to OLD-TGT and NEW-TGT and the output is restricted to differences in only those paths. OLD-TGT and NEW-TGT may be working copy paths or URL[@REV]. OLD-TGT defaults to the current working directory and NEW-TGT defaults to OLD-TGT. N defaults to BASE or, if OLD-TGT is a URL, to HEAD. M defaults to the current working version or, if NEW-TGT is a URL, to HEAD. svn diff -r N sets the revision of OLD-TGT to N, svn diff -r N:M also sets the revision of NEW-TGT to M.

svn diff -r N:M URL is shorthand for svn diff -r N:M --old=URL --new=URL.

svn diff [-r N[:M]] URL1[@N] URL2[@M] is shorthand for svn diff [-r N[:M]] --old=URL1 --new=URL2.

If TARGET is a URL, then revs N and M can be given either via the --revision or by using @ notation as described earlier.

If TARGET is a working copy path, then the --revision switch means:

--revision N:M

The server compares TARGET@N and TARGET@M.

--revision N

The client compares TARGET@N against working copy.

(no --revision)

The client compares base and working copies of TARGET.

If the alternate syntax is used, the server compares URL1 and URL2 at revisions N and M respectively. If either N or M are omitted, a value of HEAD is assumed.

By default, svn diff ignores the ancestry of files and merely compares the contents of the two files being compared. If you use --notice-ancestry, the ancestry of the paths in question will be taken into consideration when comparing revisions (that is, if you run svn diff on two files with identical contents but different ancestry you will see the entire contents of the file as having been removed and added again).

Alternate Names

di

Changes

Nothing

Accesses Repository

For obtaining differences against anything but BASE revision in your working copy

Switches

--revision (-r) REV
--old OLD-TARGET
--new NEW-TARGET
--extensions (-x) "ARGS"
--non-recursive (-N)
--diff-cmd CMD
--notice-ancestry
--username USER
--password PASS
--no-auth-cache
--non-interactive
--no-diff-deleted
--config-dir DIR

Examples

Compare BASE and your working copy (one of the most popular uses of svn diff):

$ svn diff COMMITTERS 
Index: COMMITTERS
===================================================================
--- COMMITTERS	(revision 4404)
+++ COMMITTERS	(working copy)

See how your working copy's modifications compare against an older revision:

$ svn diff -r 3900 COMMITTERS 
Index: COMMITTERS
===================================================================
--- COMMITTERS	(revision 3900)
+++ COMMITTERS	(working copy)

Compare revision 3000 to revision 3500 using @ syntax:

$ svn diff http://svn.collab.net/repos/svn/trunk/COMMITTERS@3000 http://svn.collab.net/repos/svn/trunk/COMMITTERS@3500
Index: COMMITTERS
===================================================================
--- COMMITTERS	(revision 3000)
+++ COMMITTERS	(revision 3500)
…

Compare revision 3000 to revision 3500 using range notation (you only pass the one URL in this case):

$ svn diff -r 3000:3500 http://svn.collab.net/repos/svn/trunk/COMMITTERS
Index: COMMITTERS
===================================================================
--- COMMITTERS	(revision 3000)
+++ COMMITTERS	(revision 3500)

Compare revision 3000 to revision 3500 of all files in trunk using range notation:

$ svn diff -r 3000:3500 http://svn.collab.net/repos/svn/trunk
          

Compare revision 3000 to revision 3500 of only three files in trunk using range notation:

$ svn diff -r 3000:3500 --old http://svn.collab.net/repos/svn/trunk COMMITTERS README HACKING
          

If you have a working copy, you can obtain the differences without typing in the long URLs:

$ svn diff -r 3000:3500 COMMITTERS 
Index: COMMITTERS
===================================================================
--- COMMITTERS	(revision 3000)
+++ COMMITTERS	(revision 3500)

Use --diff-cmd CMD -x to pass arguments directly to the external diff program

$ svn diff --diff-cmd /usr/bin/diff -x "-i -b" COMMITTERS 
Index: COMMITTERS
===================================================================
0a1,2
> This is a test
> 

Navn

svn export — Export a clean directory tree.

Synopsis

svn export [-r REV] URL[@PEGREV] [PATH]
svn export [-r REV] PATH1[@PEGREV] [PATH2]

Description

The first form exports a clean directory tree from the repository specified by URL, at revision REV if it is given, otherwise at HEAD, into PATH. If PATH is omitted, the last component of the URL is used for the local directory name.

The second form exports a clean directory tree from the working copy specified by PATH1 into PATH2. All local changes will be preserved, but files not under version control will not be copied.

Alternate Names

None

Changes

Local disk

Accesses Repository

Only if exporting from a URL

Switches

--revision (-r) REV
--quiet (-q)
--force
--username USER
--password PASS
--no-auth-cache
--non-interactive
--non-recursive (-N)
--config-dir DIR
--native-eol EOL
--ignore-externals

Examples

Export from your working copy (doesn't print every file and directory):

$ svn export a-wc my-export
Export complete.

Export directly from the repository (prints every file and directory):

$ svn export file:///tmp/repos my-export
A  my-export/test
A  my-export/quiz
…
Exported revision 15.

When rolling operating-system-specific release packages, it can be useful to export a tree which uses a specific EOL character for line endings. The --native-eol option will do this, but it only affects files that have svn:eol-style = native properties attached to them. For example, to export a tree with all CRLF line endings (possibly for a Windows .zip file distribution):

$ svn export file://tmp/repos my-export --native-eol CRLF
A  my-export/test
A  my-export/quiz
…
Exported revision 15.

Navn

svn help — Help!

Synopsis

svn help [SUBCOMMAND...]

Description

This is your best friend when you're using Subversion and this book isn't within reach!

Alternate Names

?, h

The options -?, -h and --help have the same effect as using the help subcommand.

Changes

Nothing

Accesses Repository

No

Switches

--version
--quiet (-q)
--config-dir DIR

Navn

svn import — Commit an unversioned file or tree into the repository.

Synopsis

svn import [PATH] URL

Description

Recursively commit a copy of PATH to URL. If PATH is omitted . is assumed. Parent directories are created in the repository as necessary.

Alternate Names

None

Changes

Repository

Accesses Repository

Yes

Switches

--message (-m) TEXT
--file (-F) FILE
--quiet (-q)
--non-recursive (-N)
--username USER
--password PASS
--no-auth-cache
--non-interactive
--force-log
--editor-cmd EDITOR
--encoding ENC
--config-dir DIR
--auto-props
--no-auto-props
--ignore-externals

Examples

This imports the local directory myproj into the root of your repository:

$ svn import -m "New import" myproj http://svn.red-bean.com/repos/test
Adding         myproj/sample.txt
…
Transmitting file data .........
Committed revision 16.

This imports the local directory myproj into trunk/misc in your repository. The directory trunk/misc need not exist before you import into it—svn import will recursively create directories for you:

$ svn import -m "New import" myproj \
    http://svn.red-bean.com/repos/test/trunk/misc/myproj
Adding         myproj/sample.txt
…
Transmitting file data .........
Committed revision 19.

After importing data, note that the original tree is not under version control. To start working, you still need to svn checkout a fresh working copy of the tree.


Navn

svn info — Display information about a local or remote item.

Synopsis

svn info [TARGET...]

Description

Print information about the working copy paths or URLs specified. The information shown for both may include:

  • Path

  • Name

  • URL

  • Repository Root

  • Repository UUID

  • Revision

  • Node Kind

  • Last Changed Author

  • Last Changed Revision

  • Last Changed Date

  • Lock Token

  • Lock Owner

  • Lock Created (date)

  • Lock Expires (date)

Additional kinds of information available only for working copy paths are:

  • Schedule

  • Copied From URL

  • Copied From Rev

  • Text Last Updated

  • Properties Last Updated

  • Checksum

  • Conflict Previous Base File

  • Conflict Previous Working File

  • Conflict Current Base File

  • Conflict Properties File

Alternate Names

None

Changes

Nothing

Accesses Repository

Only if operating on URLs

Switches

--revision (-r) REV
--recursive (-R)
--targets FILENAME
--incremental
--xml
--username USER
--password PASS
--no-auth-cache
--non-interactive
--config-dir DIR

Examples

svn info will show you all the useful information that it has for items in your working copy. It will show information for files:

$ svn info foo.c
Path: foo.c
Name: foo.c
URL: http://svn.red-bean.com/repos/test/foo.c
Repository Root: http://svn.red-bean.com/repos/test
Repository UUID: 5e7d134a-54fb-0310-bd04-b611643e5c25
Revision: 4417
Node Kind: file
Schedule: normal
Last Changed Author: sally
Last Changed Rev: 20
Last Changed Date: 2003-01-13 16:43:13 -0600 (Mon, 13 Jan 2003)
Text Last Updated: 2003-01-16 21:18:16 -0600 (Thu, 16 Jan 2003)
Properties Last Updated: 2003-01-13 21:50:19 -0600 (Mon, 13 Jan 2003)
Checksum: d6aeb60b0662ccceb6bce4bac344cb66

It will also show information for directories:

$ svn info vendors
Path: vendors
URL: http://svn.red-bean.com/repos/test/vendors
Repository Root: http://svn.red-bean.com/repos/test
Repository UUID: 5e7d134a-54fb-0310-bd04-b611643e5c25
Revision: 19
Node Kind: directory
Schedule: normal
Last Changed Author: harry
Last Changed Rev: 19
Last Changed Date: 2003-01-16 23:21:19 -0600 (Thu, 16 Jan 2003)
Properties Last Updated: 2003-01-16 23:39:02 -0600 (Thu, 16 Jan 2003)

svn info also acts on URLs (also note that the file readme.doc in this example is locked, so lock information is also provided):

$ svn info http://svn.red-bean.com/repos/test/readme.doc
Path: readme.doc
Name: readme.doc
URL: http://svn.red-bean.com/repos/test/readme.doc
Repository Root: http://svn.red-bean.com/repos/test
Repository UUID: 5e7d134a-54fb-0310-bd04-b611643e5c25
Revision: 1
Node Kind: file
Schedule: normal
Last Changed Author: sally
Last Changed Rev: 42
Last Changed Date: 2003-01-14 23:21:19 -0600 (Tue, 14 Jan 2003)
Lock Token: opaquelocktoken:14011d4b-54fb-0310-8541-dbd16bd471b2
Lock Owner: harry
Lock Created: 2003-01-15 17:35:12 -0600 (Wed, 15 Jan 2003)
Lock Comment (1 line):
My test lock comment

Navn

svn list — List directory entries in the repository.

Synopsis

svn list [TARGET[@REV]...]

Description

List each TARGET file and the contents of each TARGET directory as they exist in the repository. If TARGET is a working copy path, the corresponding repository URL will be used.

The default TARGET is ., meaning the repository URL of the current working copy directory.

With --verbose, the following fields show the status of the item:

  • Revision number of the last commit

  • Author of the last commit

  • Size (in bytes)

  • Date and time of the last commit

With --xml, output is in XML format (with a header and an enclosing document element unless --incremental is also specified). All of the information is present; the --verbose option is not accepted.

Alternate Names

ls

Changes

Nothing

Accesses Repository

Yes

Switches

--revision (-r) REV
--verbose (-v)
--recursive (-R)
--incremental
--xml
--username USER
--password PASS
--no-auth-cache
--non-interactive
--config-dir DIR

Examples

svn list is most useful if you want to see what files a repository has without downloading a working copy:

$ svn list http://svn.red-bean.com/repos/test/support
README.txt
INSTALL
examples/
…

You can pass the --verbose switch for additional information, rather like the UNIX command ls -l:

$ svn list --verbose file:///tmp/repos
     16 sally         28361 Jan 16 23:18 README.txt
     27 sally             0 Jan 18 15:27 INSTALL
     24 harry               Jan 18 11:27 examples/

For further details, see svn list.


Navn

svn lock — Lock working copy paths or URLs in the repository, so that no other user can commit changes to them.

Synopsis

svn lock TARGET...

Description

Lock each TARGET. If any TARGET is already locked by another user, print a warning and continue locking the rest of the TARGETs. Use --force to steal a lock from another user or working copy.

Alternate Names

None

Changes

Working Copy, Repository

Accesses Repository

Yes

Switches

--targets FILENAME
--message (-m) TEXT
--file (-F) FILE
--force-log
--encoding ENC
--username USER
--password PASS
--no-auth-cache
--non-interactive
--config-dir DIR
--force

Examples

Lock two files in your working copy:


$ svn lock tree.jpg house.jpg
'tree.jpg' locked by user 'harry'.
'house.jpg' locked by user 'harry'.

Lock a file in your working copy that is currently locked by another user:

$ svn lock tree.jpg
svn: warning: Path '/tree.jpg is already locked by user 'harry in \
     filesystem '/svn/repos/db'

$ svn lock --force foo
'tree.jpg' locked by user 'sally'.

Lock a file without a working copy:

$ svn lock http://svn.red-bean.com/repos/test/tree.jpg
'tree.jpg' locked by user 'sally'.

For further details, see “Locking”.


Navn

svn log — Display commit log messages.

Synopsis

svn log [PATH]
svn log URL [PATH...]

Description

The default target is the path of your current directory. If no arguments are supplied, svn log shows the log messages for all files and directories inside of (and including) the current working directory of your working copy. You can refine the results by specifying a path, one or more revisions, or any combination of the two. The default revision range for a local path is BASE:1.

If you specify a URL alone, then it prints log messages for everything that the URL contains. If you add paths past the URL, only messages for those paths under that URL will be printed. The default revision range for a URL is HEAD:1.

With --verbose, svn log will also print all affected paths with each log message. With --quiet, svn log will not print the log message body itself (this is compatible with --verbose).

Each log message is printed just once, even if more than one of the affected paths for that revision were explicitly requested. Logs follow copy history by default. Use --stop-on-copy to disable this behavior, which can be useful for determining branch points.

Alternate Names

None

Changes

Nothing

Accesses Repository

Yes

Switches

--revision (-r) REV
--quiet (-q)
--verbose (-v)
--targets FILENAME
--stop-on-copy
--incremental
--limit NUM
--xml
--username USER
--password PASS
--no-auth-cache
--non-interactive
--config-dir DIR

Examples

You can see the log messages for all the paths that changed in your working copy by running svn log from the top:

$ svn log
------------------------------------------------------------------------
r20 | harry | 2003-01-17 22:56:19 -0600 (Fri, 17 Jan 2003) | 1 line

Tweak.
------------------------------------------------------------------------
r17 | sally | 2003-01-16 23:21:19 -0600 (Thu, 16 Jan 2003) | 2 lines
…

Examine all log messages for a particular file in your working copy:

$ svn log foo.c
------------------------------------------------------------------------
r32 | sally | 2003-01-13 00:43:13 -0600 (Mon, 13 Jan 2003) | 1 line

Added defines.
------------------------------------------------------------------------
r28 | sally | 2003-01-07 21:48:33 -0600 (Tue, 07 Jan 2003) | 3 lines
…

If you don't have a working copy handy, you can log a URL:

$ svn log http://svn.red-bean.com/repos/test/foo.c
------------------------------------------------------------------------
r32 | sally | 2003-01-13 00:43:13 -0600 (Mon, 13 Jan 2003) | 1 line

Added defines.
------------------------------------------------------------------------
r28 | sally | 2003-01-07 21:48:33 -0600 (Tue, 07 Jan 2003) | 3 lines
…

If you want several distinct paths underneath the same URL, you can use the URL [PATH...] syntax.

$ svn log http://svn.red-bean.com/repos/test/ foo.c bar.c
------------------------------------------------------------------------
r32 | sally | 2003-01-13 00:43:13 -0600 (Mon, 13 Jan 2003) | 1 line

Added defines.
------------------------------------------------------------------------
r31 | harry | 2003-01-10 12:25:08 -0600 (Fri, 10 Jan 2003) | 1 line

Added new file bar.c
------------------------------------------------------------------------
r28 | sally | 2003-01-07 21:48:33 -0600 (Tue, 07 Jan 2003) | 3 lines
…

When you're concatenating the results of multiple calls to the log command, you may want to use the --incremental switch. svn log normally prints out a dashed line at the beginning of a log message, after each subsequent log message, and following the final log message. If you ran svn log on a range of two revisions, you would get this:

$ svn log -r 14:15
------------------------------------------------------------------------
r14 | …

------------------------------------------------------------------------
r15 | …

------------------------------------------------------------------------

However, if you wanted to gather 2 non-sequential log messages into a file, you might do something like this:

$ svn log -r 14 > mylog
$ svn log -r 19 >> mylog
$ svn log -r 27 >> mylog
$ cat mylog
------------------------------------------------------------------------
r14 | …

------------------------------------------------------------------------
------------------------------------------------------------------------
r19 | …

------------------------------------------------------------------------
------------------------------------------------------------------------
r27 | …

------------------------------------------------------------------------

You can avoid the clutter of the double dashed lines in your output by using the incremental switch:

$ svn log --incremental -r 14 > mylog
$ svn log --incremental -r 19 >> mylog
$ svn log --incremental -r 27 >> mylog
$ cat mylog
------------------------------------------------------------------------
r14 | …

------------------------------------------------------------------------
r19 | …

------------------------------------------------------------------------
r27 | …

The --incremental switch provides similar output control when using the --xml switch.

[Tips]Tips

If you run svn log on a specific path and provide a specific revision and get no output at all

$ svn log -r 20 http://svn.red-bean.com/untouched.txt
------------------------------------------------------------------------

That just means that the path was not modified in that revision. If you log from the top of the repository, or know the file that changed in that revision, you can specify it explicitly:

$ svn log -r 20 touched.txt 
------------------------------------------------------------------------
r20 | sally | 2003-01-17 22:56:19 -0600 (Fri, 17 Jan 2003) | 1 line

Made a change.
------------------------------------------------------------------------

Navn

svn merge — Apply the differences between two sources to a working copy path.

Synopsis

svn merge sourceURL1[@N] sourceURL2[@M] [WCPATH]
svn merge sourceWCPATH1@N sourceWCPATH2@M [WCPATH]
svn merge -r N:M SOURCE[@REV] [WCPATH]

Description

In the first and second forms, the source paths (URLs in the first form, working copy paths in the second) are specified at revisions N and M. These are the two sources to be compared. The revisions default to HEAD if omitted.

In the third form, SOURCE can be a URL or working copy item, in which case the corresponding URL is used. This URL, at revisions N and M, defines the two sources to be compared.

WCPATH is the working copy path that will receive the changes. If WCPATH is omitted, a default value of . is assumed, unless the sources have identical basenames that match a file within .: in which case, the differences will be applied to that file.

Unlike svn diff, the merge command takes the ancestry of a file into consideration when performing a merge operation. This is very important when you're merging changes from one branch into another and you've renamed a file on one branch but not the other.

Alternate Names

None

Changes

Working copy

Accesses Repository

Only if working with URLs

Switches

--revision (-r) REV
--non-recursive (-N)
--quiet (-q)
--force
--dry-run
--diff3-cmd CMD
--ignore-ancestry
--username USER
--password PASS
--no-auth-cache
--non-interactive
--config-dir DIR

Examples

Merge a branch back into the trunk (assuming that you have a working copy of the trunk, and that the branch was created in revision 250):

$ svn merge -r 250:HEAD http://svn.red-bean.com/repos/branches/my-branch
U  myproj/tiny.txt
U  myproj/thhgttg.txt
U  myproj/win.txt
U  myproj/flo.txt

If you branched at revision 23, and you want to merge changes on trunk into your branch, you could do this from inside the working copy of your branch:

$ svn merge -r 23:30 file:///tmp/repos/trunk/vendors
U  myproj/thhgttg.txt
…

To merge changes to a single file:

$ cd myproj
$ svn merge -r 30:31 thhgttg.txt 
U  thhgttg.txt

Navn

svn mkdir — Create a new directory under version control.

Synopsis

svn mkdir PATH...
svn mkdir URL...

Description

Create a directory with a name given by the final component of the PATH or URL. A directory specified by a working copy PATH is scheduled for addition in the working copy. A directory specified by a URL is created in the repository via an immediate commit. Multiple directory URLs are committed atomically. In both cases all the intermediate directories must already exist.

Alternate Names

None

Changes

Working copy, repository if operating on a URL

Accesses Repository

Only if operating on a URL

Switches

--message (-m) TEXT
--file (-F) FILE
--quiet (-q)
--username USER
--password PASS
--no-auth-cache
--non-interactive
--editor-cmd EDITOR
--encoding ENC
--force-log
--config-dir DIR

Examples

Create a directory in your working copy:

$ svn mkdir newdir
A         newdir

Create one in the repository (instant commit, so a log message is required):

$ svn mkdir -m "Making a new dir." http://svn.red-bean.com/repos/newdir

Committed revision 26.

Navn

svn move — Move a file or directory.

Synopsis

svn move SRC DST

Description

This command moves a file or directory in your working copy or in the repository.

[Tips]Tips

This command is equivalent to an svn copy followed by svn delete.

[Notat]Notat

Subversion does not support moving between working copies and URLs. In addition, you can only move files within a single repository—Subversion does not support cross-repository moving.

WC -> WC

Move and schedule a file or directory for addition (with history).

URL -> URL

Complete server-side rename.

Alternate Names

mv, rename, ren

Changes

Working copy, repository if operating on a URL

Accesses Repository

Only if operating on a URL

Switches

--message (-m) TEXT
--file (-F) FILE
--revision (-r) REV
--quiet (-q)
--force
--username USER
--password PASS
--no-auth-cache
--non-interactive
--editor-cmd EDITOR
--encoding ENC
--force-log
--config-dir DIR

Examples

Move a file in your working copy:

$ svn move foo.c bar.c
A         bar.c
D         foo.c

Move a file in the repository (an immediate commit, so it requires a commit message):

$ svn move -m "Move a file" http://svn.red-bean.com/repos/foo.c \
                            http://svn.red-bean.com/repos/bar.c

Committed revision 27.

Navn

svn propdel — Remove a property from an item.

Synopsis

svn propdel PROPNAME [PATH...]
svn propdel PROPNAME --revprop -r REV [URL]

Description

This removes properties from files, directories, or revisions. The first form removes versioned properties in your working copy, while the second removes unversioned remote properties on a repository revision.

Alternate Names

pdel, pd

Changes

Working copy, repository only if operating on a URL

Accesses Repository

Only if operating on a URL

Switches

--quiet (-q)
--recursive (-R)
--revision (-r) REV
--revprop
--username USER
--password PASS
--no-auth-cache
--non-interactive
--config-dir DIR

Examples

Delete a property from a file in your working copy

$ svn propdel svn:mime-type  some-script
property 'svn:mime-type' deleted from 'some-script'.

Delete a revision property:

$ svn propdel --revprop -r 26 release-date 
property 'release-date' deleted from repository revision '26'

Navn

svn propedit — Edit the property of one or more items under version control.

Synopsis

svn propedit PROPNAME PATH...
svn propedit PROPNAME --revprop -r REV [URL]

Description

Edit one or more properties using your favorite editor. The first form edits versioned properties in your working copy, while the second edits unversioned remote properties on a repository revision.

Alternate Names

pedit, pe

Changes

Working copy, repository only if operating on a URL

Accesses Repository

Only if operating on a URL

Switches

--revision (-r) REV
--revprop
--username USER
--password PASS
--no-auth-cache
--non-interactive
--encoding ENC
--editor-cmd EDITOR
--config-dir DIR

Examples

svn propedit makes it easy to modify properties that have multiple values:

$ svn propedit svn:keywords  foo.c 
    <svn will launch your favorite editor here, with a buffer open
    containing the current contents of the svn:keywords property.  You
    can add multiple values to a property easily here by entering one
    value per line.>
Set new value for property 'svn:keywords' on 'foo.c'

Navn

svn propget — Print the value of a property.

Synopsis

svn propget PROPNAME [TARGET[@REV]...]
svn propget PROPNAME --revprop -r REV [URL]

Description

Print the value of a property on files, directories, or revisions. The first form prints the versioned property of an item or items in your working copy, while the second prints unversioned remote property on a repository revision. See “Egenskaper” for more information on properties.

Alternate Names

pget, pg

Changes

Working copy, repository only if operating on a URL

Accesses Repository

Only if operating on a URL

Switches

--recursive (-R)
--revision (-r) REV
--revprop
--strict
--username USER
--password PASS
--no-auth-cache
--non-interactive
--config-dir DIR

Examples

Examine a property of a file in your working copy:

$ svn propget svn:keywords foo.c
Author
Date
Rev

The same goes for a revision property:

$ svn propget svn:log --revprop -r 20 
Began journal.

Navn

svn proplist — List all properties.

Synopsis

svn proplist [TARGET[@REV]...]
svn proplist --revprop -r REV [URL]

Description

List all properties on files, directories, or revisions. The first form lists versioned properties in your working copy, while the second lists unversioned remote properties on a repository revision.

Alternate Names

plist, pl

Changes

Working copy, repository only if operating on a URL

Accesses Repository

Only if operating on a URL

Switches

--verbose (-v)
--recursive (-R)
--revision (-r) REV
--quiet (-q)
--revprop
--username USER
--password PASS
--no-auth-cache
--non-interactive
--config-dir DIR

Examples

You can use proplist to see the properties on an item in your working copy:

$ svn proplist foo.c
Properties on 'foo.c':
  svn:mime-type
  svn:keywords
  owner

But with the --verbose flag, svn proplist is extremely handy as it also shows you the values for the properties:

$ svn proplist --verbose foo.c
Properties on 'foo.c':
  svn:mime-type : text/plain
  svn:keywords : Author Date Rev
  owner : sally

Navn

svn propset — Set PROPNAME to PROPVAL on files, directories, or revisions.

Synopsis

svn propset PROPNAME [PROPVAL | -F VALFILE] PATH...
svn propset PROPNAME --revprop -r REV [PROPVAL | -F VALFILE] [URL]

Description

Set PROPNAME to PROPVAL on files, directories, or revisions. The first example creates a versioned, local property change in the working copy, and the second creates an unversioned, remote property change on a repository revision.

[Tips]Tips

Subversion has a number of special properties that affect its behavior. See “Subversion properties” for more on these properties.

Alternate Names

pset, ps

Changes

Working copy, repository only if operating on a URL

Accesses Repository

Only if operating on a URL

Switches

--file (-F) FILE
--quiet (-q)
--revision (-r) REV
--targets FILENAME
--recursive (-R)
--revprop
--username USER
--password PASS
--no-auth-cache
--non-interactive
--encoding ENC
--force
--config-dir DIR

Examples

Set the mimetype on a file:

$ svn propset svn:mime-type image/jpeg foo.jpg 
property 'svn:mime-type' set on 'foo.jpg'

On a UNIX system, if you want a file to have the executable permission set:

$ svn propset svn:executable ON somescript
property 'svn:executable' set on 'somescript'

Perhaps you have an internal policy to set certain properties for the benefit of your coworkers:

$ svn propset owner sally foo.c
property 'owner' set on 'foo.c'

If you made a mistake in a log message for a particular revision and want to change it, use --revprop and set svn:log to the new log message:

$ svn propset --revprop -r 25 svn:log "Journaled about trip to New York."
property 'svn:log' set on repository revision '25'

Or, if you don't have a working copy, you can provide a URL.

$ svn propset --revprop -r 26 svn:log "Document nap." http://svn.red-bean.com/repos
property 'svn:log' set on repository revision '25'

Lastly, you can tell propset to take its input from a file. You could even use this to set the contents of a property to something binary:

$ svn propset owner-pic -F sally.jpg moo.c 
property 'owner-pic' set on 'moo.c'
[Notat]Notat

By default, you cannot modify revision properties in a Subversion repository. Your repository administrator must explicitly enable revision property modifications by creating a hook named pre-revprop-change. See “Påhakningsskript” for more information on hook scripts.


Navn

svn resolved — Remove conflicted state on working copy files or directories.

Synopsis

svn resolved PATH...

Description

Remove conflicted state on working copy files or directories. This routine does not semantically resolve conflict markers; it merely removes conflict-related artifact files and allows PATH to be committed again; that is, it tells Subversion that the conflicts have been resolved. See “Løse konflikter (Flette inn andres forandringer)” for an in-depth look at resolving conflicts.

Alternate Names

None

Changes

Working copy

Accesses Repository

No

Switches

--targets FILENAME
--recursive (-R)
--quiet (-q)
--config-dir DIR

Examples

If you get a conflict on an update, your working copy will sprout three new files:

$ svn update
C  foo.c
Updated to revision 31.
$ ls
foo.c
foo.c.mine
foo.c.r30
foo.c.r31

Once you've resolved the conflict and foo.c is ready to be committed, run svn resolved to let your working copy know you've taken care of everything.

[Advarsel]Advarsel

You can just remove the conflict files and commit, but svn resolved fixes up some bookkeeping data in the working copy administrative area in addition to removing the conflict files, so we recommend that you use this command.


Navn

svn revert — Undo all local edits.

Synopsis

svn revert PATH...

Description

Reverts any local changes to a file or directory and resolves any conflicted states. svn revert will not only revert the contents of an item in your working copy, but also any property changes. Finally, you can use it to undo any scheduling operations that you may have done (e.g. files scheduled for addition or deletion can be unscheduled).

Alternate Names

None

Changes

Working copy

Accesses Repository

No

Switches

--targets FILENAME
--recursive (-R)
--quiet (-q)
--config-dir DIR

Examples

Discard changes to a file:

$ svn revert foo.c
Reverted foo.c

If you want to revert a whole directory of files, use the --recursive flag:

$ svn revert --recursive .
Reverted newdir/afile
Reverted foo.c
Reverted bar.txt

Lastly, you can undo any scheduling operations:

$ svn add mistake.txt whoops
A         mistake.txt
A         whoops
A         whoops/oopsie.c

$ svn revert mistake.txt whoops
Reverted mistake.txt
Reverted whoops

$ svn status
?      mistake.txt
?      whoops
[Notat]Notat

If you provide no targets to svn revert, it will do nothing—to protect you from accidentally losing changes in your working copy, svn revert requires you to provide at least one target.


Navn

svn status — Print the status of working copy files and directories.

Synopsis

svn status [PATH...]

Description

Print the status of working copy files and directories. With no arguments, it prints only locally modified items (no repository access). With --show-updates, add working revision and server out-of-date information. With --verbose, print full revision information on every item.

The first six columns in the output are each one character wide, and each column gives you information about different aspects of each working copy item.

The first column indicates that an item was added, deleted, or otherwise changed.

' '

No modifications.

'A'

Item is scheduled for Addition.

'D'

Item is scheduled for Deletion.

'M'

Item has been modified.

'R'

Item has been replaced in your working copy. This means the file was scheduled for deletion, and then a new file with the same name was scheduled for addition in its place.

'C'

The contents (as opposed to the properties) of the item conflict with updates received from the repository.

'X'

Item is related to an externals definition.

'I'

Item is being ignored (e.g. with the svn:ignore property).

'?'

Item is not under version control.

'!'

Item is missing (e.g. you moved or deleted it without using svn). This also indicates that a directory is incomplete (a checkout or update was interrupted).

'~'

Item is versioned as one kind of object (file, directory, link), but has been replaced by different kind of object.

The second column tells the status of a file's or directory's properties.

' '

No modifications.

'M'

Properties for this item have been modified.

'C'

Properties for this item are in conflict with property updates received from the repository.

The third column is populated only if the working copy directory is locked. (See svn cleanup.)

' '

Item is not locked.

'L'

Item is locked.

The fourth column is populated only if the item is scheduled for addition-with-history.

' '

No history scheduled with commit.

'+'

History scheduled with commit.

The fifth column is populated only if the item is switched relative to its parent (see “Bytte om en arbeidskopi”).

' '

Item is a child of its parent directory.

'S'

Item is switched.

The sixth column is populated with lock information.

' '

When --show-updates is used, the file is not locked. If --show-updates is not used, this merely means that the file is not locked in this working copy.

K

File is locked in this working copy.

O

File is locked either by another user or in another working copy. This only appears when --show-updates is used.

T

File was locked in this working copy, but the lock has been stolenand is invalid. The file is currently locked in the repository. This only appears when --show-updates is used.

B

File was locked in this working copy, but the lock has been brokenand is invalid. The file is no longer locked This only appears when --show-updates is used.

The out-of-date information appears in the seventh column (only if you pass the --show-updates switch).

' '

The item in your working copy is up-to-date.

'*'

A newer revision of the item exists on the server.

The remaining fields are variable width and delimited by spaces. The working revision is the next field if the --show-updates or --verbose switches are passed.

If the --verbose switch is passed, the last committed revision and last committed author are displayed next.

The working copy path is always the final field, so it can include spaces.

Alternate Names

stat, st

Changes

Nothing

Accesses Repository

Only if using --show-updates

Switches

--show-updates (-u)
--verbose (-v)
--non-recursive (-N)
--quiet (-q)
--no-ignore
--username USER
--password PASS
--no-auth-cache
--non-interactive
--config-dir DIR
--ignore-externals

Examples

This is the easiest way to find out what changes you have made to your working copy:

$ svn status wc
 M     wc/bar.c
A  +   wc/qax.c

If you want to find out what files in your working copy are out-of-date, pass the --show-updates switch (this will not make any changes to your working copy). Here you can see that wc/foo.c has changed in the repository since we last updated our working copy:

$ svn status --show-updates wc
 M           965    wc/bar.c
       *     965    wc/foo.c
A  +         965    wc/qax.c
Status against revision:    981
[Notat]Notat

--show-updates only places an asterisk next to items that are out of date (that is, items that will be updated from the repository if you run svn update). --show-updates does not cause the status listing to reflect the repository's version of the item.

And finally, the most information you can get out of the status subcommand:

$ svn status --show-updates --verbose wc
 M           965       938 sally        wc/bar.c
       *     965       922 harry        wc/foo.c
A  +         965       687 harry        wc/qax.c
             965       687 harry        wc/zig.c
Head revision:   981

For many more examples of svn status, see svn status.


Navn

svn switch — Update working copy to a different URL.

Synopsis

svn switch URL [PATH]
switch --relocate FROM TO [PATH...]

Description

This subcommand updates your working copy to mirror a new URL—usually a URL which shares a common ancestor with your working copy, although not necessarily. This is the Subversion way to move a working copy to a new branch. See “Bytte om en arbeidskopi” for an in-depth look at switching.

Alternate Names

sw

Changes

Working copy

Accesses Repository

Yes

Switches

--revision (-r) REV
--non-recursive (-N)
--quiet (-q)
--diff3-cmd CMD
--relocate FROM TO
--username USER
--password PASS
--no-auth-cache
--non-interactive
--config-dir DIR

Examples

If you're currently inside the directory vendors which was branched to vendors-with-fix and you'd like to switch your working copy to that branch:

$ svn switch http://svn.red-bean.com/repos/branches/vendors-with-fix .
U  myproj/foo.txt
U  myproj/bar.txt
U  myproj/baz.c
U  myproj/qux.c
Updated to revision 31.

And to switch back, just provide the URL to the location in the repository from which you originally checked out your working copy:

$ svn switch http://svn.red-bean.com/repos/trunk/vendors .
U  myproj/foo.txt
U  myproj/bar.txt
U  myproj/baz.c
U  myproj/qux.c
Updated to revision 31.
[Tips]Tips

You can just switch part of your working copy to a branch if you don't want to switch your entire working copy.

Sometimes an administrator might change the base location of your repository—in other words, the contents of the repository doesn't change, but the main URL used to reach the root of the repository does. For example, the hostname may change, the URL scheme, or any part of the URL which leads to the repository itself. Rather than checkout a new working copy, you can have the svn switch command rewrite the beginnings of all the URLs in your working copy. Use the --relocate option to do the substitution. No file contents are changed, nor is the repository contacted. It's similar to running a Perl script over your working copy .svn/ directories which runs s/OldRoot/NewRoot/.

$ svn checkout file:///tmp/repos test
A  test/a
A  test/b
…

$ mv repos newlocation
$ cd test/

$ svn update
svn: Unable to open an ra_local session to URL
svn: Unable to open repository 'file:///tmp/repos'

$ svn switch --relocate file:///tmp/repos file:///tmp/newlocation .
$ svn update
At revision 3.
[Advarsel]Advarsel

Be careful when using the --relocate option. If you mistype the argument, you might end up creating nonsensical URLs within your working copy that render the whole workspace unusable and tricky to fix. It's also important to understand exactly when one should or shouldn't use --relocate. Here's the rule of thumb:

  • If the working copy needs to reflect a new directory within the repository, then use just svn switch.

  • If the working copy still reflects the same repository directory, but the location of the repository itself has changed, then use svn switch --relocate.


Navn

svn unlock — Unlock working copy paths or URLs.

Synopsis

svn unlock TARGET...

Description

Unlock each TARGET. If any TARGET is either locked by another user or no valid lock token exists in the working copy, print a warning and continue unlocking the rest of the TARGETs. Use --force to break a lock belonging to another user or working copy.

Alternate Names

None

Changes

Working Copy, Repository

Accesses Repository

Yes

Switches

--targets FILENAME
--username USER
--password PASS
--no-auth-cache
--non-interactive
--config-dir DIR
--force

Examples

Unlock two files in your working copy:


$ svn unlock tree.jpg house.jpg
'tree.jpg' unlocked.
'house.jpg' unlocked.

Unlock a file in your working copy that is currently locked by another user:

$ svn unlock tree.jpg
svn: 'tree.jpg' is not locked in this working copy
$ svn unlock --force tree.jpg
'tree.jpg' unlocked.

Unlock a file without a working copy:

$ svn unlock http://svn.red-bean.com/repos/test/tree.jpg
'tree.jpg unlocked.

For further details, see “Locking”.


Navn

svn update — Update your working copy.

Synopsis

svn update [PATH...]

Description

svn update brings changes from the repository into your working copy. If no revision given, it brings your working copy up-to-date with the HEAD revision. Otherwise, it synchronizes the working copy to the revision given by the --revision switch. As part of the synchronization, svn update also removes any stale locks (see svn cleanup) found in the working copy.

For each updated item a line will start with a character reporting the action taken. These characters have the following meaning:

A

Added

D

Deleted

U

Updated

C

Conflict

G

Merged

A character in the first column signifies an update to the actual file, while updates to the file's properties are shown in the second column.

Alternate Names

up

Changes

Working copy

Accesses Repository

Yes

Switches

--revision (-r) REV
--non-recursive (-N)
--quiet (-q)
--diff3-cmd CMD
--username USER
--password PASS
--no-auth-cache
--non-interactive
--config-dir DIR
--ignore-externals

Examples

Pick up repository changes that have happened since your last update:

$ svn update
A  newdir/toggle.c
A  newdir/disclose.c
A  newdir/launch.c
D  newdir/README
Updated to revision 32.

You can also update your working copy to an older revision (Subversion doesn't have the concept of sticky files like CVS does; see Tillegg B, Subversion for CVS-brukere):

$ svn update -r30
A  newdir/README
D  newdir/toggle.c
D  newdir/disclose.c
D  newdir/launch.c
U  foo.c
Updated to revision 30.
[Tips]Tips

If you want to examine an older revision of a single file, you may want to use svn cat.

svnadmin

svnadmin is the administrative tool for monitoring and repairing your Subversion repository. For detailed information, see “svnadmin”.

Since svnadmin works via direct repository access (and thus can only be used on the machine that holds the repository), it refers to the repository with a path, not a URL.

svnadmin Switches

--bdb-log-keep

(Berkeley DB specific) Disable automatic log removal of database log files.

--bdb-txn-nosync

(Berkeley DB specific) Disables fsync when committing database transactions.

--bypass-hooks

Bypass the repository hook system.

--clean-logs

Removes unused Berkeley DB logs.

--force-uuid

By default, when loading data into repository that already contains revisions, svnadmin will ignore the UUID from the dump stream. This switch will cause the repository's UUID to be set to the UUID from the stream.

--ignore-uuid

By default, when loading an empty repository, svnadmin will use the UUID from the dump stream. This switch will cause that UUID to be ignored.

--incremental

Dump a revision only as a diff against the previous revision, instead of the usual fulltext.

--parent-dir DIR

When loading a dump file, root paths at DIR instead of /.

--revision (-r) ARG

Specify a particular revision to operate on.

--quiet

Do not show normal progress—show only errors.

--use-post-commit-hook

When loading a dump file, run the repository's post-commit hook after finalizing each newly loaded revision.

--use-pre-commit-hook

When loading a dump file, run the repository's pre-commit hook before finalizing each newly loaded revision. If the hook fails, abort the commit and terminate the load process.

svnadmin Subcommands

Navn

svnadmin create — Create a new, empty repository.

Synopsis

svnadmin create REPOS_PATH

Description

Create a new, empty repository at the path provided. If the provided directory does not exist, it will be created for you.[50] As of Subversion 1.2, svnadmin creates new repositories with the fsfs filesystem backend by default.

Switches

--bdb-txn-nosync
--bdb-log-keep
--config-dir DIR
--fs-type TYPE

Examples

Creating a new repository is just this easy:

$ svnadmin create /usr/local/svn/repos

In Subversion 1.0, a Berkeley DB repository is always created. In Subversion 1.1, a Berkeley DB repository is the default repository type, but an FSFS repository can be created using the --fs-type option:

$ svnadmin create /usr/local/svn/repos --fs-type fsfs



[50] Remember, svnadmin works only with local paths, not URLs.


Navn

svnadmin deltify — Deltify changed paths in a revision range.

Synopsis

svnadmin deltify [-r LOWER[:UPPER]] REPOS_PATH

Description

svnadmin deltify only exists in current versions of Subversion due to historical reasons. This command is deprecated and no longer needed.

It dates from a time when Subversion offered administrators greater control over compression strategies in the repository. This turned out to be a lot of complexity for very little gain, and this feature was deprecated.

Switches

--revision (-r) REV
--quiet (-q)

Navn

svnadmin dump — Dump the contents of filesystem to stdout.

Synopsis

svnadmin dump REPOS_PATH [-r LOWER[:UPPER]] [--incremental]

Description

Dump the contents of filesystem to stdout in a dumpfile portable format, sending feedback to stderr. Dump revisions LOWER rev through UPPER rev. If no revisions are given, dump all revision trees. If only LOWER is given, dump that one revision tree. See “Flytte et depot” for a practical use.

By default, the Subversion dumpfile stream contains a single revision (the first revision in the requested revision range) in which every file and directory in the repository in that revision is presented as if that whole tree was added at once, followed by other revisions (the remainder of the revisions in the requested range) which contain only the files and directories which were modified in those revisions. For a modified file, the complete fulltext representation of its contents, as well as all of its properties, are presented in the dumpfile; for a directory, all of its properties are presented.

There are a pair of useful options which modify the dumpfile generator's behavior. The first is the --incremental option, which simply causes that first revision in the dumpfile stream to contain only the files and directories modified in that revision, instead of being presented as the addition of a new tree, and in exactly the same way that every other revision in the dumpfile is presented. This is useful for generating a dumpfile that is to be loaded into another repository which already has the files and directories that exist in the original repository.

The second useful option is --deltas. This switch causes svnadmin dump to, instead of emitting fulltext representations of file contents and property lists, emit only deltas of those items against their previous versions. This reduces (in some cases, drastically) the size of the dumpfile that svnadmin dump creates. There are, however, disadvantages to using this option—deltified dumpfiles are more CPU intensive to create, cannot be operated on by svndumpfilter, and tend not to compress as well as their non-deltified counterparts when using third-party tools like gzip and bzip2.

Switches

--revision (-r) REV
--incremental
--quiet (-q)
--deltas

Examples

Dump your whole repository:

$ svnadmin dump /usr/local/svn/repos
SVN-fs-dump-format-version: 1
Revision-number: 0
* Dumped revision 0.
Prop-content-length: 56
Content-length: 56
…

Incrementally dump a single transaction from your repository:

$ svnadmin dump /usr/local/svn/repos -r 21 --incremental 
* Dumped revision 21.
SVN-fs-dump-format-version: 1
Revision-number: 21
Prop-content-length: 101
Content-length: 101
…

Navn

svnadmin help — Help!

Synopsis

svnadmin help [SUBCOMMAND...]

Description

This subcommand is useful when you're trapped on a desert island with neither a net connection nor a copy of this book.

Alternate Names

?, h


Navn

svnadmin hotcopy — Make a hot copy of a repository.

Synopsis

svnadmin hotcopy REPOS_PATH NEW_REPOS_PATH

Description

This subcommand makes a full hot backup of your repository, including all hooks, configuration files, and, of course, database files. If you pass the --clean-logs switch, svnadmin will perform a hotcopy of your repository, and then remove unused Berkeley DB logs from the original repository. You can run this command at any time and make a safe copy of the repository, regardless of whether other processes are using the repository.

Switches

--clean-logs

Navn

svnadmin list-dblogs — Ask Berkeley DB which log files exist for a given Subversion repository (applies only to repositories using the bdb backend).

Synopsis

svnadmin list-dblogs REPOS_PATH

Description

Berkeley DB creates logs of all changes to the repository, which allow it to recover in the face of catastrophe. Unless you enable DB_LOG_AUTOREMOVE, the log files accumulate, although most are no longer used and can be deleted to reclaim disk space. See “Bruken av diskplass” for more information.


Navn

svnadmin list-unused-dblogs — Ask Berkeley DB which log files can be safely deleted (applies only to repositories using the bdb backend).

Synopsis

svnadmin list-unused-dblogs REPOS_PATH

Description

Berkeley DB creates logs of all changes to the repository, which allow it to recover in the face of catastrophe. Unless you enable DB_LOG_AUTOREMOVE, the log files accumulate, although most are no longer used and can be deleted to reclaim disk space. See “Bruken av diskplass” for more information.

Examples

Remove all unused log files from a repository:

$ svnadmin list-unused-dblogs /path/to/repos
/path/to/repos/log.0000000031
/path/to/repos/log.0000000032
/path/to/repos/log.0000000033

$ svnadmin list-unused-dblogs /path/to/repos | xargs rm
## disk space reclaimed!

Navn

svnadmin load — Read a dumpfile-formatted stream from stdin.

Synopsis

svnadmin load REPOS_PATH

Description

Read a dumpfile-formatted stream from stdin, committing new revisions into the repository's filesystem. Send progress feedback to stdout.

Switches

--quiet (-q)
--ignore-uuid
--force-uuid
--use-pre-commit-hook
--use-post-commit-hook
--parent-dir

Example

This shows the beginning of loading a repository from a backup file (made, of course, with svnadmin dump):

$ svnadmin load /usr/local/svn/restored < repos-backup
<<< Started new txn, based on original revision 1
     * adding path : test ... done.
     * adding path : test/a ... done.
…

Or if you want to load into a subdirectory:

$ svnadmin load --parent-dir new/subdir/for/project /usr/local/svn/restored < repos-backup
<<< Started new txn, based on original revision 1
     * adding path : test ... done.
     * adding path : test/a ... done.
…

Navn

svnadmin lslocks — Print descriptions of all locks.

Synopsis

svnadmin lslocks REPOS_PATH

Description

Print descriptions of all locks in a repository.

Switches

None

Example

This lists the one locked file in the repository at /svn/repos

$ svnadmin lslocks /svn/repos
Path: /tree.jpg
UUID Token: opaquelocktoken:ab00ddf0-6afb-0310-9cd0-dda813329753
Owner: harry
Created: 2005-07-08 17:27:36 -0500 (Fri, 08 Jul 2005)
Expires: 
Comment (1 line):
Rework the uppermost branches on the bald cypress in the foreground.

Navn

svnadmin lstxns — Print the names of all uncommitted transactions.

Synopsis

svnadmin lstxns REPOS_PATH

Description

Print the names of all uncommitted transactions. See “Depotvedlikehold” for information on how uncommitted transactions are created and what you should do with them.

Examples

List all outstanding transactions in a repository.

$ svnadmin lstxns /usr/local/svn/repos/ 
1w
1x

Navn

svnadmin recover — Bring a repository database back into a consistent state (applies only to repositories using the bdb backend). In addition, if repos/conf/passwd does not exist, it will create a default password file .

Synopsis

svnadmin recover REPOS_PATH

Description

Run this command if you get an error indicating that your repository needs to be recovered.

Switches

--wait

Examples

Recover a hung repository:

$ svnadmin recover /usr/local/svn/repos/ 
Repository lock acquired.
Please wait; recovering the repository may take some time...

Recovery completed.
The latest repos revision is 34.

Recovering the database requires an exclusive lock on the repository. (This is a database lock; see Three meanings of lock.) If another process is accessing the repository, then svnadmin recover will error:

$ svnadmin recover /usr/local/svn/repos
svn: Failed to get exclusive repository access; perhaps another process
such as httpd, svnserve or svn has it open?

$

The --wait option, however, will cause svnadmin recover to wait indefinitely for other processes to disconnect:

$ svnadmin recover /usr/local/svn/repos --wait
Waiting on repository lock; perhaps another process has it open?

### time goes by…

Repository lock acquired.
Please wait; recovering the repository may take some time...

Recovery completed.
The latest repos revision is 34.

Navn

svnadmin rmlocks — Unconditionally remove one or more locks from a repository.

Synopsis

svnadmin rmlocks REPOS_PATH LOCKED_PATH...

Description

Remove lock from each LOCKED_PATH.

Switches

None

Example

This deletes the locks on tree.jpg and house.jpg in the repository at /svn/repos

$ svnadmin rmlocks /svn/repos tree.jpg house.jpg
Removed lock on '/tree.jpg.
Removed lock on '/house.jpg.

Navn

svnadmin rmtxns — Delete transactions from a repository.

Synopsis

svnadmin rmtxns REPOS_PATH TXN_NAME...

Description

Delete outstanding transactions from a repository. This is covered in detail in “Depotvedlikehold”.

Switches

--quiet (-q)

Examples

Remove named transactions:

$ svnadmin rmtxns /usr/local/svn/repos/ 1w 1x

Fortunately, the output of lstxns works great as the input for rmtxns:

$ svnadmin rmtxns /usr/local/svn/repos/  `svnadmin lstxns /usr/local/svn/repos/`

Which will remove all uncommitted transactions from your repository.


Navn

svnadmin setlog — Set the log-message on a revision.

Synopsis

svnadmin setlog REPOS_PATH -r REVISION FILE

Description

Set the log-message on revision REVISION to the contents of FILE.

This is similar to using svn propset --revprop to set the svn:log property on a revision, except that you can also use the option --bypass-hooks to avoid running any pre- or post-commit hooks, which is useful if the modification of revision properties has not been enabled in the pre-revprop-change hook.

[Advarsel]Advarsel

Revision properties are not under version control, so this command will permanently overwrite the previous log message.

Switches

--revision (-r) REV
--bypass-hooks

Examples

Set the log message for revision 19 to the contents of the file msg:

$ svnadmin setlog /usr/local/svn/repos/ -r 19 msg

Navn

svnadmin verify — Verify the data stored in the repository.

Synopsis

svnadmin verify REPOS_PATH

Description

Run this command if you wish to verify the integrity of your repository. This basically iterates through all revisions in the repository by internally dumping all revisions and discarding the output.

Examples

Verify a hung repository:

$ svnadmin verify /usr/local/svn/repos/ 
* Verified revision 1729.

svnlook

svnlook is a command-line utility for examining different aspects of a Subversion repository. It does not make any changes to the repository—it's just used for peeking. svnlook is typically used by the repository hooks, but a repository administrator might find it useful for diagnostic purposes.

Since svnlook works via direct repository access (and thus can only be used on the machine that holds the repository), it refers to the repository with a path, not a URL.

If no revision or transaction is specified, svnlook defaults to the youngest (most recent) revision of the repository.

svnlook Switches

Switches in svnlook are global, just like in svn and svnadmin; however, most switches only apply to one subcommand since the functionality of svnlook is (intentionally) limited in scope.

--no-diff-deleted

Prevents svnlook from printing differences for deleted files. The default behavior when a file is deleted in a transaction/revision is to print the same differences that you would see if you had left the file but removed all the content.

--revision (-r)

Specify a particular revision number that you wish to examine.

--revprop

Operates on a revision property instead of a Subversion property specific to a file or directory. This switch requires that you also pass a revision with the --revision (-r) switch. See “Uversjonerte egenskaper” for more details on unversioned properties.

--transaction (-t)

Specify a particular transaction ID that you wish to examine.

--show-ids

Show the filesystem node revision IDs for each path in the filesystem tree.

svnlook

Navn

svnlook author — Print the author.

Synopsis

svnlook author REPOS_PATH

Description

Print the author of a revision or transaction in the repository.

Switches

--revision (-r) REV
--transaction (-t)

Examples

svnlook author is handy, but not very exciting:

$ svnlook author -r 40 /usr/local/svn/repos 
sally

Navn

svnlook cat — Print the contents of a file.

Synopsis

svnlook cat REPOS_PATH PATH_IN_REPOS

Description

Print the contents of a file.

Switches

--revision (-r) REV
--transaction (-t)

Examples

This shows the contents of a file in transaction ax8, located at /trunk/README:

$ svnlook cat -t ax8 /usr/local/svn/repos /trunk/README

               Subversion, a version control system.
               =====================================

$LastChangedDate: 2003-07-17 10:45:25 -0500 (Thu, 17 Jul 2003) $

Contents:

     I. A FEW POINTERS
    II. DOCUMENTATION
   III. PARTICIPATING IN THE SUBVERSION COMMUNITY
…

Navn

svnlook changed — Print the paths that were changed.

Synopsis

svnlook changed REPOS_PATH

Description

Print the paths that were changed in a particular revision or transaction, as well as svn update-style status letters in the first two columns:

'A '

Item added to repository.

'D '

Item deleted from repository.

'U '

File contents changed.

'_U'

Properties of item changed.

'UU'

File contents and properties changed.

Files and directories can be distinguished, as directory paths are displayed with a trailing '/' character.

Switches

--revision (-r) REV
--transaction (-t)

Examples

This shows a list of all the changed files in revision 39 of a test repository:

$ svnlook changed -r 39 /usr/local/svn/repos
A   trunk/vendors/deli/
A   trunk/vendors/deli/chips.txt
A   trunk/vendors/deli/sandwich.txt
A   trunk/vendors/deli/pickle.txt
U   trunk/vendors/baker/bagel.txt
_U  trunk/vendors/baker/croissant.txt
UU  trunk/vendors/baker/pretzel.txt
D   trunk/vendors/baker/baguette.txt

Navn

svnlook date — Print the datestamp.

Synopsis

svnlook date REPOS_PATH

Description

Print the datestamp of a revision or transaction in a repository.

Switches

--revision (-r) REV
--transaction (-t)

Examples

This shows the date of revision 40 of a test repository:

            
$ svnlook date -r 40 /tmp/repos/
2003-02-22 17:44:49 -0600 (Sat, 22 Feb 2003)

Navn

svnlook diff — Print differences of changed files and properties.

Synopsis

svnlook diff REPOS_PATH

Description

Print GNU-style differences of changed files and properties in a repository.

Switches

--revision (-r) REV
--transaction (-t)
--no-diff-added
--no-diff-deleted

Examples

This shows a newly added (empty) file, a deleted file, and a copied file:

$ svnlook diff -r 40 /usr/local/svn/repos/
Copied: egg.txt (from rev 39, trunk/vendors/deli/pickle.txt)

Added: trunk/vendors/deli/soda.txt
==============================================================================

Modified: trunk/vendors/deli/sandwich.txt
==============================================================================
--- trunk/vendors/deli/sandwich.txt	(original)
+++ trunk/vendors/deli/sandwich.txt	2003-02-22 17:45:04.000000000 -0600
@@ -0,0 +1 @@
+Don't forget the mayo!

Modified: trunk/vendors/deli/logo.jpg
==============================================================================
(Binary files differ)

Deleted: trunk/vendors/deli/chips.txt
==============================================================================

Deleted: trunk/vendors/deli/pickle.txt
==============================================================================

If a file has a non-textual svn:mime-type property, then the differences are not explicitly shown.


Navn

svnlook dirs-changed — Print the directories that were themselves changed.

Synopsis

svnlook dirs-changed REPOS_PATH

Description

Print the directories that were themselves changed (property edits) or whose file children were changed.

Switches

--revision (-r) REV
--transaction (-t)

Examples

This shows the directories that changed in revision 40 in our sample repository:

$ svnlook dirs-changed -r 40 /usr/local/svn/repos
trunk/vendors/deli/

Navn

svnlook help — Help!

Synopsis

Also svnlook -h and svnlook -?.

Description

Displays the help message for svnlook. This command, like its brother svn help, is also your friend, even though you never call it anymore and forgot to invite it to your last party.

Alternate Names

?, h


Navn

svnlook history — Print information about the history of a path in the repository (or the root directory if no path is supplied).

Synopsis

svnlook history REPOS_PATH [PATH_IN_REPOS]

Description

Print information about the history of a path in the repository (or the root directory if no path is supplied).

Switches

--revision (-r) REV
--show-ids

Examples

This shows the history output for the path /tags/1.0 as of revision 20 in our sample repository.

$ svnlook history -r 20 /usr/local/svn/repos /tags/1.0 --show-ids
REVISION   PATH <ID>
--------   ---------
      19   /tags/1.0 <1.2.12>
      17   /branches/1.0-rc2 <1.1.10>
      16   /branches/1.0-rc2 <1.1.x>
      14   /trunk <1.0.q>
      13   /trunk <1.0.o>
      11   /trunk <1.0.k>
       9   /trunk <1.0.g>
       8   /trunk <1.0.e>
       7   /trunk <1.0.b>
       6   /trunk <1.0.9>
       5   /trunk <1.0.7>
       4   /trunk <1.0.6>
       2   /trunk <1.0.3>
       1   /trunk <1.0.2>

Navn

svnlook info — Print the author, datestamp, log message size, and log message.

Synopsis

svnlook info REPOS_PATH

Description

Print the author, datestamp, log message size, and log message.

Switches

--revision (-r) REV
--transaction (-t)

Examples

This shows the info output for revision 40 in our sample repository.

$ svnlook info -r 40 /usr/local/svn/repos
sally
2003-02-22 17:44:49 -0600 (Sat, 22 Feb 2003)
15
Rearrange lunch.

Navn

svnlook lock — If a lock exists on a path in the repository, describe it.

Synopsis

svnlook lock REPOS_PATH PATH_IN_REPOS

Description

Print all information available for the lock at PATH_IN_REPOS. If PATH_IN_REPOS is not locked, print nothing.

Switches

None

Examples

This describes the lock on the file tree.jpg.

$ svnlook lock /svn/repos tree.jpg
UUID Token: opaquelocktoken:ab00ddf0-6afb-0310-9cd0-dda813329753
Owner: harry
Created: 2005-07-08 17:27:36 -0500 (Fri, 08 Jul 2005)
Expires: 
Comment (1 line):
Rework the uppermost branches on the bald cypress in the foreground.

Navn

svnlook log — Print the log message.

Synopsis

svnlook log REPOS_PATH

Description

Print the log message.

Switches

--revision (-r) REV
--transaction (-t)

Examples

This shows the log output for revision 40 in our sample repository:

$ svnlook log /tmp/repos/
Rearrange lunch.

Navn

svnlook propget — Print the raw value of a property on a path in the repository.

Synopsis

svnlook propget REPOS_PATH PROPNAME [PATH_IN_REPOS]

Description

List the value of a property on a path in the repository.

Alternate Names

pg, pget

Switches

--revision (-r) REV
--transaction (-t)
--revprop

Examples

This shows the value of the seasonings property on the file /trunk/sandwich in the HEAD revision:

$ svnlook pg /usr/local/svn/repos seasonings /trunk/sandwich
mustard

Navn

svnlook proplist — Print the names and values of versioned file and directory properties.

Synopsis

svnlook proplist REPOS_PATH [PATH_IN_REPOS]

Description

List the properties of a path in the repository. With --verbose, show the property values too.

Alternate Names

pl, plist

Switches

--revision (-r) REV
--transaction (-t)
--verbose (-v)
--revprop

Examples

This shows the names of properties set on the file /trunk/README in the HEAD revision:

$ svnlook proplist /usr/local/svn/repos /trunk/README
  original-author
  svn:mime-type

This is the same command as in the previous example, but this time showing the property values as well:

$ svnlook --verbose proplist /usr/local/svn/repos /trunk/README
  original-author : fitz
  svn:mime-type : text/plain

Navn

svnlook tree — Print the tree.

Synopsis

svnlook tree REPOS_PATH [PATH_IN_REPOS]

Description

Print the tree, starting at PATH_IN_REPOS (if supplied, at the root of the tree otherwise), optionally showing node revision IDs.

Switches

--revision (-r) REV
--transaction (-t)
--show-ids

Examples

This shows the tree output (with node-IDs) for revision 40 in our sample repository:

$ svnlook tree -r 40 /usr/local/svn/repos --show-ids
/ <0.0.2j>
 trunk/ <p.0.2j>
  vendors/ <q.0.2j>
   deli/ <1g.0.2j>
    egg.txt <1i.e.2j>
    soda.txt <1k.0.2j>
    sandwich.txt <1j.0.2j>

Navn

svnlook uuid — Print the repository's UUID.

Synopsis

svnlook uuid REPOS_PATH

Description

Print the UUID for the repository. the UUID is the repository's universal unique identifier. The Subversion client uses this identifier to differentiate between one repository and another.

Examples

          
$ svnlook uuid /usr/local/svn/repos
e7fe1b91-8cd5-0310-98dd-2f12e793c5e8

Navn

svnlook youngest — Print the youngest revision number.

Synopsis

svnlook youngest REPOS_PATH

Description

Print the youngest revision number of a repository.

Examples

This shows the youngest revision of our sample repository:

          
$ svnlook youngest /tmp/repos/ 
42

svnserve

svnserve allows access to Subversion repositories using the svn network protocol. You can run svnserve either as a standalone server process, or you can have another process, such as inetd, xinetd or sshd, launch it for you.

Once the client has selected a repository by transmitting its URL, svnserve reads a file named conf/svnserve.conf in the repository directory to determine repository-specific settings such as what authentication database to use and what authorization policies to apply. See “svnserve, en tilpasset server” for details of the svnserve.conf file.

svnserve Switches

Unlike the previous commands we've described. svnserve has no subcommands—svnserve is controlled exclusively by switches.

--daemon (-d)

Causes svnserve to run in daemon mode. svnserve backgrounds itself and accepts and serves TCP/IP connections on the svn port (3690, by default).

--listen-port=PORT

Causes svnserve to listen on PORT when run in daemon mode.

--listen-host=HOST

Causes svnserve to listen on the interface specified by HOST, which may be either a hostname or an IP address.

--foreground

When used together with -d, this switch causes svnserve to stay in the foreground. This switch is mainly useful for debugging.

--inetd (-i)

Causes svnserve to use the stdin/stdout file descriptors, as is appropriate for a daemon running out of inetd.

--help (-h)

Displays a usage summary and exits.

--version

Displays version information, a list of repository back-end modules available, and exits.

--root=ROOT (-r=ROOT)

Sets the virtual root for repositories served by svnserve. The pathname in URLs provided by the client will be interpreted relative to this root, and will not be allowed to escape this root.

--tunnel (-t)

Causes svnserve to run in tunnel mode, which is just like the inetd mode of operation (serve one connection over stdin/stdout) except that the connection is considered to be pre-authenticated with the username of the current uid. This flag is selected by the client when running over a tunnel agent such as ssh.

--tunnel-user NAME

Used in conjunction with --tunnel switch; tells svnserve to assume that NAME is the authenticated user, rather than the UID of the svnserve process. Useful for users wishing to share a single system account over SSH, but maintaining separate commit identities.

--threads (-T)

When running in daemon mode, causes svnserve to spawn a thread instead of a process for each connection. The svnserve process still backgrounds itself at startup time.

--listen-once (-X)

Causes svnserve to accept one connection on the svn port, serve it, and exit. This option is mainly useful for debugging.

svnversion

Navn

svnversion — Summarize the local revision(s) of a working copy.

Synopsis

svnversion [OPTIONS] [WC_PATH [TRAIL_URL]]

Description

svnversion is a program for summarizing the revision mixture of a working copy. The resultant revision number, or revision range, is written to standard output.

TRAIL_URL, if present, is the trailing portion of the URL used to determine if WC_PATH itself is switched (detection of switches within WC_PATH does not rely on TRAIL_URL).

When WC_PATH is not defined the current directory will be used as the working copy path. TRAIL_URL cannot be defined if WC_PATH is not explicitly given.

Switches

Like svnserve, svnversion has no subcommands, it only has switches.

--no-newline (-n)

Omit the usual trailing newline from the output.

--committed (-c)

Use the last-changed revisions rather than the current (i.e., highest locally available) revisions.

--help (-h)

Print a help summary.

--version

Print the version of svnversion and exit with no error.

Examples

If the working copy is all at the same revision (for example, immediately after an update), then that revision is printed out:

$ svnversion
4168

You can add TRAIL_URL to show that the working copy is not switched from what you expect. Note that the WC_PATH was required in this command:

$ svnversion . /repos/svn/trunk
4168

For a mixed-revision working copy, the range of revisions present is printed:

$ svnversion
4123:4168

If the working copy contains modifications, a trailing "M" is added:

$ svnversion
4168M

If the working copy is switched, a trailing "S" is added:

$ svnversion
4168S

Thus, here is a mixed-revision, switched working copy containing some local modifications:

$ svnversion
4212:4168MS

If invoked on a directory that is not a working copy, svnversion assumes it is an exported working copy and prints "exported":

$ svnversion
exported

mod_dav_svn

Navn

mod_dav_svn Configuration Directives — Apache configuration directives for serving Subversion repositories through Apache HTTP Server.

Description

This section briefly describes each of the Subversion Apache configuration directives. For an in-depth description of configuring Apache with Subversion, see “HTTP-serveren Apache (httpd)”.)

Directives

DAV svn

This directive must be included in any Directory or Location block for a Subversion repository. It tells httpd to use the Subversion backend for mod_dav to handle all requests.

SVNAutoversioning On

This directive allows write requests from WebDAV clients to result in automatic commits. A generic log message is auto-generated and attached to each revision. If you enable Autoversioning, you'll likely want to set ModMimeUsePathInfo On so that mod_mime can set svn:mime-type to the correct mime-type automatically (as best as mod_mime is able to, of course). For more information, see Tillegg C, WebDAV and Autoversioning

SVNPath

This directive specifies the location in the filesystem for a Subversion repository's files. In a configuration block for a Subversion repository, either this directive or SVNParentPath must be present, but not both.

SVNSpecialURI

Specifies the URI component (namespace) for special Subversion resources. The default is !svn, and most administrators will never use this directive. Only set this if there is a pressing need to have a file named !svn in your repository. If you change this on a server already in use, it will break all of the outstanding working copies and your users will hunt you down with pitchforks and flaming torches.

SVNReposName

Specifies the name of a Subversion repository for use in HTTP GET requests. This value will be prepended to the title of all directory listings (which are served when you navigate to a Subversion repository with a web browser). This directive is optional.

SVNIndexXSLT

Specifies the URI of an XSL transformation for directory indexes. This directive is optional.

SVNParentPath

Specifies the location in the filesystem of a parent directory whose child directories are Subversion repositories. In a configuration block for a Subversion repository, either this directive or SVNPath must be present, but not both.

SVNPathAuthz

Control path-based authorization by enabling or disabling subrequests. See “Slå av stibaserte kontroller” for details.

Subversion properties

Navn

Subversion-defined properties — properties defined by Subversion to control behavior.

Description

Subversion allows users to invent arbitrarily-named versioned properties on files and directories, as well as unversioned properties on revisions. The only restriction is on properties prefixed with svn:. Properties in that namespace are reserved for Subversion's own use. While these properties may be set by users to control Subversion's behavior, users may not invent new svn: properties.

Versioned Properties

svn:executable

If present on a file, the client will make the file executable in Unix-hosted working copies. See “File Executability”.

svn:mime-type

If present on a file, the value indicates the file's mime-type. This allows the client to decide whether line-based contextual merging is safe to perform during updates, and can also affect how the file behaves when fetched via web browser. See “File Content Type”.

svn:ignore

If present on a directory, the value is a list of unversioned file patterns to be ignored by svn status and other subcommands. See “Ignoring Unversioned Items”

svn:keywords

If present on a file, the value tells the client how to expand particular keywords within the file. See “Keyword Substitution”.

svn:eol-style

If present on a file, the value tells the client how to manipulate the file's line-endings in the working copy. See “End-of-Line Character Sequences”.

svn:externals

If present on a directory, the value is a multi-line list of other paths and URLs the client should check out. See “Externals Definitions”.

svn:special

If present on a file, indicates that the file is not an ordinary file, but a symbolic link or other special object.

svn:needs-lock

If present on a file, tells the client to make the file read-only in the working copy, as a reminder that the file should be locked before editing begins. See “Lock Communication”.

Unversioned Properties

svn:author

If present, contains the authenticated username of the person who created the revision. (If not present, then the revision was committed anonymously.)

svn:date

Contains the UTC time the revision was created, in ISO format. The value comes from the server machine's clock.

svn:log

Contains the log message describing the revision.

svn:autoversioned

If present, the revision was created via the autoversioning feature. See “Autoversioning”.




[49] Yes, yes, you don't need a subcommand to use the --version switch, but we'll get to that in just a minute.

[50] Remember, svnadmin works only with local paths, not URLs.

Tillegg A. Hurtiginnføring i Subversion

Noen personer har problemer med å absorbere en ny teknologi ved å lese dokumentasjon lagt ut etter et ovenfra og ned-prinsipp som i denne boka. Dette tillegget er en veldig kort introduksjon til Subversion, og er ment å gi personer som lærer nedenfra og opp en sjanse. Hvis du foretrekker å lære gjennom eksperimentering, vil den følgende demonstrasjonen få deg i gang. Under gjennomgangen vil vi gi deg lenker til de relevante kapitlene i denne boka.

Hvis du er ny innen hele konseptet med versjonskontroll eller til kopier-rediger-flett-modellen brukt av både CVS og Subversion, bør du lese Kapittel 1, Grunnleggende konsepter før du går videre.

Installering av Subversion

Subversion er bygget på et portabilitetslag kalt APR – Apache Portable Runtime. APR-biblioteket inneholder alle grensesnitt som Subversion trenger for å fungere på forskjellige operativsystemer: Diskaksess, nettverkstilgang, styring av hukommelsen og så videre. Selv om Subversion er i stand til å bruke Apache som nettverksserver, fører ikke Subversions APR-avhengighet til at Apache er en nødvendig komponent. APR er et selvstendig bibliotek som kan brukes av mange programmer. Det det derimot betyr, er at Subversion skal kunne kjøre på alle operativsystemer som Apache httpd-serveren kjører på: Windows, Linux, alle varianter av BSD, Mac OS X, Netware og andre.

Den letteste måten å få tak i Subversion er å hente en binær pakke bygget for ditt operativsystem. Subversions hjemmeside (http://subversion.tigris.org) har ofte disse pakkene tilgjengelig for nedlasting, lagt ut av frivillige. Denne plassen inneholder vanligvis grafiske installasjonspakker for brukere av operativsystemer fra Microsoft. Hvis du kjører et Unix-lignende operativsystem, kan du bruke systemets innebygde distribusjonssystem (RPM-filer, DEB-filer, ports-treet, osv.) for å hente Subversion.

Du kan også bygge Subversion direkte fra kildekode. Siste versjon av programmet kan hentes fra Subversions hjemmeside. Etter at du har pakket det ut, følg instruksjonene i fila INSTALL for å kompilere den. Merk at en offentliggjort kildekodepakke inneholder alt du trenger for å bygge en kommandolinjeklient i stand til å kommunisere med et fjerntliggende depot (mer spesifikt, bibliotekene apr, apr-util og neon). Men valgfrie deler av Subversion har mange andre avhengigheter, som Berkeley DB og muligens Apache httpd. Hvis du vil foreta en komplett kompilering, vær sikker på at du har alle pakkene dokumentert i INSTALL-fila.

Hvis du er av den typen som liker å bruke rykende fersk programvare, kan du også hente kildekoden for Subversion fra Subversion-depotet hvor den er lagret. For å gjøre dette, trenger du en Subversion-klient. Med den kan du hente ut en arbeidskopi av Subversion-depotet fra http://svn.collab.net/repos/svn/trunk/:[51]

$ svn checkout http://svn.collab.net/repos/svn/trunk subversion
A    subversion/HACKING
A    subversion/INSTALL
A    subversion/README
A    subversion/autogen.sh
A    subversion/build.conf
…

Kommandoen ovenfor vil hente ut den rykende ferske og nyeste versjonen av kildekoden for Subversion inn i en underkatalog kalt subversion. Du kan selvfølgelig forandre det siste parameteret til det du syns passer. Men, uansett hva du kaller den nye arbeidskopien, etter at denne operasjonen er fullført, vil du ha kildekoden til Subversion. Du vil også trenge å hente en del programbiblioteker (apr, apr-util og så videre) – se INSTALL-fila i toppkatalogen i arbeidskopien for detaljene.

Høyhastighetsopplæring

Vennligst rett opp seteryggen, fest setebeltet og rett opp bordene. Flight attendants, prepare for take-off …

Det som kommer nå er en høytflygende innføring som vil ta deg gjennom litt grunnleggende konfigurasjon og bruk av Subversion. Når du har fullført innføringen, vil du ha en grunnleggende forståelse av Subversions typiske bruksmåter.

[Notat]Notat

Eksemplene som brukes i dette tillegget forutsetter at du har svn, kommandolinjeklienten, og svnadmin, det administrative verktøyet, klar til kjøring. Det forutsetter også at du bruker Subversion 1.2 eller senere (kjør svn --version for å sjekke).

Subversion lagrer alle versjonerte data i et sentralt depot. For å begynne, lag et nytt depot:

$ svnadmin create /sti/til/depot
$ ls /sti/til/depot
conf/  dav/  db/  format  hooks/  locks/  README.txt

Denne kommandoen lager en ny katalog /sti/til/depot som inneholder et Subversiondepot. Denne nye katalogen inneholder (sammen med andre ting) en samling databasefiler. Du vil ikke se dine versjonerte filer hvis du tar en kikk innenfor. For mer informasjon om opprettelse og vedlikehold av depot, se Kapittel 5, Depotadministrasjon.

Subversion har ikke noen oppfatning av et prosjekt. Depotet er kun et virtuelt versjonert filsystem, et stort tre som kan inneholde hva du vil. Noen administratorer foretrekker å lagre bare ett prosjekt i et depot, andre foretrekker å lagre flere prosjekter i et depot ved å plassere dem i egne kataloger. Fordeler og ulemper med hvert system diskuteres i “Velge en depot-layout”. Uansett, depotet holder bare rede på filer og kataloger, så det er opp til mennesker å se på spesielle kataloger som prosjekter. Så selv om du ser referanser til prosjekter i denne boka, husk på at vi bare snakker om en katalog (eller samling av kataloger) i depotet.

I dette eksempelet går vi ut i fra at du allerede har en form for prosjekt (en samling av filer og kataloger) som du vil importere inn i det nyopprettede Subversiondepotet ditt. Start med å organisere dem i en enkel katalog kalt mittprosjekt eller noe annet, hvis du vil. På grunn av ting som bli avklart senere (se Kapittel 4, Forgrening og fletting), bør katalogstrukturen til prosjektet inneholde tre kataloger på toppnivå som kalles branches, tags og trunk. trunk-katalogen inneholder alle dine data, mens katalogene branches og tags er tomme:

/tmp/mittprosjekt/branches/
/tmp/mittprosjekt/tags/
/tmp/mittprosjekt/trunk/
                     foo.c
                     bar.c
                     Makefile
                     …

Katalogene branches, tags og trunk er egentlig ikke nødvendig for at Subversion skal fungere. Det er bare en utbredt konvensjonell måte å gjøre ting på som du også sannsynligvis vil komme til å bruke.

Når du har klargjort treet med data, importer det inn i depotet med kommandoen svn import (se svn import):

$ svn import /tmp/mittprosjekt file:///sti/til/depot/mittprosjekt -m "Innledende import"
Legger til         /tmp/mittprosjekt/branches
Legger til         /tmp/mittprosjekt/tags
Legger til         /tmp/mittprosjekt/trunk
Legger til         /tmp/mittprosjekt/trunk/foo.c
Legger til         /tmp/mittprosjekt/trunk/bar.c
Legger til         /tmp/mittprosjekt/trunk/Makefile
…
La inn revisjon 1.
$ 

Nå inneholder depotet dette treet med data. Som nevnt tidligere, vil du ikke se filene dine ved å se direkte inn i depotet; de er lagret i en database. Men depotets virtuelle filsystem inneholder nå en toppkatalog kalt mittprosjekt, som igjen inneholder dine data.

Legg merke til at den originale /tmp/mittprosjekt-katalogen er uforandret, Subversion kjenner ikke til den. (Faktisk kan du til og med slette denne katalogen hvis du ønsker det.) For å starte med å manipulere dataene i depotet, må du lage en ny arbeidskopi av dataene, et slags personlig arbeidsområde. Be Subversion om å hente ut en arbeidskopi fra katalogen mittprosjekt/trunk i depotet:

$ svn checkout file:///sti/til/depot/mittprosjekt/trunk mittprosjekt
A  mittprosjekt/foo.c
A  mittprosjekt/bar.c
A  mittprosjekt/Makefile
…
Sjekket ut revisjon 1.

Nå har du en personlig kopi av en del av depotet i en ny katalog kalt mittprosjekt. Du kan redigere filene i arbeidskopien og deretter legge disse forandringene inn i depotet.

  • Gå inn i arbeidskopien og rediger innholdet av en fil.

  • Kjør kommandoen svn diff for å se en unified diff (forskjellsfil) over forandringene dine.

  • Kjør svn commit for å legge inn den nye versjonen av fila di til depotet.

  • Kjør svn update for å oppdatere arbeidskopien din i forhold til depotet.

For en full gjennomgang av tingene som du kan gjøre med arbeidskopien din, les Kapittel 2, Grunnleggende bruk.

Ved dette punktet har du valget å gjøre depotet ditt tilgjengelig over et nettverk. Se Kapittel 6, Serverkonfigurasjon for å lære om de forskjellige serverprosessene tilgjengelig og hvordan du setter dem opp.

### TODO: Let's make this into a full tutorial, rather than simply referring off to other sections. ###




[51] Legg merke til at URLen som hentes ut i eksempelet ovenfor ikke ender med svn, men med en underkatalog fra den kalt trunk. Se diskusjonen vår om Subversions forgrenings- og merkemodell for begrunnelsen for dette.

Tillegg B. Subversion for CVS-brukere

Dette tillegget er en guide for CVS-brukere som nettopp har begynt å bruke Subversion. Det er hovedsaklig en liste over forskjeller mellom de to systemene som om den er sett fra en høyde av 3.000 meter. For hver seksjon refererer vi tilbake til relevante kapitler når det er mulig.

Selv om målet til Subversion er å overta dagens og fremtidens brukermasse, var det nødvendig med nye funksjoner og forandringer i oppbygningen for å ordne enkelte ødelagte virkemåter i CVS. Dette betyr at du som CVS-bruker kanskje må bryte vaner – av den typen du har glemt var merkelige til å begynne med.

Revisjonsnumre er forskjellige nå

I CVS er revisjonsnumrene konstruert for hver enkelt fil. Dette er fordi CVS lagrer dataene sine i RCS-filer; hver fil har en tilsvarende RCS-fil i depotet, og depotet er lagt ut på bortimot samme måte som prosjekttreet ditt.

I Subversion ser depotet ut som et enkeltstående filsystem. Hver innlegging resulterer i et helt nytt filsystemtre; depotet er i grunnen en rekke av trær. Hvert av disse trærne er merket med hvert sitt revisjonsnummer. Når noen snakker om revisjon 54, snakker de om et spesifikt tre (og indirekte, sånn som filsystemet så ut etter den 54. innleggingen).

Teknisk sett gir det ingen ingen mening å snakke om revisjon 5 av foo.c. Istedenfor vil man si foo.c som den fremstår i revisjon 5. Vær også forsiktig når du gjør deg antakelser om utviklingen av en fil. I CVS er revisjon 5 og 6 av foo.c alltid forskjellig. I Subversion er det mest sannsynlig at foo.c ikke forandret seg mellom revisjon 5 og 6.

For flere detaljer om dette emnet, se “Revisjoner”.

Katalogversjoner

I tillegg til å arkivere innholdet av filene, holder Subversion også orden på trestrukturer. Dette er en av hovedgrunnene til at Subversion ble skrevet for å erstatte CVS.

Her er hva dette har å si for deg, som en tidligere CVS-bruker:

  • Kommandoene svn add og svn delete virker nå også på kataloger, akkurat som de gjør på filer. Det samme gjelder svn copy og svn move. Disse kommandoene forårsaker imidlertid ingen øyeblikkelige forandringer i depotet. Istedenfor blir de elementene det gjelder lagt i kø for tillegging eller sletting. Det vil ikke bli gjort noen forandringer i depotet før du kjører svn commit.

  • Kataloger er ikke dumme lagringsplasser for filer mer, de har revisjonsnumre i likhet med filer. (Eller riktigere beskrevet, det er korrekt å snakke om katalogen foo/ i revisjon 5.

La oss snakke mer om det siste punktet. Versjonskontroll av kataloger er et vanskelig problem. Fordi vi ønsker å tillate kopier som inneholder blandede revisjoner, er det lagt inn begrensninger i hvor langt vi kan gå når det gjelder å misbruke denne modellen.

Fra et teoretisk synspunkt definerer vi revisjon 5 av katalogen foo til å bety en spesifikk samling av katalogposter og egenskaper. Tenk deg så at vi begynner å legge til og fjerne filer fra foo, og deretter legger det inn. Det ville være løgn å si at vi fortsatt har revisjon 5 av foo. Imidlertid, hvis vi øker revisjonsnummeret for foo etter innleggingen, ville det også være en løgn; det kan være andre forandringer i foo som vi foreløpig ikke har mottatt, fordi vi ikke har oppdatert enda.

Subversion tar seg av dette problemet ved å i all stillhet undersøke innlagte tillegginger og slettinger i .svn, det sjekkes at alt er i orden i henhold til depotet, og det nye revisjonsnummeret blir korrekt satt for katalogen. Derfor, det er kun etter en oppdatering det er helt sikkert å si at du har en perfekt revisjon av en katalog. Mesteparten av tiden vil arbeidskopien din inneholde uperfekte katalogrevisjoner.

På samme måte vil et problem oppstå hvis du forsøker å legge inn forandringer i egenskapene for en katalog. Normalt ville innleggingen øke det lokale revisjonsnummeret for arbeidskatalogen. Men også her ville det være en løgn, fordi det kan være tillegg og slettinger som katalogen fortsatt ikke har, fordi ingen oppdatering er gjort. Derfor får du ikke lov til å legge inn egenskapsforandringer på en katalog hvis den ikke er oppdatert.

For videre diskusjon om begrensningene på versjonskontroll for kataloger, se “Arbeidskopier med blandede revisjonsnumre”.

Flere frakoblede operasjoner

I de senere år har diskplass blitt hårreisende billig og tilgjengelig, i motsetning til båndbredde. Derfor er arbeidskopiene til Subversion blitt optimalisert for den mer dyrebare ressursen.

Den administrative katalogen .svn tjener samme formål som CVS-katalogen, unntatt at den også lagrer skrivebeskyttede, rene kopier av filene dine. Dette gjør at du kan gjøre mange ting uten nettforbindelse:

svn status

Viser deg alle lokale forandringer du har gjort (se svn status)

svn diff

Viser deg forandringene dine i detalj (se svn diff)

svn revert

Tilbakestiller dine lokale forandringer (se svn revert)

I tillegg tillater de originale filene Subversionklienten å sende oppdateringen som en differansefil, noe CVS ikke kan gjøre.

Den siste delkommandoen i listen er ny; den vil ikke bare fjerne lokale forandringer, men den vil også fjerne operasjoner som tillegg og slettinger fra køen. Dette er den foretrukne måten å tilbakestille ei fil. Kommandoene rm file; svn update vil fortsatt virke, men det utydeliggjør meningen med oppdatering. Og med det samme vi er inne på temaet:

Skille mellom status og oppdatering

I Subversion har vi prøvd å fjerne en del av forvirringen angående kommandoene cvs status og cvs update.

Kommandoen cvs status har to formål: For det første å vise brukeren alle lokale forandringer i arbeidskopien, og for det andre å vise brukeren hvilke filer som er utdatert. Uheldigvis, på grunn av CVSs uoversiktlige utlisting, er det mange CVS-brukere som ikke bruker denne kommandoen i det hele tatt. Istedenfor har de lagt seg til vanen å kjøre cvs update eller cvs update -n for å få en rask oversikt over forandringene. Hvis brukere glemmer å bruke -n-valget, vil dette føre til at det flettes inn forandringer fra depotet som de kanskje ikke er klare til å håndtere.

Med Subversion har vi forsøkt å fjerne dette rotet ved å gjøre informasjonen fra svn status lettlest både for menneske og maskin. I tillegg begrenser informasjonen fra svn update seg til kun å inneholde filer som blir oppdatert, ikke lokale endringer.

Status

svn status lister alle filer som inneholder lokale forandringer. Standard oppførsel er å ikke kontakte depotet og nettverkskontakt er derfor ikke nødvendig. Denne delkommandoen godtar en god del valg, dette er de mest vanlige:

-u

Kontakt depotet for å finne ut, og deretter vise informasjon om utdaterte elementer.

-v

Vis alle elementer som er under versjonskontroll.

-N

Kjør kommandoen ikke-rekursivt (ikke gå inn i underkataloger).

status-kommandoen har to visningsformater. Med det vanlige korte formatet ser lokale forandringer ut som dette:

$ svn status
M      foo.c
M      bar/baz.c

Hvis du spesifisererer valget --show-updates (-u), brukes et lengre format:

$ svn status -u
M            1047   foo.c
       *     1045   faces.html
       *            bloo.png
M            1050   bar/baz.c
Status against revision:   1066

I dette tilfellet kommer to nye kolonner til syne. Den andre kolonnen inneholder en asterisk hvis fila eller katalogen er utdatert. Den tredje kolonnen viser arbeidskopiens revisjonsnummer for elementet. I eksempelet ovenfor indikerer asterisken at faces.html vil bli patchet hvis vi oppdaterer, og at bloo.png er ei fil som nylig er lagt til i depotet. (Når revisjonsnummeret ved siden av bloo.png mangler, betyr det at at fila ikke eksisterer enda i arbeidskopien.)

Til sist, her er en rask oversikt over de vanligste statuskodene som du vil se:

A    Ressursen er klargjort for tillegging (Addition)
D    Ressursen er klargjort for sletting (Deletion)
M    Ressursen inneholder lokale forandringer (Modifications)
C    Ressursen inneholder konflikter (forandringer er enda ikke blitt
       flettet sammen med depotet og arbeidskopien) (Conflicts)
X    Ressursen er ekstern i denne arbeidskopien (kan komme fra et annet
       depot (eXternal). Se “Externals Definitions”
?    Ressursen er ikke under versjonskontroll
!    Ressursen mangler eller er ikke komplett (fjernet av et annet
       verktøy enn Subversion)

For en mer detaljert diskusjon om svn status, se svn status.

Update

svn update oppdaterer arbeidskopien din og skriver kun informasjon om filer som blir oppdatert.

Subversion har kombinert CVSs P- og U-kode inn i den ene U-koden. Når en fletting eller konflikt oppstår, skriver Subversion rett og slett bare G eller C, istedenfor en hel setning om det.

For en mer detaljert diskusjon om svn update, se “Oppdater arbeidskopien din”.

Forgreninger og merker

Subversion skiller ikke mellom områder i filsystemet og områder for forgreninger, forgreninger og merker er vanlige kataloger i filsystemet. Dette er muligens det største enkeltstående mentale hinderet en CVS-bruker må forsere. Les alt om det i Kapittel 4, Forgrening og fletting.

[Advarsel]Advarsel

Siden Subversion behandler forgreninger og merker som ordinære kataloger, husk alltid på å hente ut katalogen kalt trunk (http://svn.example.com/repos/calc/trunk/) fra prosjektet ditt, og ikke selve prosjektet (http://svn.example.com/repos/calc/). Hvis du gjør den feilen å hente ut selve prosjektet, vil du ende opp med en kopi som inneholder en kopi av prosjektet for hver eneste gren og merke som du har.[52]

Metadata-egenskaper

En ny funksjon i Subversion lar deg legge til vilkårlige metadata (eller egenskaper) til filer og kataloger. Egenskaper er vilkårlige navn/verdi-par koblet til filer og kataloger i arbeidskopien din.

For å sette eller lese et egenskapsnavn, bruk delkommandoene svn propset og svn propget. For å liste ut alle egenskaper ved et objekt, bruk svn proplist.

For mer informasjon, se “Egenskaper”.

Reparering av konflikter

CVS markerer konflikter med innlagte konfliktmerker, og skriver en C under oppdatering. Historisk sett har dette laget problemer, fordi CVS ikke gjør nok. Mange brukere glemmer (eller ser ikke) C-en etter den fyker forbi på terminalen deres. Ofte glemmer de at konfliktmerkene er der i det hele tatt, og de legger deretter inn filer som inneholder konfliktmerker.

Subversion løser dette problemet ved å gjøre konflikter mer synlige. Den husker at ei fil har en konflikt, og vil ikke tillate deg å legge inn forandringene dine før du kjører svn resolved. Se “Løse konflikter (Flette inn andres forandringer)” for flere detaljer.

Binære filer og konverteringer

Generelt sett behandler Subversion binære filer mer elegant enn CVS. Fordi CVS bruker RCS, kan den bare lagre hele kopier av binære filer som forandres. Subversion, derimot, behandler forskjeller mellom filer ved hjelp av en binærdata-basert algoritme, uansett om de inneholder tekst eller binære data. Dette betyr at alle filer er lagret differensielt (pakket) i depotet.

CVS-brukere må merke binære filer med flagget -kb, for å forhindre data å bli rotet til (på grunn av nøkkelordutvidelser og oversettelse av linjeslutt). Dette glemmer de noen ganger.

Subversion tar den mer paranoide ruten – til å begynne med utfører den ingen form for nøkkelordutvidelser hvis du ikke ber den spesielt om å gjøre det (Se “Keyword Substitution” og “End-of-Line Character Sequences” for flere detaljer). Standard oppførsel for Subversion er å behandle alle fildata som rene strenger av bytes, og filer blir alltid lagret i depotet i en uoversatt tilstand.

For det andre har Subversion et internt begrep om ei fil er tekst eller binære data, men dette begrepet er bare bevart i arbeidskopien. Under en svn update vil Subversion utføre kontekstbaserte flettinger på tekstfiler som inneholder lokale endringer, men vil ikke forsøke dette for binære filer.

For å avgjøre hvorvidt en kontekstbasert fletting er mulig, leser Subversion svn:mime-type-egenskapen. Hvis fila ikke har noen svn:mime-type-egenskap, eller den har en mime-type som indikerer tekst (for eksempel text/*), går Subversion ut i fra at det er tekst. Ellers går Subversion ut i fra at fila er binær. Subversion hjelper også brukere ved å kjøre en algoritme som sjekker om ei fil er binær for kommandoene svn import og svn add. Disse kommandoene gjetter godt og setter (muligens) en binær svn:mime-type-egenskap på fila som blir lagt til. (Hvis Subversion gjetter feil, kan brukeren alltids fjerne eller redigere egenskapen for hånd.)

Versjonerte moduler

I motsetning til CVS er en arbeidskopi i Subversion klar over at den har hentet ut en modul. Dette betyr at hvis noen forandrer definisjonen av en modul (det vil si legger til eller fjerner komponenter), vil et kall til svn update oppdatere arbeidskopien på en skikkelig måte.

Subversion definerer moduler som en liste av kataloger innenfor en katalogegenskap: Se “Externals Definitions”.

Autentisering

Med CVSs pserver er du nødt til å logge inn på serveren før du kan utføre lese- eller skriveoperasjoner – du må til og med logge inn for anonyme operasjoner. Med et Subversiondepot som bruker Apache httpd eller svnserve på serveren, oppgir du ingen autentiseringsopplysninger, serveren vil spørre deg etter opplysningene (enten disse er brukernavn og passord, et klientsertifikat, eller til og med begge). Så hvis depotet er lesbart for hele verden, trenger du ikke å autentisere i det hele tatt for leseoperasjoner.

I likhet med CVS vil Subversion lagre dine autentiseringsopplysninger på disken (i katalogen ~/.subversion/auth/) unntatt hvis du ber programmet om å ikke gjøre det. Til dette bruker du valget --no-auth-cache.

Unntaket fra denne oppførselen, derimot, er tilfellet med å aksessere en svnserve-server gjennom en SSH-tunnel ved å bruke URL-skjemaet svn+ssh://. I det tilfellet forlanger ssh autentisering bare for å starte tunnelen.

Konvertere et depot fra CVS til Subversion

Kanskje den viktigste måten å gjøre CVS-brukere kjent med Subversion er å la dem fortsette arbeidet på prosjektene deres ved bruk av det nye systemet. Mens dette kan bli gjennomført til en viss grad ved å bruke et Subversiondepot som inneholder en flat import av et eksportert CVS-depot, vil den mer gjennomførte løsningen ikke bare inneholde den siste versjonen av dataene, men også hele historien, fra et system til et annet. Dette er et ekstremt vanskelig problem å løse som involverer å fastslå et sett med forandringer uten at atomiske egenskaper er tilgjengelige, og å oversette mellom systemenes forskjellige forgreningsmåter, i tillegg til andre komplikasjoner. Til tross for dette er det en håndfull verktøy som påstår i hvertfall delvis å kunne konvertere eksisterende CVS-depoter til Subversion.

Et slikt verktøy er cvs2svn (http://cvs2svn.tigris.org/), et Pythonskript originalt laget av medlemmer fra Subversions utviklermiljø. Et annet er Lev Serebryakovs RefineCVS (http://lev.serebryakov.spb.ru/refinecvs/). Disse verktøyene er komplette i varierende grad, og kan komme til å gjøre helt forskjellige vurderinger om hvordan historien til CVS-depotet skal behandles. Uansett hvilket verktøy du bestemmer deg for å bruke, vær nøye med å utføre så mye verifisering som du kan på konverteringsresultatet – når alt kommer til alt har du jobbet hardt for å lage denne historien!

For en oppdatert samling av lenker til kjente konverteringsverktøy, besøk lenkesiden på hjemmesiden til Subversion (http://subversion.tigris.org/project_links.html).




[52] Forutsatt at du ikke går tom for diskplass før uthentingen er ferdig.

Tillegg C. WebDAV and Autoversioning

WebDAV is an extension to HTTP, and is growing more and more popular as a standard for file-sharing. Today's operating systems are becoming extremely Web-aware, and many now have built-in support for mounting shares exported by WebDAV servers.

If you use Apache/mod_dav_svn as your Subversion network server, then to some extent, you are also running a WebDAV server. This appendix gives some background on the nature of this protocol, how Subversion uses it, and how well Subversion interoperates with other software that is WebDAV-aware.

Basic WebDAV Concepts

This section provides a very brief, very general overview to the ideas behind WebDAV. It should lay the foundation for understanding WebDAV compatibility issues between clients and servers.

Original WebDAV

RFC 2518 defines a set of concepts and accompanying extension methods to HTTP 1.1 that make the web into a more universal read/write medium. The basic idea is that a WebDAV-compliant web server can act like a generic file server; clients can mount shared folders that behave much like NFS or SMB filesystems.

The tragedy, though, is that the RFC 2518 WebDAV specification does not provide any sort of model for version control, despite the V in DAV. Basic WebDAV clients and servers assume only one version of each file or directory exists, and can be repeatedly overwritten.

Here are the concepts and terms introduced in basic WebDAV:

Resources

WebDAV lingo refers to any server-side object (that can be described with a URI) as a resource.

New write methods

Beyond the standard HTTP PUT method (which creates or overwrites a web resource), WebDAV defines new COPY and MOVE methods for duplicating or rearranging resources.

Collections

A collection is the WebDAV term for a grouping of resources. In most cases, it is analogous to a directory. Whereas file resources can be written or created with a PUT method, collection resources are created with the new MKCOL method.

Properties

This is the same idea present in Subversion—metadata attached to files and collections. A client can list or retrieve properties attached to a resource with the new PROPFIND method, and can change them with the PROPPATCH method. Some properties are wholly created and controlled by users (e.g. a property called color), and others are wholly created and controlled by the WebDAV server (e.g. a property that contains the last modification time of a file). The former kind are called dead properties, and the latter kind are called live properties.

Locking

A WebDAV server may decide to offer a locking feature to clients—this part of the specification is optional, although most WebDAV servers do offer the feature. If present, then clients can use the new LOCK and UNLOCK methods to mediate access to a resource. In most cases these methods are used to create exclusive write locks (as discussed in Lås-rediger-lås opp-løsningen”), although shared write locks are also possible in some server implementations.

Access control

A more recent specification (RFC 3744) defines a system for defining access control lists (ACLs) on WebDAV resources. Some clients and servers have begun to implement this feature.

DeltaV Extensions

Because RFC 2518 left out versioning concepts, another committee was left with the responsibility of writing RFC 3253, which adds versioning to WebDAV, a.k.a. DeltaV. WebDAV/DeltaV clients and servers are often called just DeltaV programs, since DeltaV implies the existence of basic WebDAV.

DeltaV introduces a whole slew of new acronyms, but don't be intimidated. The ideas are fairly straightforward:

Per-resource versioning

Like CVS and other version-control systems, DeltaV assumes that each resource has a potentially infinite number of states. A client begins by placing a resource under version control using the new VERSION-CONTROL method.

Server-side working-copy model

Some DeltaV servers support the ability to create a virtual workspace on the server, where all of your work is performed. Clients use the MKWORKSPACE method to create a private area, then indicate they want to change specific resources by checking them out into the workspace, editing them, and checking them in again. In HTTP terms, the sequence of methods would be CHECKOUT, PUT, CHECKIN.

Client-side working-copy model

Some DeltaV servers also support the idea that the client may have a private working copy on local disk. When the client wants to commit changes to the server, it begins by creating a temporary server transaction (called an activity) with the MKACTIVITY method. The client then performs a CHECKOUT on each resource it wishes to change and sends PUT requests. Finally, the client performs a CHECKIN resource, or sends a MERGE request to check in all resources at once.

Configurations

DeltaV allows you define flexible collections of resources called configurations, which don't necessarily correspond to particular directories. A configuration can be made to point to specific versions of files, and then a baseline snapshot can be made, much like a tag.

Extensibility

DeltaV defines a new method, REPORT, which allows the client and server to perform customized data exchanges. While DeltaV defines a number of standardized history reports that a client can request, the server is also free to define custom reports. The client sends a REPORT request with a properly-labeled XML body full of custom data; assuming the server understands the specific report-type, it responds with an equally custom XML body. This technique is very similar to XML-RPC.

Subversion and DeltaV

The original WebDAV standard has been widely successful. Every modern computer operating system has a general WebDAV client built-in (details to follow), and a number of popular standalone applications are also able to speak WebDAV — Microsoft Office, Dreamweaver, and Photoshop to name a few. On the server end, the Apache webserver has been able to provide WebDAV services since 1998 and is considered the de-facto open-source standard. There are several other commercial WebDAV servers available, including Microsoft's own IIS.

DeltaV, unfortunately, has not been so successful. It's very difficult to find any DeltaV clients or servers. The few that do exist are relatively unknown commercial products, and thus it's very difficult to test interoperability. It's not entirely clear as to why DeltaV has remained stagnant. Some argue that the specification is just too complex, others argue that while WebDAV's features have mass appeal (even the least technical users appreciate network file-sharing), version control features aren't interesting or necessary for most users. Finally, some have argued that DeltaV remains unpopular because there's still no open-source server product which implements it.

When Subversion was still in its design phase, it seemed like a great idea to use Apache httpd as the main network server. It already had a module to provide WebDAV services. DeltaV was a relatively new specification. The hope was that the Subversion server module (mod_dav_svn) would eventually evolve into an open-source DeltaV reference implementation. Unfortunately, DeltaV has a very specific versioning model that doesn't quite line up with Subversion's model. Some concepts were mappable, others were not.

The upshot is that

  1. The Subversion client is not a fully-implemented DeltaV client.

    The client needs certain things from the server that DeltaV cannot provide, and thus is largely dependent on a number of Subversion-specific REPORT requests that only mod_dav_svn understands.

  2. mod_dav_svn is not a fully-implemented DeltaV server.

    Many portions of the DeltaV specification were irrelevant to Subversion, and thus left unimplemented.

There is still some debate in the developer community as to whether or not it's worthwhile to remedy either of these situations. It's fairly unrealistic to change Subversion's design to match DeltaV, so there's probably no way the client can ever learn to get everything it needs from a general DeltaV server. On the other hand, mod_dav_svn could be further developed to implement all of DeltaV, but it's hard to find motivation to do so—there are almost no DeltaV clients to interoperate with.

Autoversioning

While the Subversion client is not a full DeltaV client, nor the Subversion server a full DeltaV server, there's still a glimmer of WebDAV interoperability to be happy about: it's called autoversioning.

Autoversioning is an optional feature defined in the DeltaV standard. A typical DeltaV server will reject an ignorant WebDAV client attempting to do a PUT to a file that's under version control. To change a version-controlled file, the server expects a series proper versioning requests: something like MKACTIVITY, CHECKOUT, PUT, CHECKIN. But if the DeltaV server supports autoversioning, then write-requests from basic WebDAV clients are accepted. The server behaves as if the client had issued the proper series of versioning requests, performing a commit under the hood. In other words, it allows a DeltaV server to interoperate with ordinary WebDAV clients that don't understand versioning.

Because so many operating systems already have integrated WebDAV clients, the use case for this feature borders on fantastical: imagine an office of ordinary users running Microsoft Windows or Mac OS. Each user mounts the Subversion repository, which appears to be an ordinary network folder. They use the shared folder as they always do: open files, edit them, save them. Meanwhile, the server is automatically versioning everything. Any administrator (or knowledgeable user) can still use a Subversion client to search history and retrieve older versions of data.

This scenario isn't fiction: it's real and it works, as of Subversion 1.2 and later. To activate autoversioning in mod_dav_svn, use the SVNAutoversioning directive within the httpd.conf Location block, like so:

<Location /repos>
  DAV svn
  SVNPath /path/to/repository
  SVNAutoversioning on
</Location>

When SVNAutoversioning is active, write requests from WebDAV clients result in automatic commits. A generic log message is auto-generated and attached to each revision.

Before activating this feature, however, understand what you're getting into. WebDAV clients tend to do many write requests, resulting in a huge number of automatically committed revisions. For example, when saving data, many clients will do a PUT of a 0-byte file (as a way of reserving a name) followed by another PUT with the real filedata. The single file-write results in two separate commits. Also consider that many applications auto-save every few minutes, resulting in even more commits.

If you have a post-commit hook program that sends email, you may want to disable email generation either altogether, or on certain sections of the repository; it depends on whether you think the influx of emails will still prove to be valuable notifications or not. Also, a smart post-commit hook program can distinguish between a transaction created via autoversioning and one created through a normal svn commit. The trick is to look for a revision property named svn:autoversioned. If present, the commit was made by a generic WebDAV client.

Another feature that may be a useful complement for SVNAutoversioning comes from Apache's mod_mime module. If a generic WebDAV client adds a new file to the repository, there's no opportunity for the user to set the the svn:mime-type property. This might cause the file to appear as generic icon when viewed within a WebDAV shared folder, not having an association with any application. One remedy is to have a sysadmin (or other Subversion-knowledgable person) check out a working copy and manually set the svn:mime-type property on necessary files. But there's potentially no end to such cleanup tasks. Instead, you can use the ModMimeUsePathInfo directive in your Subversion <Location> block:

<Location /repos>
  DAV svn
  SVNPath /path/to/repository
  SVNAutoversioning on

  ModMimeUsePathInfo on

</Location>

This directive allows mod_mime to attempt automatic deduction of the mime-type on new files that enter the repository via autoversioning. The module looks at the file's named extension and possibly the contents as well; if the file matches some common patterns, then the the file's svn:mime-type property will be set automatically.

Client Interoperability

All WebDAV clients fall into one of three categories—standalone applications, file-explorer extensions, or filesystem implementations. These categories broadly define the types of WebDAV functionality available to users. Tabell C.1, “Common WebDAV Clients” gives our categorization and a quick description of some common pieces of WebDAV-enabled software. More details about these software offerings, as well as their general category, can be found in the sections that follow.

Tabell C.1. Common WebDAV Clients

SoftwareCategoryDescription
Adobe PhotoshopStandalone WebDAV applicationsImage editing software, allowing direct opening from, and writing to, WebDAV URLs
CadaverStandalone WebDAV applicationsCommand-line WebDAV client supporting file transfer, tree, and locking operations
DAV ExplorerStandalone WebDAV applicationsGUI tool for exploring WebDAV shares
davfs2WebDAV filesystem implementationLinux file system driver that allows you to mount a WebDAV share
GNOME NautilusFile-explorer WebDAV extensionsGUI file explorer able to perform tree operations on a WebDAV share
KDE KonquerorFile-explorer WebDAV extensionsGUI file explorer able to perform tree operations on a WebDAV share
Mac OS XWebDAV filesystem implementationOperating system with built-in support for mounting WebDAV shares locally
Macromedia DreamweaverStandalone WebDAV applicationsWeb production software able to directly read from and write to WebDAV URLs
Microsoft OfficeStandalone WebDAV applicationsOffice productivity suite with several components able to directly read from and write to WebDAV URLs
Microsoft Web FoldersFile-explorer WebDAV extensionsGUI file explorer program able to perform tree operations on a WebDAV share
Novell NetDriveWebDAV filesystem implementationDrive-mapping program for assigning Windows drive letters to a mounted remote WebDAV share
SRT WebDriveWebDAV filesystem implementationFile transfer software which, among other things, allows the assignment of Windows drive letters to a mounted remote WebDAV share


Standalone WebDAV applications

A WebDAV application is a program which contains built-in functionality for speaking WebDAV protocols with a WebDAV server. We'll cover some of the most popular programs with this kind of WebDAV support.

Microsoft Office, Dreamweaver, Photoshop

On Windows, there are several well-known applications that contain integrated WebDAV client functionality, such as Microsoft's Office, [53] Adobe's Photoshop, and Macromedia's Dreamweaver programs. They're able to directly open and save to URLs, and tend to make heavy use of WebDAV locks when editing a file.

Note that while many of these programs also exist for the Mac OS X, they do not appear to support WebDAV directly on that platform. In fact, on Mac OS X, the File->Open dialog box doesn't allow one to type a path or URL at all. It's likely that the WebDAV features were deliberately left out of Macintosh versions of these programs, since OS X already provides such excellent low-level filesystem support for WebDAV.

Cadaver, DAV Explorer

Cadaver is a bare-bones Unix commandline program for browsing and changing WebDAV shares. Like the Subversion client, it uses the neon HTTP library—not surprisingly, both neon and cadaver are written by the same author. Cadaver is free software (GPL license) and is available at http://www.webdav.org/cadaver/.

Using cadaver is similar to using a commandline FTP program, and thus it's extremely useful for basic WebDAV debugging. It can be used to upload or download files in a pinch, and also to examine properties, copy, move, lock or unlock files:

$ cadaver http://host/repos
dav:/repos/> ls
Listing collection `/repos/': succeeded.
Coll: > foobar                                 0  May 10 16:19
      > playwright.el                       2864  May  4 16:18
      > proofbypoem.txt                     1461  May  5 15:09
      > westcoast.jpg                      66737  May  5 15:09

dav:/repos/> put README
Uploading README to `/repos/README':
Progress: [=============================>] 100.0% of 357 bytes succeeded.

dav:/repos/> get proofbypoem.txt
Downloading `/repos/proofbypoem.txt' to proofbypoem.txt:
Progress: [=============================>] 100.0% of 1461 bytes succeeded.

DAV Explorer is another standalone WebDAV client, written in Java. It's under a free Apache-like license and is available at http://www.ics.uci.edu/~webdav/. DAV Explorer does everything cadaver does, but has the advantages of being portable and being a more user-friendly GUI application. It's also one of the first clients to support the new WebDAV Access Control Protocol (RFC 3744).

Of course, DAV Explorer's ACL support is useless in this case, since mod_dav_svn doesn't support it. The fact that both Cadaver and DAV Explorer support some limited DeltaV commands isn't particularly useful either, since they don't allow MKACTIVITY requests. But it's not relevant anyway; we're assuming all of these clients are operating against an autoversioning repository.

File-explorer WebDAV extensions

Some popular file explorer GUI programs support WebDAV extensions which allow a user to browse a DAV share as if it was just another directory on the local computer, and allowing basic tree editing operations on the items in that share. For example, Windows Explorer is able to browse a WebDAV server as a network place. Users can drag files to and from the desktop, or can rename, copy, or delete files in the usual way. But because it's only a feature of the file-explorer, the DAV share isn't visible to ordinary applications. All DAV interaction must happen through the explorer interface.

Microsoft Web Folders

Microsoft was one of the original backers of the WebDAV specification, and first started shipping a client in Windows 98, known as Web Folders. This client was also shipped in Windows NT4 and 2000.

The original Web Folders client was an extension to Explorer, the main GUI program used to browse filesystems. It works well enough. In Windows 98, the feature might need to be explicitly installed if Web Folders aren't already visible inside My Computer. In Windows 2000, simply add a new network place, enter the URL, and the WebDAV share will pop up for browsing.

With the release of Windows XP, Microsoft started shipping a new implementation of Web Folders, known as the WebDAV mini-redirector. The new implementation is a filesystem-level client, allowing WebDAV shares to be mounted as drive letters. Unfortunately, this implementation is incredibly buggy. The client usually tries to convert http URLs (http://host/repos) into UNC share notation (\\host\repos); it also often tries to use Windows Domain authentication to respond to basic-auth HTTP challenges, sending usernames as HOST\username. These interoperability problems are severe and documented in numerous places around the web, to the frustration of many users. Even Greg Stein, the original author of Apache's WebDAV module, recommends against trying to use XP Web Folders against an Apache server.

It turns out that the original Explorer-only Web Folders implementation isn't dead in XP, it's just buried. It's still possible to find it by using this technique:

  1. Go to 'Network Places'.

  2. Add a new network place.

  3. When prompted, enter the URL of the repository, but include a port number in the URL. For example, http://host/repos would be entered as http://host:80/repos instead.

  4. Respond to any authentication prompts.

There are a number of other rumored workarounds to the problems, but none of them seem to work on all versions and patchlevels of Windows XP. In our tests, only the previous algorithm seems to work consistently on every system. The general consensus of the WebDAV community is that you should avoid the new Web Folders implementation and use the old one instead, and that if you need a real filesystem-level client for Windows XP, then use a third-party program like WebDrive or NetDrive.

A final tip: if you're attempting to use XP Web Folders, make sure you have the absolute latest version from Microsoft. For example, Microsoft released a bug-fixed version in January 2005, available at http://support.microsoft.com/?kbid=892211. In particular, this release is known to fix a bug whereby browsing a DAV share shows an unexpected infinite recursion.

Nautilus, Konqueror

Nautilus is the official file manager/browser for the GNOME desktop (http://www.gnome.org), and Konqueror is the manager/browser for the KDE desktop (http://www.kde.org). Both of these applications have an explorer-level WebDAV client built-in, and operate just fine against an autoversioning repository.

In GNOME's Nautilus, from the File menu, select Open location and enter the URL. The repository should then be displayed like any other filesystem.

In KDE's Konqueror, you need to use the webdav:// scheme when entering the URL in the location bar. If you enter an http:// URL, Konqueror will behave like an ordinary web browser. You'll likely see the generic HTML directory listing produced by mod_dav_svn. By entering webdav://host/repos instead of http://host/repos, Konqueror becomes a WebDAV client and displays the repository as a filesystem.

WebDAV filesystem implementation

The WebDAV filesystem implementation is arguably the best sort of WebDAV client. It's implemented as a low-level filesystem module, typically within the operating system's kernel. This means that the DAV share is mounted like any other network filesystem, similar to mounting an NFS share on Unix, or attaching an SMB share as drive-letter in Windows. As a result, this sort of client provides completely transparent read/write WebDAV access to all programs. Applications aren't even aware that WebDAV requests are happening.

WebDrive, NetDrive

Both WebDrive and NetDrive are excellent commercial products which allow a WebDAV share to be attached as drive letters in Windows. We've had nothing but success with these products. At the time of writing, WebDrive can be purchased from South River Technologies (http://www.southrivertech.com). NetDrive ships with Netware, is free of charge, and can be found by searching the web for netdrive.exe. Though it is freely available online, users are required to have a Netware license. (If any of that sounds odd to you, you're not alone. See this page on Novell's website: http://www.novell.com/coolsolutions/qna/999.html)

Mac OS X

Apple's OS X operating system has an integrated filesystem-level WebDAV client. From the Finder, select the Connect to Server item from the Go menu. Enter a WebDAV URL, and it appears as a disk on the desktop, just like any other mounted volume. You can also mount a WebDAV share from the Darwin terminal by using the webdav filesystem type with the mount command:

$ mount -t webdav http://svn.example.com/repos/project /some/mountpoint
$

Note that if your mod_dav_svn is older than version 1.2, OS X will refuse to mount the share as read-write; it will appear as read-only. This is because OS X insists on locking support for read-write shares, and the ability to lock files first appeared in Subversion 1.2.

One more word of warning: OS X's WebDAV client can sometimes be overly sensitive to HTTP redirects. If OS X is unable to mount the repository at all, you may need to enable the BrowserMatch directive in the Apache server's httpd.conf:

BrowserMatch "^WebDAVFS/1.[012]" redirect-carefully

Linux davfs2

Linux davfs2 is a filesystem module for the Linux kernel, whose development is located at http://dav.sourceforge.net/. Once installed, a WebDAV network share can be mounted with the usual Linux mount command:

$ mount.davfs http://host/repos /mnt/dav



[53] WebDAV support was removed from Microsoft Access for some reason, but exists in the rest of the Office suite.

Tillegg D. Third Party Tools

Subversion's modular design (covered in “Layered Library Design”) and the availability of language bindings (as described in “Using Languages Other than C and C++”) make it a likely candidate for use as an extension or backend to other pieces of software. For a listing of many third-party tools that are using Subversion functionality under-the-hood, check out the Links page on the Subversion website (http://subversion.tigris.org/project_links.html).

Tillegg E. Copyright


Copyright (c) 2002-2006
Ben Collins-Sussman, Brian W. Fitzpatrick, C. Michael Pilato.  

This work is licensed under the Creative Commons Attribution License.
To view a copy of this license, visit
http://creativecommons.org/licenses/by/2.0/ or send a letter to
Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305,
USA.

A summary of the license is given below, followed by the full legal
text.

--------------------------------------------------------------------

You are free:

    * to copy, distribute, display, and perform the work
    * to make derivative works
    * to make commercial use of the work

Under the following conditions:
	
Attribution. You must give the original author credit.

    * For any reuse or distribution, you must make clear to others the
      license terms of this work.

    * Any of these conditions can be waived if you get permission from
      the author.

Your fair use and other rights are in no way affected by the above.

The above is a summary of the full license below.

====================================================================

Creative Commons Legal Code
Attribution 2.0

CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR
DAMAGES RESULTING FROM ITS USE.

License

THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS
CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS
PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE
WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS
PROHIBITED.

BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND
AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS
YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF
SUCH TERMS AND CONDITIONS.

1. Definitions

   a. "Collective Work" means a work, such as a periodical issue,
      anthology or encyclopedia, in which the Work in its entirety in
      unmodified form, along with a number of other contributions,
      constituting separate and independent works in themselves, are
      assembled into a collective whole. A work that constitutes a
      Collective Work will not be considered a Derivative Work (as
      defined below) for the purposes of this License.

   b. "Derivative Work" means a work based upon the Work or upon the
      Work and other pre-existing works, such as a translation,
      musical arrangement, dramatization, fictionalization, motion
      picture version, sound recording, art reproduction, abridgment,
      condensation, or any other form in which the Work may be recast,
      transformed, or adapted, except that a work that constitutes a
      Collective Work will not be considered a Derivative Work for the
      purpose of this License. For the avoidance of doubt, where the
      Work is a musical composition or sound recording, the
      synchronization of the Work in timed-relation with a moving
      image ("synching") will be considered a Derivative Work for the
      purpose of this License.

   c. "Licensor" means the individual or entity that offers the Work
      under the terms of this License.

   d. "Original Author" means the individual or entity who created the Work.

   e. "Work" means the copyrightable work of authorship offered under
      the terms of this License.

   f. "You" means an individual or entity exercising rights under this
      License who has not previously violated the terms of this
      License with respect to the Work, or who has received express
      permission from the Licensor to exercise rights under this
      License despite a previous violation.

2. Fair Use Rights. Nothing in this license is intended to reduce,
   limit, or restrict any rights arising from fair use, first sale or
   other limitations on the exclusive rights of the copyright owner
   under copyright law or other applicable laws.

3. License Grant. Subject to the terms and conditions of this License,
   Licensor hereby grants You a worldwide, royalty-free,
   non-exclusive, perpetual (for the duration of the applicable
   copyright) license to exercise the rights in the Work as stated
   below:

   a. to reproduce the Work, to incorporate the Work into one or more
      Collective Works, and to reproduce the Work as incorporated in
      the Collective Works;

   b. to create and reproduce Derivative Works;

   c. to distribute copies or phonorecords of, display publicly,
      perform publicly, and perform publicly by means of a digital
      audio transmission the Work including as incorporated in
      Collective Works;

   d. to distribute copies or phonorecords of, display publicly,
      perform publicly, and perform publicly by means of a digital
      audio transmission Derivative Works.

   e.

      For the avoidance of doubt, where the work is a musical composition:

         i. Performance Royalties Under Blanket Licenses. Licensor
            waives the exclusive right to collect, whether
            individually or via a performance rights society
            (e.g. ASCAP, BMI, SESAC), royalties for the public
            performance or public digital performance (e.g. webcast)
            of the Work.

        ii. Mechanical Rights and Statutory Royalties. Licensor waives
            the exclusive right to collect, whether individually or
            via a music rights agency or designated agent (e.g. Harry
            Fox Agency), royalties for any phonorecord You create from
            the Work ("cover version") and distribute, subject to the
            compulsory license created by 17 USC Section 115 of the US
            Copyright Act (or the equivalent in other jurisdictions).

   f. Webcasting Rights and Statutory Royalties. For the avoidance of
      doubt, where the Work is a sound recording, Licensor waives the
      exclusive right to collect, whether individually or via a
      performance-rights society (e.g. SoundExchange), royalties for
      the public digital performance (e.g. webcast) of the Work,
      subject to the compulsory license created by 17 USC Section 114
      of the US Copyright Act (or the equivalent in other
      jurisdictions).

The above rights may be exercised in all media and formats whether now
known or hereafter devised. The above rights include the right to make
such modifications as are technically necessary to exercise the rights
in other media and formats. All rights not expressly granted by
Licensor are hereby reserved.

4. Restrictions.The license granted in Section 3 above is expressly
   made subject to and limited by the following restrictions:

   a. You may distribute, publicly display, publicly perform, or
      publicly digitally perform the Work only under the terms of this
      License, and You must include a copy of, or the Uniform Resource
      Identifier for, this License with every copy or phonorecord of
      the Work You distribute, publicly display, publicly perform, or
      publicly digitally perform. You may not offer or impose any
      terms on the Work that alter or restrict the terms of this
      License or the recipients' exercise of the rights granted
      hereunder. You may not sublicense the Work. You must keep intact
      all notices that refer to this License and to the disclaimer of
      warranties. You may not distribute, publicly display, publicly
      perform, or publicly digitally perform the Work with any
      technological measures that control access or use of the Work in
      a manner inconsistent with the terms of this License
      Agreement. The above applies to the Work as incorporated in a
      Collective Work, but this does not require the Collective Work
      apart from the Work itself to be made subject to the terms of
      this License. If You create a Collective Work, upon notice from
      any Licensor You must, to the extent practicable, remove from
      the Collective Work any reference to such Licensor or the
      Original Author, as requested. If You create a Derivative Work,
      upon notice from any Licensor You must, to the extent
      practicable, remove from the Derivative Work any reference to
      such Licensor or the Original Author, as requested.

   b. If you distribute, publicly display, publicly perform, or
      publicly digitally perform the Work or any Derivative Works or
      Collective Works, You must keep intact all copyright notices for
      the Work and give the Original Author credit reasonable to the
      medium or means You are utilizing by conveying the name (or
      pseudonym if applicable) of the Original Author if supplied; the
      title of the Work if supplied; to the extent reasonably
      practicable, the Uniform Resource Identifier, if any, that
      Licensor specifies to be associated with the Work, unless such
      URI does not refer to the copyright notice or licensing
      information for the Work; and in the case of a Derivative Work,
      a credit identifying the use of the Work in the Derivative Work
      (e.g., "French translation of the Work by Original Author," or
      "Screenplay based on original Work by Original Author"). Such
      credit may be implemented in any reasonable manner; provided,
      however, that in the case of a Derivative Work or Collective
      Work, at a minimum such credit will appear where any other
      comparable authorship credit appears and in a manner at least as
      prominent as such other comparable authorship credit.

5. Representations, Warranties and Disclaimer

UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING,
LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR
WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED,
STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF
TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE,
NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY,
OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT
DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED
WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.

6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY
   APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY
   LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE
   OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE
   WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
   DAMAGES.

7. Termination

   a. This License and the rights granted hereunder will terminate
      automatically upon any breach by You of the terms of this
      License. Individuals or entities who have received Derivative
      Works or Collective Works from You under this License, however,
      will not have their licenses terminated provided such
      individuals or entities remain in full compliance with those
      licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any
      termination of this License.

   b. Subject to the above terms and conditions, the license granted
      here is perpetual (for the duration of the applicable copyright
      in the Work). Notwithstanding the above, Licensor reserves the
      right to release the Work under different license terms or to
      stop distributing the Work at any time; provided, however that
      any such election will not serve to withdraw this License (or
      any other license that has been, or is required to be, granted
      under the terms of this License), and this License will continue
      in full force and effect unless terminated as stated above.

8. Miscellaneous

   a. Each time You distribute or publicly digitally perform the Work
      or a Collective Work, the Licensor offers to the recipient a
      license to the Work on the same terms and conditions as the
      license granted to You under this License.

   b. Each time You distribute or publicly digitally perform a
      Derivative Work, Licensor offers to the recipient a license to
      the original Work on the same terms and conditions as the
      license granted to You under this License.

   c. If any provision of this License is invalid or unenforceable
      under applicable law, it shall not affect the validity or
      enforceability of the remainder of the terms of this License,
      and without further action by the parties to this agreement,
      such provision shall be reformed to the minimum extent necessary
      to make such provision valid and enforceable.

   d. No term or provision of this License shall be deemed waived and
      no breach consented to unless such waiver or consent shall be in
      writing and signed by the party to be charged with such waiver
      or consent.

   e. This License constitutes the entire agreement between the
      parties with respect to the Work licensed here. There are no
      understandings, agreements or representations with respect to
      the Work not specified here. Licensor shall not be bound by any
      additional provisions that may appear in any communication from
      You. This License may not be modified without the mutual written
      agreement of the Licensor and You.

Creative Commons is not a party to this License, and makes no warranty
whatsoever in connection with the Work. Creative Commons will not be
liable to You or any party on any legal theory for any damages
whatsoever, including without limitation any general, special,
incidental or consequential damages arising in connection to this
license. Notwithstanding the foregoing two (2) sentences, if Creative
Commons has expressly identified itself as the Licensor hereunder, it
shall have all rights and obligations of Licensor.

Except for the limited purpose of indicating to the public that the
Work is licensed under the CCPL, neither party will use the trademark
"Creative Commons" or any related trademark or logo of Creative
Commons without the prior written consent of Creative Commons. Any
permitted use will be in compliance with Creative Commons'
then-current trademark usage guidelines, as may be published on its
website or otherwise made available upon request from time to time.

Creative Commons may be contacted at http://creativecommons.org/.

====================================================================

Indeks

Symboler

###
TODO: Flere indeksoppføringer!, Innledning

C

COMMITTED, Nøkkelord for revisjoner
Concurrent Versions System (CVS), Innledning

E

egenskaper, Egenskaper

R

revisions
specifying, Revision Specifiers
revisjoner
revisjonsnøkkelord, Nøkkelord for revisjoner
spesifisert som datoer, Revisjonsdatoer

S

Subversion
historien om, Subversions historie
svn
subcommands
add, svn add
blame, svn blame
cat, svn cat
checkout, svn checkout
cleanup, svn cleanup
commit, svn commit
copy, svn copy
delete, svn delete
diff, svn diff
export, svn export
help, svn help
import, svn import
info, svn info
list, svn list
lock, svn lock
log, svn log
merge, svn merge
mkdir, svn mkdir
move, svn move
propdel, svn propdel
propedit, svn propedit
propget, svn propget
proplist, svn proplist
propset, svn propset
resolved, svn resolved
revert, svn revert
status, svn status
switch, svn switch
unlock, svn unlock
update, svn update
svnadmin
subcommands
create, svnadmin create
deltify, svnadmin deltify
dump, svnadmin dump
help, svnadmin help
hotcopy, svnadmin hotcopy
list-dblogs, svnadmin list-dblogs
list-unused-dblogs, svnadmin list-unused-dblogs
load, svnadmin load
lslocks, svnadmin lslocks
lstxns, svnadmin lstxns
recover, svnadmin recover
rmlocks, svnadmin rmlocks
rmtxns, svnadmin rmtxns
setlog, svnadmin setlog
verify, svnadmin verify
svnlook
subcommands
author, svnlook author
cat, svnlook cat
changed, svnlook changed
date, svnlook date
diff, svnlook diff
dirs-changed, svnlook dirs-changed
help, svnlook help
history, svnlook history
info, svnlook info
lock, svnlook lock
log, svnlook log
propget, svnlook propget
proplist, svnlook proplist
tree, svnlook tree
uuid, svnlook uuid
youngest, svnlook youngest
svnversion, svnversion