Versjonskontroll med Subversion

For Subversion 1.4

(Bokrevisjon 3658)

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.