Opphavsrett © 2002, 2003, 2004, 2005, 2006, 2007 Ben Collins-Sussman, Brian W. Fitzpatrick, C. Michael Pilato
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
Figuroversikt
tabelloversikt
Eksempeloversikt
.reg-fil..svn/entries
FileEn 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 <users@subversion.tigris.org> 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.
Innholdsfortegnelse
“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.
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.
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:
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.
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.
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.
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.
Denne seksjonen tar for seg de forskjellige konvensjonene brukt i denne boka.
Brukt om kommandoer, utdata fra kommandoer og om valg.
Skrå skrift med konstant
breddeBrukt til utbyttbare elementer i kode og tekst
Skrå skriftBrukes for fil- og katalognavn
Kapitlene som følger og innholdet deres er listet her:
Dekker historien til Subversion så vel som funksjoner, arkitektur og komponenter.
Forklarer det grunnleggende om versjonskontroll og forskjellige versjoneringsmodeller, sammen med Subversions depot, arbeidskopier og revisjoner.
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.
Dekker mer kompleks funksjonalitet som vanlige brukere etterhvert vil komme i kontakt med, som versjonerte metadata, låsing av filer og “peg-revisjoner”.
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.
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.
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.
Utforsker Subversion-klientens konfigurasjonsfiler, behandling av internasjonalisert tekst og hvordan få eksterne verktøy til å samarbeide med Subversion.
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.
Forklarer i stor detalj hver eneste delkommando i svn, svnadmin og svnlook med nok eksempler for hele familien!
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.
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.
Beskriver detaljene om WebDAV og DeltaV, og hvordan du kan konfigurere Subversiondepotet til å være montert som et delt DAV-område.
Diskuterer verktøy som støtter eller bruker Subversion, inkludert alternative klientprogrammer, verktøy for å utforske depotet og så videre.
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.
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.
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.
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.
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.
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.
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.
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:
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.
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.
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.
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.
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.
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.
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.
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.
Figur 1, “Subversions arkitektur” illustrerer en “milehøy” oversikt over Subversions design.
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.
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.
Kommandolinjeklienten.
Et program for å rapportere tilstanden (i betydningen av revisjoner for de elementene som finnes) for en arbeidskopi.
Et verktøy for å inspisere et Subversiondepot direkte.
Et verktøy for å lage, tilpasse eller reparere et Subversiondepot.
Et program for å filtrere strømmer i dumpfil-format for et Subversiondepot.
En programtilleggsmodul for Apache HTTP-serveren, som brukes til å gjøre depotet ditt tilgjengelig for andre over et nettverk.
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.
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.
Innholdsfortegnelse
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.
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.
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.
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.
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å!
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.
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.
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.
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.
Det er på tide å gå fra det abstrakte til det konkrete. I denne seksjonen vil vi vise reelle eksempler på bruk av 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.
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”.
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.
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.
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.
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:
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.
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.
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.
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”.
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.
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.
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.
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.
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.
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.
Innholdsfortegnelse
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.
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.
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.
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
), or a pair of them
separated by a colon (REV-r
).
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.REV1:REV2
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
is the same thing as
using REV-r
.
And you can trivially reverse the implied range, too, by putting
a dash in front of the revision number, as in REV-1:REV-c
-.REV
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 |
|---|---|
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.
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
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 fooFila foo ble oppdatert
(Updated) og mottok
forandringer fra serveren.
A fooFila eller katalogen foo ble lagt
til (Added) i
arbeidskopien din.
D fooFila eller katalogen foo ble
slettet (Deleted) fra
arbeidskopien.
R fooFila 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 fooFila 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 fooFila 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.
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:
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.
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 |
|---|---|
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. |
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).
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]
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.
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.
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.
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 elementFila, katalogen eller den symbolske lenken
element er blitt klargjort for
tillegging til depotet.
C elementFila 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 elementFila, katalogen eller den symbolske lenken
element er blitt klargjort for
sletting fra depotet.
M elementInnholdet av fila element er
blitt forandret.
R elementFila, 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 elementKatalogen element er
uversjonert, men er relatert til en ekstern definisjon i
Subversion.
For å finne ut mer om
“externals”-defineringer, se “Externals Definitions”.
? elementFila, 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”.
! elementFila, 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.
~ elementFila, 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 elementFila, 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.)
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.
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 |
|---|---|
svn revert
|
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
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.mineDette 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.rGAMMELREVDette 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.rNYREVDette 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
Å 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.
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
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.
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 |
|---|---|
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.
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:
Viser deg bred informasjon: Loggmeldinger med dato- og forfatterinformasjon for revisjonene og hvilke stier som forandret seg i hver revisjon.
Viser deg de spesifikke detaljene om hvordan ei fil forandret seg over tid.
Denne blir brukt til å hente en vilkårlig fil som den var da den eksisterte i en spesiell revisjon og vise den på skjermen.
List filene i katalogen for en vilkårlig revisjon.
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.
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
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 $
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 $
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 … $
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-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.
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
…
Selv om de ikke blir så ofte brukt som kommandoene tidligere nevnt i dette kapitlet, vil du innimellom trenge disse kommandoene.
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-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.
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.
Innholdsfortegnelse
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!
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 |
|---|---|
The various forms of Subversion revision specifiers can be
mixed and matched when used to specify revision ranges. For
example, you can use |
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:
Den seneste (eller “yngste”) revisjonen i depotet.
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.
Den seneste revisjonen før eller lik
BASE, der et element ble
forandret.
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
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 |
|---|---|
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. |
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.
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.
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 |
|---|---|
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. |
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.
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.
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.
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.
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.
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:
nativeThis 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.
CRLFThis causes the file to contain
CRLF sequences for EOL markers,
regardless of the operating system in use.
LFThis causes the file to contain
LF characters for EOL markers,
regardless of the operating system in use.
CRThis 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).
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 |
|---|---|
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.
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:
DateThis 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.
RevisionThis 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.
AuthorThis 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.
HeadURLThis 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.
IdThis 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 |
|---|---|
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. |
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.
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.
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.
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.
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 |
|---|---|
Users and administrators alike are encouraged to attach
the |
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]
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 |
|---|---|
Because the |
![]() | 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.
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.
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.
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]
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:
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,
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,
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!
Innholdsfortegnelse
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).
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”).
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.
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å.
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.
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.
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.
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.
Det er to viktige ting du bør huske fra denne seksjonen.
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.
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.
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.
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:
Du vil flette katalogforandringer inn i den gjeldende arbeidskatalogen.
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
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 merge – “flette” – 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-apply – “finn 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:
Et innledende depottre (ofte kalt den venstre siden av sammenligningen),
Et slutt-depottre (ofte kalt den høyre siden av sammenligningen),
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.
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.
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.
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.
Når du snakker med en Subversionutvikler kan det hende du hører referanser til begrepet slektskap – ancestry. 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.
Det er mange forskjellige bruksområder for forgreninger og svn merge, og denne seksjonen beskriver de vanligste som du sannsynligvis vil komme over.
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 |
|---|---|
En fin måte å finne revisjonen en gren ble opprettet i
(“basen” av forgreningen) er å bruke valget
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
|
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.
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 forandringssett –
changesets).
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]
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.
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.
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.
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.
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:
Kopier hele “trunk” fra prosjektet til en ny grenkatalog.
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.
Et annet vanlig versjonskontrollkonsept er et merke – tag. 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.
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.
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.
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.
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.
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.
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.
Dette er måten vedlikehold av leverandørgrener vanligvis
fungerer på.
Du lager en katalog på toppnivå (som for eksempel
/vendor) for å lagre leverandørgrenene.
Deretter importerer du tredjepartskoden inn i en underkatalog i
denne toppkatalogen.
Så kopierer du denne underkatalogen inn på grenen der
hovedutviklingen foregår (for eksempel
/trunk på den riktige plasseringen.
Du gjør alltid dine lokale forandringer på grenen der
hovedutviklingen foregår.
For hver ny utgivelse av koden du følger med på, legger du den
inn på leverandørgrenen og fletter forandringene inn i
/trunk og ordner eventuelle konflikter som
måtte oppstå mellom dine lokale forandringer og de offisielle
forandringene.
Kanskje vil et eksempel hjelpe på å klarne opp i
fremgangsmåten.
Vi bruker en situasjon der utviklingsteamet lager et
regneprogram som lenker mot et tredjeparts bibliotek for
kompleks aritmetikk, libcomplex.
Vi starter med den innledende opprettelsen av leverandørgrenen og den første importen av
leverandørutgivelsen.
Vi kaller leverandørgrenen libcomplex, og
leverandørutgivelsene går i en underkatalog i
leverandørgrenen kalt current.
Og siden svn import oppretter alle de
mellomliggende foreldrekataloger som vi trenger, kan vi faktisk
gjøre begge disse stegene med en enkelt kommando.
$ svn import /sti/til/libcomplex-1.0 \
http://svn.example.com/repos/vendor/libcomplex/current \
-m 'Importerer innledende 1.0-versjon'
…
Vi har nå den nåværende versjonen av libcomplex-kildekoden i
/vendor/libcomplex/current.
Nå merker vi denne versjonen (se “Merker
(“tags”)” og deretter kopierer den inn
på hovedutviklingsgrenen.
Kopien vår vil opprette en ny katalog kalt
libcomplex i den eksisterende
prosjektkatalogen calc.
Det er i denne kopien av leverandørdataene vi vil gjøre
forandringene.
$ svn copy http://svn.example.com/repos/vendor/libcomplex/current \
http://svn.example.com/repos/vendor/libcomplex/1.0 \
-m 'Merker libcomplex-1.0'
…
$ svn copy http://svn.example.com/repos/vendor/libcomplex/1.0 \
http://svn.example.com/repos/calc/libcomplex \
-m 'Legger libcomplex-1.0 inn på hovedgrenen'
…
Vi henter ut prosjektets hovedgren – som nå inneholder en kopi av den første leverandørutgivelsen – og vi setter i gang med å tilpasse libcomplex-koden. Før vi vet ordet av det, er den modifiserte versjonen av libcomplex fullstendig integrert i kalkulatorprogrammet.[26]
Noen uker senere slipper utviklerne av libcomplex en ny versjon av biblioteket – versjon 1.1 – som inneholder trivelig funksjonalitet som vi har lyst på. Vi vil oppgradere til denne nye versjonen, men uten å miste forandringene vi gjorde i den eksisterende versjonen. Det vi egentlig vil gjøre, er å erstatte den nåværende utviklingsversjonen med en kopi av libcomplex 1.1 og deretter legge inn forandringene våre i den nye versjonen. Men vi gjør det faktisk den andre veien, legger inn forandringene i libcomplex mellom versjon 1.0 og 1.1 i den modifiserte kopien av den.
For å gjennomføre denne oppgraderingen, henter vi ut en kopi
av leverandørgrenen og erstatter koden i
current-katalogen med den nye koden for
libcomplex 1.1.
Vi kopierer bokstavelig talt nye filer på toppen av eksisterende
filer, kanskje ved å pakke ut .tar.gz-fila
oppå de eksisterende filene og katalogene.
Meningen med dette er å få
current-katalogen til å inneholde kun koden
fra libcomplex 1.1, og å forsikre seg om at all denne koden er
under versjonskontroll.
Og en annen ting var at vi ville at dette skulle skje uten å
forstyrre versjonskontrollhistorien alt for mye.
Etter å ha erstattet 1.0-koden med 1.1, vil svn
status vise filer med lokale forandringer sammen med
filer som kanskje er uversjonert eller mangler.
Hvis vi gjorde det vi skulle, er de uversjonerte filene bare de
nye filene introdusert i 1.1-versjonen av libcomplex – vi kjører
svn add på disse for å få dem under
versjonskontroll.
De manglende filene er filer som var i 1.0, men ikke i 1.1, og
på disse stiene kjører vi svn delete.
Helt til slutt, når current-arbeidskopien
kun inneholder koden for libcomplex 1.1, legger vi inn
forandringene vi gjorde for å få den til å se ut som den
gjør.
Nå inneholder current-grenen den nye
leverandørversjonen.
Vi merker den nye versjonen (på den samme måten vi tidligere
merket 1.0-versjonen) og fletter deretter forandringene mellom
merket for den forrige versjonen og den nye gjeldende versjonen
inn i hovedutviklingsgrenen.
$ cd arbeidskopier/calc
$ svn merge http://svn.example.com/repos/vendor/libcomplex/1.0 \
http://svn.example.com/repos/vendor/libcomplex/current \
libcomplex
… # Rydd opp i alle konfliktene mellom deres og våre forandringer
$ svn commit -m 'merging libcomplex-1.1 into the main branch'
…
I enkle sitasjoner vil den nye versjonen av tredjepartsdataene se ut som, fra et fil og katalog-syn, akkurat om den forrige versjonen. Ingen av filene i libcomplex vil være slettet, ha fått nytt navn eller blitt flyttet til andre plasseringer – den nye versionen vil bare inneholde tekstmessige forandringer i forhold til den forrige. I en perfekt verden ville våre forandringer legge seg inn i den nye versjonen uten antydning til komplikasjoner eller konflikter.
Men det er ikke alltid så enkelt, og faktisk er det ganske vanlig for kildekodefiler å bli flyttet rundt mellom programutgivelser. Dette kompliserer prosessen som går ut på å forsikre seg om at våre forandringer fortsatt er gyldige for den nye versjonen av koden, noe som kan ende med den situasjonen at vi manuelt må gjenopprette våre forandringer i den nye versjonen. Når Subversion vet om historien til en gitt kildefil – inkludert alle dens tidligere plasseringer – er prosessen med å flette inn den nye versjonen av biblioteket ganske enkel. Men vi er ansvarlig for å fortelle Subversion hvordan kildekodelayouten forandret seg fra leverandørversjon til leverandørversjon.
Vendor drops that contain more than a few deletes, additions and moves complicate the process of upgrading to each successive version of the third-party data. So Subversion supplies the svn_load_dirs.pl script to assist with this process. This script automates the importing steps we mentioned in the general vendor branch management procedure to make sure that mistakes are minimized. You will still be responsible for using the merge commands to merge the new versions of the third-party data into your main development branch, but svn_load_dirs.pl can help you more quickly and easily arrive at that stage.
In short, svn_load_dirs.pl is an enhancement to svn import that has several important characteristics:
It can be run at any point in time to bring an existing directory in the repository to exactly match an external directory, performing all the necessary adds and deletes, and optionally performing moves, too.
It takes care of complicated series of operations between which Subversion requires an intermediate commit—such as before renaming a file or directory twice.
It will optionally tag the newly imported directory.
It will optionally add arbitrary properties to files and directories that match a regular expression.
svn_load_dirs.pl takes three mandatory arguments. The first argument is the URL to the base Subversion directory to work in. This argument is followed by the URL—relative to the first argument—into which the current vendor drop will be imported. Finally, the third argument is the local directory to import. Using our previous example, a typical run of svn_load_dirs.pl might look like:
$ svn_load_dirs.pl http://svn.example.com/repos/vendor/libcomplex \
current \
/path/to/libcomplex-1.1
…
You can indicate that you'd like
svn_load_dirs.pl to tag the new vendor drop
by passing the -t command-line option and
specifying a tag name. This tag is another URL relative to
the first program argument.
$ svn_load_dirs.pl -t libcomplex-1.1 \
http://svn.example.com/repos/vendor/libcomplex \
current \
/path/to/libcomplex-1.1
…
When you run svn_load_dirs.pl, it
examines the contents of your existing “current”
vendor drop, and compares them with the proposed new vendor
drop. In the trivial case, there will be no files that are in
one version and not the other, and the script will perform the
new import without incident. If, however, there are
discrepancies in the file layouts between versions,
svn_load_dirs.pl will prompt you for how
you would like to resolve those differences. For example, you
will have the opportunity to tell the script that you know
that the file math.c in version 1.0 of
libcomplex was renamed to arithmetic.c in
libcomplex 1.1. Any discrepancies not explained by moves
are treated as regular additions and deletions.
The script also accepts a separate configuration file for
setting properties on files and directories matching a regular
expression that are added to the
repository. This configuration file is specified to
svn_load_dirs.pl using the
-p command-line option. Each line of the
configuration file is a whitespace-delimited set of two or
four values: a Perl-style regular expression to match the
added path against, a control keyword (either
break or cont), and then
optionally a property name and value.
\.png$ break svn:mime-type image/png \.jpe?g$ break svn:mime-type image/jpeg \.m3u$ cont svn:mime-type audio/x-mpegurl \.m3u$ break svn:eol-style LF .* break svn:eol-style native
For each added path, the configured property changes whose
regular expression matches the path are applied in order,
unless the control specification is break
(which means that no more property changes should be applied
to that path). If the control specification is
cont—an abbreviation for
continue—then matching will continue
with the next line of the configuration file.
Any whitespace in the regular expression, property name,
or property value must be surrounded by either single or
double quote characters. You can escape quote characters that
are not used for wrapping whitespace by preceding them with a
backslash (\) character. The backslash
escapes only quotes when parsing the configuration file, so do
not protect any other characters beyond what is necessary for
the regular expression.
Vi har gått gjennom en god del i dette kapittelet. Vi har diskutert konseptene rundt merker og grener, og demonstrert hvordan Subversion implementerer disse konseptene ved å kopiere kataloger med svn copy-kommandoen. Vi har vist hvordan svn merge brukes for å kopiere forandringer fra en gren til en annen, eller omgjøre feile forandringer. Vi har gått over bruken av svn switch for å lage arbeidskopier med blandede revisjoner. Og vi har snakket om hvordan man kan vedlikeholde organiseringen og levetiden til grener i et depot.
Husk mantraet til Subversion: Grener og merker er billige. Bruk dem så mye du vil!
[21] Subversion støtter ikke kopiering mellom forskjellige depot. Når du bruker URLer med svn copy eller svn move kan du bare kopiere elementer innenfor det samme depotet.
[22] I fremtiden planlegger Subversionprosjektet å bruke (eller finne opp) et utvidet patchformat som beskriver forandringer i trestruktur og egenskaper.
[23] Subversionprosjektet har imidlertid planer om å legge inn en svnadmin obliterate-kommando som vil ta seg av oppgaven med å permanent slette informasjon. I mellomtiden, se “svndumpfilter” for en mulig omvei om problemet.
[24] Fordi CVS ikke versjonerer trær, lager den et
Attic-område innenfor hver depotkatalog
som en måte å huske slettede filer på.
[25] Du kan imidlertid bruke svn
switch med --relocate-valget hvis
URL-en til serveren forandrer seg og du ikke vil forkaste
en eksisterende arbeidskopi.
Se svn switch-seksjonen i Kapittel 9, Subversion Complete Reference for mer informasjon og et eksempel.
[26] Og uten en eneste bug, selvfølgelig!
Innholdsfortegnelse
Subversiondepotet er den sentrale lagringsplassen for versjonerte data for ethvert antall prosjekter. Som sådan blir det en opplagt kandidat for all kjærlighet og oppmerksomhet en administrator kan tilby. Selv om depotet vanligvis er et element som krever lite vedlikehold, er det viktig å forstå hvordan du kan konfigurere og passe på det så potensielle problemer blir unngått, og aktuelle problemer løst på en trygg måte.
I dette kapittelet vil vi diskutere hvordan du kan opprette og konfigurere et Subversiondepot. Vi vil også snakke om depotvedlikehold, inkludert bruken av verktøyene svnlook og svnadmin (som følger med Subversion). Vi vil adressere vanlige spørsmål og feilgrep, og komme med noen forslag til hvordan du kan legge opp dataene i depotet.
Hvis du planlegger å aksessere et Subversiondepot bare i rollen som en bruker som har data under versjonskontroll (det vil si via en Subversionklient), kan du hoppe over hele dette kapitlet. Hvis du derimot er, eller vil bli, en administrator for et Subversiondepot,[27] bør du så absolutt følge med i dette kapittelet.
Før vi hopper inn i det mer generelle innen emnet depotadministrasjon, la oss definere videre hva et depot er. Hvordan ser det ut? Hvordan føles det? Vil det ha teen sin varm eller med is, søt, og med sitron? Som en administrator blir det forventet av deg at du må forstå sammensetningen av et depot både fra et logisk perspektiv – det å styre med hvordan data er representert i depotet – og fra et fysisk skrue-og-mutter-perspektiv – hvordan et depot ser ut og oppfører seg i sammenheng med verktøy som ikke hører med til Subversion-pakken. Den følgende seksjonen dekker noen av disse grunnleggende konseptene på et høyt nivå.
Konseptmessig sagt er et Subversiondepot en sekvens av trær. Hvert tre er et øyeblikksbilde av hvordan filene og katalogene så ut på et spesielt tidspunkt. Disse øyeblikksbildene er opprettet som et resultat av klientoperasjoner og blir kalt revisjoner.
Hver revisjon begynner livet som et transaksjonstre. Når du gjør en innlegging, bygger en klient en Subversiontransaksjon som avspeiler deres lokale forandringer (pluss eventuelle forandringer som er blitt lagt inn i tillegg til depotet siden begynnelsen av innleggingsprosessen), og instruerer deretter depotet om å lagre dette treet som det neste øyeblikksbildet i sekvensen. Hvis innleggingen lykkes, blir transaksjonen innlemmet i et nytt revisjonstre, og blir tildelt et nytt revisjonsnummer. Hvis innleggingen av en eller annen grunn ikke lykkes, blir transaksjonen ødelagt og klienten informeres om feilen.
Oppdateringer fungerer på en lignende måte. Klienten bygger et midlertidig transaksjonstre som avspeiler tilstanden til arbeidskopien. Depotet sammenligner deretter dette transaksjonstreet med revisjonstreet i den forespurte revisjonen (vanligvis det nyeste, eller “yngste” treet), og sender tilbake informasjon som forteller klienten om hvilke forandringer som er nødvendig for å forandre deres arbeidskopi til et replikat av det aktuelle revisjonstreet. Etter at oppdateringen er fullført, blir den midlertidige transaksjonen slettet.
Bruken av transaksjonstrær er den eneste måten å gjøre permanente forandringer til et depots versjonskontrollerte filsystem. Det er imidlertid viktig å forstå at livløpet til en transaksjon er komplett fleksible. I tilfellet med oppdateringer er transaksjoner midlertidige trær som blir øyeblikkelig ødelagt. I tilfellet med innlegginger blir transaksjoner transformert inn i permanente revisjoner (eller fjernet hvis innleggingen feiler). I tilfelle en generell feil eller programfeil oppstår, er det mulig at en transaksjon kan bli liggende igjen i depotet (uten å påvirke noe som helst, men tar opp diskplass).
I teorien vil kanskje hele arbeidsflytapplikasjoner en gang gi mer nøyaktig kontroll med levetiden til en transaksjon. Det er mulig å tenke seg et system som ved hver transaksjon beregnet på å bli en revisjon blir satt på venting etter at klienten er ferdig med å beskrive sine forandringer til depotet. Dette ville muliggjøre at hver ny innlegging kan bli sett over av noen andre, kanskje en manager eller ledende utvikler, som kan velge å forfremme transaksjonen til en revisjon eller avbryte den.
Transaksjoner og revisjoner i Subversiondepotet kan ha vedlagte egenskaper. Disse egenskapene er generiske “nøkkel-til-verdi”-mappinger, og blir vanligvis brukt til å lagre informasjon om treet som de er vedlagt. Navnene og verdiene til disse egenskapene er lagret i depotets filsystem, sammen med resten av dataene for treet.
Revisjons- og transaksjonsegenskaper er nyttige for å
assosiere informasjon sammen med et tre som ikke er spesifikt
relatert til filene og katalogene i dette treet ― den typen
informasjon som ikke er behandlet av arbeidskopier for klienten.
For eksempel, når en ny innleggingstransaksjon er opprettet i
depotet, legger Subversion en egenskap til denne transaksjonen
kalt svn:date – et tidsmerke som
representerer tidspunktet transaksjonen ble opprettet.
Når innleggingsprosessen er fullført, og transaksjonen blir
forfremmet til en permanent revisjon, har treet også fått en
egenskap for å lagre brukernavnet til revisjonens forfatter
(svn:author) og en egenskap for å lagre
loggmeldingen som hører til denne revisjonen
svn:log.
Revisjons- og transaksjonsegenskaper er
uversjonerte egenskaper – når de blir
modifisert blir den foregående verdien permanent forkastet.
Selv om revisjonstrær er uforanderlige, gjelder ikke dette
egenskapene som er vedlagt disse trærne.
Du kan legge til, fjerne, og modifisere revisjonsegenskaper til
enhver tid i fremtiden.
Hvis du legger inn en ny revisjon og senere finner ut at du la
inn feil informasjon eller skrivefeil i loggmeldingen, kan du
enkelt forandre verdien i svn:log-egenskapen
med en ny, rettet loggmelding.
I Subversion 1.1 er det to valg for å lagre data i et Subversiondepot. En depottype lagrer alt i en Berkeley DB-database; den andre typen lagrer data som ordinære “flate filer” i et tilpasset format. Fordi Subversionutviklere ofte referer til et depot som “det (versjonerte) filsystemet”, har de lagt seg til vanen med å refere til den sistnevnte typen depot som FSFS[28] – en versjonert filsystemimplementasjon som bruker det vanlige filsystemet til operativsystemet for å lagre data.
Når et depot er opprettet, må administratoren bestemme om Berkeley DB eller FSFS skal brukes. Det er fordeler og ulemper med begge to, som vi vil gå gjennom ganske snart. Ingen av de bakenforliggende depotene er mer “offisielle” enn andre, og programmer som aksesserer depotet er beskyttet fra denne implementasjonsdetaljen. Programmer har ingen formening om hvordan depotet lagrer data; de ser bare revisjons- og transaksjonstrær gjennom depotgrensesnittet.
Tabell 5.1, “Sammenligning av datalagring i depoter” inneholder en tabell som gir en oversikt over forskjellene mellom depoter av typen Berkeley DB og FSFS. De neste seksjonene går inn i detalj.
Tabell 5.1. Sammenligning av datalagring i depoter
| Funksjonalitet | Berkeley DB | FSFS |
|---|---|---|
| Følsom for avbrytelser | veldig; krasj og problemer med rettigheter kan etterlate databasen i en “fastkilt” (Engelsk: wedged) tilstand som krever journalførte gjenopprettingsprosedyrer. | ganske ufølsom. |
| Kan brukes fra et ikke-skrivbart medium | nei | ja |
| Plattformuavhengig lagring | nei | ja |
| Brukbar over nettverksfilsystem | nei | ja |
| Depotstørrelse | litt større | litt mindre |
| Skalerbarhet: Antall revisjonstrær | database; ingen problemer | ytelsen på noen eldre filsystemer blir dårligere med tusenvis av elementer i en katalog. |
| Skalerbarhet: Kataloger med mange filer | langsommere | raskere |
| Hastighet: Uthenting av nyeste kode | raskere | langsommere |
| Hastighet: Store innlegginger | langsommere, men arbeidet blir spredt ut over innleggingen | raskere, men forsinkelse i avslutningen kan forårsake tidsavbrudd for klienten. |
| Behandling av grupperettigheter | følsom for problemer med umask; det beste er om den blir aksessert av bare en bruker. | jobber seg rundt problemer med umask |
| Kodemodenhet | i bruk siden 2001 | i bruk siden 2004 |
I den innledende designfasen av Subversion bestemte utviklerne seg for å bruke Berkeley DB av diverse grunner, blant annet dens åpne lisens, transaksjonsstøtte, stabilitet, effektivitet, enkelt grensesnitt, trådsikkerhet, støtte for databasepekere og så videre.
Berkeley DB tilbyr reell støtte for transaksjoner – kanskje dens kraftigste funksjonalitet. Flere prosesser som aksesserer Subversiondepotene dine trenger ikke å tenke på faren ved å rote til hverandres data. Isolasjonen som transaksjonssystemet tilbyr er slik at for enhver operasjon ser Subversions depotkode et statisk bilde av en database – ikke en database som konstant forandres av en annen prosess – og kan foreta avgjørelser basert på dette bildet. Hvis avgjørelsen kommer i konflikt med det en annen prosess gjør, blir hele operasjonen rullet tilbake som om den aldri skjedde, og Subversion prøver forsiktig operasjonen mot et nytt, oppdatert (og fortsatt statisk) bilde av databasen.
En annen fin funksjonalitet med Berkeley DB er varme backuper (hot backups) – muligeten til å ta sikkerhetskopi av databasen uten å ta den ned. Vi vil diskutere hvordan du tar backup av depotet i “Sikkerhetskopi av depotet”, men fordelene med å kunne ta fullstendige fungerende kopier av depotene dine uten nedetid er innlysende.
Berkeley DB er også et veldig sikkert databasesystem. Subversion bruker Berkeley DBs loggefasiliteter, som betyr at databasen først lager en beskrivelse i loggfiler på disken om hva den er i ferd med å gjøre, og foretar deretter selve modifiseringen. Dette er for å forsikre seg om at i tilfelle noe går galt, kan databasesystemet hente tilbake et tidligere sjekkpunkt – en posisjon i loggfilene som den vet ikke er ødelagt – og “spille av” transaksjoner inntil dataene er gjenopprettet til en fungerende tilstand. Se “Bruken av diskplass” for mer angående loggfilene i Berkeley DB.
Men alle roser har torner, og derfor må vi være klar over noen kjente begrensninger i Berkeley DB. For det første er ikke Berkeley DB-miljøer portable. Du kan ikke bare kopiere et Subversiondepot som er laget på et UNIX-system til et Windows-system og forvente at det skal virke. Selv om mye av Berkely DB-formatet er arkitekturuavhengig, er det andre aspekter med miljøet som ikke er det. For det andre bruker Subersion Berkeley DB på en måte som ikke vil fungere i Windows 95/98 – hvis du må ha depotet på en Windowsmaskin, bruk Windows 2000 eller Windows XP. Legg heller aldri et Berkeley DB-depot på en nettverksdisk. Selv om Berkeley DB lover å oppføre seg korrekt på nettverksdisker som oppfyller spesielle kriterier, er det nesten ingen kjente nettverksdelinger som faktisk oppfyller alle disse spesifikasjonene.
Til sist, fordi Berkeley DB er et bibliotek linket direkte
inn i Subversion, er det mer sårbart for avbrudd enn et typisk
relasjonsdatabasesystem.
De fleste SQL-systemer har for eksempel en dedisert
serverprosess som fordeler all tilgang til tabeller.
Hvis et program som aksesserer databasen krasjer av en eller
annen grunn, oppdager daemonen som styrer databasen at
forbindelsen er brutt og ordner opp i eventuelt rot som blir
liggende igjen.
Og fordi databasedaemonen er den eneste prosessen som
aksesserer tabellene, trenger ikke applikasjoner å tenke på
rettighetskonflikter.
Disse tingene er imidlertid ikke tilfelle med Berkeley DB.
Subversion (og programmer som bruker Subversionbiblioteker)
aksesserer databasetabellene direkte, noe som betyr at et
programkrasj kan etterlate databasen i en midlertidig,
utilgjengelig tilstand.
Når dette skjer, må en administrator be Berkeley DB om
gjenoppretting til et sjekkpunkt, noe som er litt plagsomt.
Andre ting kan føre til at et depot “kiler seg
fast”
(“wedge”) sammen
med krasjede prosesser, som for eksempel programmer som kommer
i konflikt angående eierskap og tilgang til databasefilene.
Så mens et Berkeley DB-depot er ganske raskt og skalerbart,
fungerer det best når det kun blir brukt av én enkelt
serverprosess som kjører som én bruker – som for eksempel
Apaches httpd eller
svnserve (se Kapittel 6, Serverkonfigurasjon) – istedenfor å aksessere det med
mange forskjellige brukere via file:///
eller svn+ssh://-URLer.
Hvis et Berkeley DB-depot blir brukt direkte med flere
forskjellige brukere, pass på at du har lest “Støtte for flere metoder for
tilgang til depotet”.
I midten av 2004 ble et nytt lagringsformat for depotet laget, et som ikke bruker en database i det hele tatt. Et FSFS-depot lagrer et revisjonstre i en enkelt fil, og alle depotets revisjoner kan dermed finnes i en enkelt underkatalog full av nummererte filer. Transaksjoner blir opprettet i separate underkataloger. Når den er komplett, blir en enkelt transaksjonsfil opprettet og flyttet til revisjonskatalogen og garanterer dermed at innleggingen blir atomisk. Og fordi en revisjonsfil er permanent og uforanderlig, kan depotet også bli tatt backup av mens det er i bruk, akkurat som et Berkeley DB-depot.
Revisjonsfilformatet representerer en revisjons katalogstruktur, filinnhold og forskjeller i forhold til filer i andre revisjonstrær. Ulikt en Berkeley DB-database, er dette lagringsformatet portabelt mellom forskjellige operativsystemer og er ikke sensitiv ovenfor CPU-arkitektur. Fordi det ikke blir brukt journalfiler eller filer som bruker delt hukommelse, kan depotet trygt aksesseres via et nettverksfilsystem og bli utforsket i et skrivebeskyttet miljø. Mangelen på databaseoverhead betyr også at den samlede depotstørrelsen blir en del mindre.
FSFS har også forskjellige ytelseskarakteristikker. Når en katalog med mange filer legges inn, bruker FSFS en O(N)-algoritme for å legge til poster, mens Berkeley DB bruker en O(N^2)-algoritme for å skrive hele katalogen en gang til. På den annen side skriver FSFS den seneste versjonen av ei fil som en delta (forskjell) mot en tidligere versjon, noe som betyr at det å hente ut det seneste treet er litt langsommere enn å hente fullteksten lagret i en HEAD-revisjon i Berkeley DB. FSFS har også en lengre forsinkelse når en innlegging skal fullføres, noe som i ekstreme tilfeller kan føre til at klienter får et tidsavbrudd under venting på respons.
Men den viktigste forskjellen er FSFSs evne til å ikke bli “fastkilt” hvis noe går galt. Hvis en prosess som bruker en Berkeley DB-database får problemer med rettigheter eller plutselig krasjer, er ikke databasen brukbar før en administrator gjenoppretter den. Hvis det samme skjer med en prosess som bruker et FSFS-depot, blir ikke depotet påvirket i det hele tatt. I verste fall blir bare noen transaksjonsdata liggende igjen.
Det eneste virkelige argumentet mot FSFS er fartstiden det har hatt i forhold til Berkeley DB. Det er ikke like mye brukt og har ikke blitt stresstestet like mye, så derfor er mange av disse antakelsene om hastighet og skalerbarhet nettopp det: Antakelser, basert på gode gjetninger. I teorien lover den en lavere barriere å forsere for nye administratorer og er forventet å skape mindre problemer. I praksis vil bare tiden vise om dette stemmer.
Det å opprette et Subversiondepot er en utrolig enkel oppgave. svnadmin-verktøyet som følger med Subversion har en delkommando som gjør akkurat det. For å opprette et nytt depot, er det bare å kjøre:
$ svnadmin create /sti/til/depot
Dette oppretter et nytt depot i katalogen
/sti/til/depot.
Dette nye depotet starter livet ved revisjon 0, som er definert
til å bare innholde en rot på toppnivå (/) i
filsystemet.
Revisjon 0 har også en enkelt revisjonsegenskap satt
innledningsvis, svn:date, som er satt til
tidspunktet depotet ble opprettet.
I Subversion 1.2 blir et depot opprettet i FSFS-formatet som
standard (se “Datalagring i depotet”).
Formatet kan bli eksplisitt valgt med
--fs-type-valget:
$ svnadmin create --fs-type fsfs /sti/til/depot $ svnadmin create --fs-type bdb /sti/til/annet/depot
![]() | Advarsel |
|---|---|
Opprett ikke et Berkeley DB-depot på en nettverksdisk – det kan ikke eksistere på et fjerntliggende filsystem som NFS, AFS eller Windows SMB. Berkeley DB krever at det underliggende filsystemet har implementert streng POSIX låsesemantikk, og enda viktigere, muligheten til å mappe filer direkte inn i prosesshukommelsen. Nesten ingen nettverksfilsystemer tilbyr disse mulighetene. Hvis du forsøker å bruke Berkeley DB på en nettverksdisk, er resultatene uforutsigelige – du kan se mystiske feilmeldinger med en gang, eller det kan gå månedsvis før du oppdager at depotet i all stillhet blir herpa. Hvis du trenger flere datamaskiner for å aksessere depotet, lager du et FSFS-depot på nettverksdisken, ikke et Berkeley DB-depot. Eller enda bedre, sett opp en skikkelig serverprosess (som for eksempel Apache eller svnserve), legg depotet i et lokalt filsystem som serveren kan aksessere og gjør depotet tilgjengelig over et nettverk. Kapittel 6, Serverkonfigurasjon dekker denne prosessen i detalj. |
Du har kanskje lagt merke til at stiargumentet til
svnadmin bare var en vanlig filsystemsti og
ikke en URL lik det svn-klienten bruker når den
refererer til depot.
Både svnadmin og svnlook
ansees som serverside-verktøy – de blir brukt på maskinen hvor
depotet ligger for å undersøke og modifisere aspekter ved depotet,
og er faktisk ikke i stand til å utføre oppgaver over nettverket.
En vanlig feil som blir gjort av nybakte Subversionbrukere er å gi
URLer (til og med av typene “local” og
file:) til disse to programmene.
Så, etter at du har kjørt svnadmin create-kommandoen, har du et skinnende nytt depot i sin egen katalog. La oss ta en kikk på hva som egentlig er laget i denne katalogen.
$ ls depot conf/ dav/ db/ format hooks/ locks/ README.txt
Med unntak av filene README.txt og
format, er depotkatalogen en samling av
underkataloger.
Som i andre områder av Subversion-designet er modularitet gitt
stor oppmerksomhet, og hierarkisk organisering er foretrukket
framfor rotete kaos.
Her er en rask beskrivelse av alle elementene som du ser i den nye
depotkatalogen:
En katalog som inneholder konfigurasjonsfiler for depotet.
En katalog der Apache og mod_dav_svn lagrer sine husholdningsdata.
Der alle dine versjonerte data ligger. Denne katalogen er enten et Berkeley DB-miljø (full av databasetabeller og andre ting) eller et FSFS-miljø som inneholder revisjonsfiler.
Ei fil som inneholder en enkelt heltallsverdi som spesifiserer versjonsnummeret til depotlayouten.
En katalog full av maler for påhakningsskript (Engelsk: hooks) og påhakningsskriptene selv, når du har installert noen.
En katalog for Subversions låsedata, brukt for å følge tilganger til depotet.
Ei fil som bare informerer sine lesere om at de ser på et Subversiondepot.
Generelt sett skal du ikke fikle med depotet “for hånd”. svnadmin-verktøyet skal være nok til alle nødvendige forandringer i depotet, eller du kan se på tredjeparts verktøy (som Berkeley DBs verktøysamling) for å finpusse relevante delseksjoner av depotet. Noen unntak gjelder imidlertid, og disse skal vi gå gjennom her.
Et påhakningsskript (på engelsk kalt hooks) er et program som blir utløst av en hendelse i depotet, som for eksempel opprettelsen av en ny revisjon eller modifiseringen av en uversjonert egenskap. Hver påhakning blir gitt nok informasjon til å fortelle hva denne hendelsen er, hvilke mål den opererer på, og brukernavnet til personen som satte i gang hendelsen. Avhengig av påhakningens utdata eller returstatus, kan påhakningsprogrammet fortsette hendelsen, stoppe den, eller utsette den på en eller annen måte.
hooks-katalogen er, som standard, fylt
med maler for diverse depotpåhakninger.
$ ls depot/hooks/ post-commit.tmpl post-unlock.tmpl pre-revprop-change.tmpl post-lock.tmpl pre-commit.tmpl pre-unlock.tmpl post-revprop-change.tmpl pre-lock.tmpl start-commit.tmpl
Det er en mal for hver påhakning som Subversiondepotet
implementerer, og ved å undersøke innholdet til disse
eksempelskriptene, kan du se hva som fører til at hvert av disse
skriptene begynner å kjøre og hvilke data som blir levert til
dette skriptet.
Det som også ligger i mange av disse malene er eksempler på
hvordan man kan bruke skriptet i sammenheng med andre programmer
som følger med Subversion for å utføre vanlige, nyttige
oppgaver.
For å faktisk installere en påhakning som virker, trenger du
bare å plassere et kjørbart program eller skript i
depot/hooks-katalogen som kan bli kjørt
basert på navnet (som for eksempel
start-commit eller
post-commit) til påhakningen.
På Unix-plattformer betyr dette å legge inn et skript eller
program (som kan være et shellskript, et
Pythonprogram, et kompilert C-program, eller hva som helst
annet) som heter akkurat det samme som påhakningen.
Selvfølgelig, malfilene er der for mer enn bare
informasjonsverdien – den letteste måten å installere en
påhakning på Unixplattformer er å bare kopiere den riktige
malfila til ei ny fil som mangler
.tmpl-etternavnet, finpusse på innholdet, og
forsikre deg om at skriptet er kjørbart.
Men Windows bruker filetternavn til å avgjøre hvorvidt et
program er kjørbart eller ikke, så da må du legge inn et program
der hovednavnet er navnet på påhakningen, og der etternavnet er
en av de spesielle etternavnene som Windows kjenner igjen som
kjørbare, for eksempel .exe eller
.com for programmer, og
.bat for batchfiler.
![]() | Tips |
|---|---|
Av sikkerhetsgrunner kjører Subversion påhakningsskript
med et tomt miljø (environment) – det betyr, ingen
miljøvariabler er satt i det hele tatt, ikke engang
|
Det er lagt inn ni påhakninger i Subversiondepotet:
start-commitDenne blir kjørt allerede før innleggingstransaksjonen er opprettet. Det blir vanligvis brukt til å avgjøre om brukeren har innleggingsprivilegier i det hele tatt. Depotet leverer to argumenter til dette programmet: Stien til depotet, og brukernavnet som forsøker seg på innleggingen. Hvis programmet returnerer en verdi som ikke er null, blir denne innleggingen stoppet allerede før transaksjonen blir laget. Hvis påhakningen skriver data til standardfeil, vil det bli sendt tilbake til klienten.
pre-commitDette blir kjørt når transaksjonen er komplett, men før den er lagt inn. Vanligvis blir denne påhakningen brukt til å beskytte mot innlegginger som er forbudt på grunn av innhold eller beliggenhet (for eksempel kan serveren kreve at alle innlegginger til en spesiell gren inneholder et billettnummer fra feildatabasen, eller at den innkommende loggmeldingen ikke er tom). Depotet leverer to argumenter til dette programmet: Stien til depotet, og navnet på transaksjonen som legges inn. Hvis programmet returnerer en verdi som ikke er null, avbrytes innleggingen og transaksjonen blir fjernet. Hvis programmet skriver data til stderr, vil dette bli sendt tilbake til klienten.
Subversiondistribusjonen inneholder noen
aksesskontrollskript (i
tools/hook-scripts-katalogen i
kildekodefiltreet til Subversion) som kan bli kalt fra
pre-commit for å kunne legge inn
finjustert kontroll for skriveaksess.
En annen mulighet er å bruke Apache-modulen
mod_authz_svn som gir både lese- og
skrivekontroll i individuelle kataloger (se “Adgangskontroll på katalognivå”).
I en framtidig versjon av Subversion planlegger vi å legge
inn lister for aksesskontroll (ACL) direkte inn i
filsystemet.
post-commitDette blir kjørt etter at transaksjonen er lagt inn, og en ny revisjon er opprettet. De fleste vil bruke denne påhakningen til å sende ut beskrivende eposter om innleggingen eller for å ta backup av depotet. Depotet gir to argumenter til dette programmet: Stien til depotet, og det nye revisjonsnummeret som ble opprettet. Returverdien fra programmet blir ignorert.
Subversiondistribusjonen inneholder skriptene
mailer.py og
commit-email.pl (i
tools/hook-scripts/-katalogen i
Subversiontreet) som kan bli brukt til å sende epost med
(og/eller legge til en loggfil) en beskrivelse av en
mottatt innlegging.
Denne mailen inneholder en liste over de stiene som ble
forandret, loggmeldingen som er vedlagt innleggingen,
forfatteren og datoen til innleggingen, sammen med en GNU
diff-visning av forandringene som ble gjort til diverse
filer som del av innleggingen.
Et annet nyttig verktøy som følger med Subversion er
skriptet hot-backup.py (i
tools/backup/-katalogen i
kildekodetreet til Subversion).
Dette skriptet tar “varme” backuper av
Subversiondepotet (en funksjonalitet støttet av den
bakenforliggende Berkeley DB-databasen), og kan bli brukt
til å foreta en øyeblikkslagring av depotet mellom hver
innlegging for arkiverings- eller sikkerhetsformål.
pre-revprop-changeFordi Subversions revisjonsegenskaper ikke er
versjonerte, vil det å forandre slike egenskaper (for
eksempel svn:log-egenskapen som
inneholder loggmeldingen for innleggingen) overskrive den
forrige verdien for alltid.
Siden data kan gå tapt her, har Subversion denne
påhakningen (og dens motstykke
post-revprop-change) så
depotadministratorer kan lage logger med forandringer i
disse elementene ved bruk av eksterne hjelpemidler hvis de
vil det.
Som en forholdsregel mot å miste uversjonerte data, vil
ikke Subversionklienter få lov til å forandre
revisjonsegenskaper i det hele tatt hvis ikke denne
påhakningen er aktivisert i depotet ditt.
Denne påhakningen kjører like før en slik modifisering blir lagt inn i depotet. Depotet leverer fire argumenter til denne påhakningen: Stien til depotet, revisjonen som egenskapen som skal forandres befinner seg på, det autentiserte brukernavnet til personen som gjør forandringen, og navnet på selve egenskapen.
post-revprop-changeSom nevnt tidligere, er denne påhakningen motstykket
til pre-revprop-change-påhakningen.
For paranoiaens skyld vil faktisk ikke dette skriptet
kjøre uten at
pre-revprop-change-skriptet finnes.
Når begge disse skriptene finnes, kjører
post-revprop-change-påhakningen like
etter at en revisjonsegenskap er blitt forandret, og blir
vanligvis brukt til å sende en epost som inneholder den
nye verdien til den forandrede egenskapen.
Depotet leverer fire argumenter til denne påhakningen:
Stien til depotet, revisjonen som egenskapen tilhører, det
godkjente brukernavnet til personen som gjør forandringen,
og navnet på selve egenskapen.
Subversiondistribusjonen inkluderer skriptet
propchange-email.pl (i
tools/hook-scripts/-katalogen i
Subversions kildekodetre) som kan bli brukt til å sende
epost med (og/eller legge til en loggfil) detaljene om en
egenskapsforandring.
Denne eposten inneholder revisjonen og navnet til den
forandrede egenskapen, brukeren som gjorde forandringen,
og den nye verdien til egenskapen.
pre-lockDenne påhakningen kjøres hver gang noen prøver å låse ei fil. Den kan bli brukt til å forby låser i det hele tatt, eller å definere et mer komplekst regelsett som spesifiserer nøyaktig hvilke brukere som får lov til å låse spesielle stier. Hvis påhakningen finner en allerede eksisterende lås, kan den også bestemme om en bruker har lov til å “stjele” den eksisterende låsen. Depotet leverer tre argumenter til påhakningen: Stien til depotet, stien som blir låst, og navnet på brukeren som prøver å utføre låsingen. Hvis programmet returnerer en verdi som ikke er null, blir låseprosessen avbrutt og alt som blir skrevet til standard feil blir sendt tilbake til klienten.
post-lockDenne påhakningen kjører etter at en sti er låst. Den låste stien sendes til påhakningens standard inn, og påhakningen mottar også to argumenter: Stien til depotet og brukeren som utførte låsingen. Skriptet kan dermed sende melding via epost eller logge hendelsen på den måten som er bestemt. Fordi låsingen allerede har skjedd, blir utdataene fra påhakningen ignorert.
pre-unlockDenne påhakningen kjøres når noen prøver å fjerne en lås på ei fil. Den kan brukes til å lage regler som spesifiserer hvilke brukere som har lov til å låse opp spesielle stier. Den er spesielt viktig for å avgjøre regler om bryting av låser. Hvis bruker A låser ei fil, får bruker B lov til å bryte låsen? Hva hvis låsen er mer enn en uke gammel? Denne typen ting kan bli bestemt og gjennomført av påhakningen. Depotet leverer tre argumenter til påhakningen: Stien til depotet, stien som låses opp, og navnet på brukeren som prøver å fjerne låsen. Hvis programmet returnerer en verdi som ikke er null, blir opplåsingsprosessen avbrutt og alt som blir skrevet til standardfeil leveres til klienten.
post-unlockDenne påhakningen kjøres etter at en sti er låst opp. Stien som er låst opp sendes til skriptets standard inn, og det mottar også to argumenter: Stien til depotet og brukeren som fjernet låsen. Påhakningen kan dermed sende epost eller logge hendelsen på den måten som er valgt. Fordi fjerningen av låsen allerede har skjedd, blir utdataene fra påhakningen ignorert.
![]() | Advarsel |
|---|---|
Ikke forsøk å forandre transaksjonen ved å bruke
påhakningsskript.
Et vanlig eksempel på dette ville være å automatisk sette
egenskaper som Istedenfor å forsøke å modifisere transaksjonen, er det
mye bedre å sjekke transaksjonen i
|
Subversion vil forsøke å kjøre påhakningsskriptene som den samme brukeren som eier prosessen som aksesserer Subversiondepotet. I de fleste tilfeller blir depotet aksessert via Apache HTTP-serveren og mod_dav_svn, så denne brukeren er den samme som Apache kjører som. Selve påhakningene må bli satt opp med rettigheter på operativsystemnivå som tillater denne brukeren å kjøre dem. Dette betyr også at enhver fil eller program (inkludert selve Subversiondepotet) aksessert direkte eller indirekte av påhakningen vil bli aksessert som den samme brukeren. Med andre ord, vær obs på mulig rettighetsproblematikk som kan forhindre påhakningsskriptet fra å utføre de oppgavene du har satt det til.
Et Berkeley DB-miljø er en innkapsling av en eller flere databaser, loggfiler, regionfiler og konfigurasjonsfiler. Berkeley DB-miljøet har sitt eget sett med konfigurasjonsverdier for ting som antallet databaselåser som er tillatt brukt på en gang, maksimal størrelse på journalloggfiler og så videre. Subversions filsystemkode velger i tillegg standardverdier for noen av konfigurasjonsvalgene i Berkeley DB.
Folkene i Sleepycat (produsentene av Berkeley DB) innser at
forskjellige databaser har forskjellige krav, og de har derfor
lagt inn en mekanisme for å overstyre mange av
konfigurasjonsverdiene til Berkeley DB under kjøring.
Berkeley sjekker at fila DB_CONFIG finnes i
hver miljøkatalog, og leser valgene som er i denne fila for bruk
med akkurat dette Berkeley-miljøet.
Berkeley-konfigurasjonsfila for ditt depot ligger i
miljøkatalogen db i
depot/db/DB_CONFIG.
Subversion oppretter selv denne fila når den lager resten av
depotet.
Fila inneholder innledningsvis noen standardvalg sammen med
pekere til dokumentasjonen til Berkeley DB som ligger på nettet
så du kan lese om hva disse valgene gjør.
Du har selvfølgelig også muligheten til å legge til alle valg
som Berkeley DB støtter til DB_CONFIG-fila.
Pass bare på at mens Subversion aldri prøver å lese eller forstå
innholdet i fila og bruker ingen av valgene i den, vil du unngå
å gjøre forandringer i konfigurasjonen som får Berkeley DB seg
til å oppføre seg annerledes enn det Subversionkoden forventer.
I tillegg vil ikke forandringer gjort i
DB_CONFIG aktiviseres før du gjenoppretter
databasemiljøet (ved bruk av svnadmin
recover).
Å vedlikeholde et Subversiondepot kan være en skremmende oppgave, mest på grunn av kompleksiteten som er innebygget i systemer med en bakenforliggende database. Å utføre oppgaven godt handler om å kjenne verktøyene – hva de er, når de skal brukes, og hvordan de brukes. Denne seksjonen vil introdusere deg for administrasjonsverktøy som følger med Subversion, og hvordan få dem til å utføre oppgaver som flytting av depot, oppgraderinger, sikkerhetskopiering og opprydding.
Subversion har en håndfull programmer som er nyttige til å opprette, inspisere, modifisere og reparere depotet ditt. La oss se litt nærmere på hvert av disse verktøyene. Etterpå vil vi gå raskt over noen av de programmene som er inkludert i Berkeley DB-distribusjonen som tilbyr funksjonalitet spesifikk til databasedelen i depotet som ikke Subversions egne verktøy tar seg av.
svnlook er et verktøy som følger med Subversion. Det er beregnet for å utforske de forskjellige revisjonene og transaksjonene i et depot. Ingen deler av dette programmet prøver å forandre depotet – det er et “bare lese”-verktøy. svnlook blir vanligvis brukt av påhakningsskriptene i depotet for å rapportere forandringene som er i ferd med å bli lagt inn (i tilfellet med pre-commit-påhakningen) eller det som nettopp ble lagt inn (i tilfellet med post-commit-påhakningen) i depotet. En depotadministrator kan bruke dette verktøyet for diagnoseformål.
svnlook har en likefrem syntaks:
$ svnlook help
general usage: svnlook SUBCOMMAND REPOS_PATH [ARGS & OPTIONS ...]
Note: any subcommand which takes the '--revision' and '--transaction'
options will, if invoked without one of those options, act on
the repository's youngest revision.
Type "svnlook help <subcommand>" for help on a specific subcommand.
…
Nesten hver eneste av delkommandoene til
svnlook kan operere på enten et revisjons-
eller transaksjonstre og skrive ut informasjon om selve treet
eller hvordan det skiller seg ut fra den forrige revisjonen i
depotet.
Du bruker valgene --revision og
--transaction for å spesifisere henholdsvis
hvilken revisjon eller transaksjon som skal undersøkes.
Legg merke til at mens revisjonsnumre fremstår som naturlige
tall, er transaksjonsnavn alfanumeriske strenger.
Husk at filsystemet bare tillater gjennomgang av transaksjoner
som enda ikke er lagt inn (transaksjoner som ikke har
resultert i en ny revisjon).
De fleste depot vil ikke ha noen slike transaksjoner, fordi
transaksjoner vanligvis enten er lagt inn (som diskvalifiserer
dem fra visning) eller avbrutt og fjernet.
Hvis både valgene --revision og
--transaction mangler, vil
svnlook undersøke den yngste (eller
“HEAD”) revisjonen i depotet.
Så de følgende to kommandoene gjør akkurat det samme når 19 er
den yngste revisjonen i depotet som ligger i
/sti/til/depot:
$ svnlook info /sti/til/depot $ svnlook info /sti/til/depot --revision 19
Det eneste unntaket fra disse reglene om delkommandoer er
svnlook youngest-delkommandoen, som ikke
tar noen valg, og bare skriver ut nummeret for
HEAD-revisjonen.
$ svnlook youngest /sti/til/depot 19
Utdataene fra svnlook er designet for å
være lesbare både for menneske og maskin.
Som et eksempel kan vi ta utdataene fra delkommandoen
info:
$ svnlook info /sti/til/depot sally 2002-11-04 09:29:13 -0600 (Mon, 04 Nov 2002) 27 La til det vanlige greske treet.
Utdataene fra info-delkommandoen er
definert som:
Forfatteren, etterfulgt av linjeslutt.
Datoen, etterfulgt av linjeslutt.
Antallet tegn i loggmeldingen, etterfulgt av linjeslutt.
Selve loggmeldingen, etterfulgt av linjeslutt.
Disse utdataene er leselige for det menneskelige øye, det vil si at elementer som datoen blir vist som tekst istedenfor noe mer obskurt (som antall nanosekunder siden isbilen kjørte forbi). Men disse utdataene er også lesbare for en datamaskin – fordi loggmeldingen kan inneholde flere linjer og ha ubegrenset lengde, skriver svnlook lengden på denne meldingen før selve meldingen. Dette tillater skript og andre programmer som bruker denne kommandoen å gjøre intelligente valg angående loggmeldingen, som hvor mye hukommelse som skal reserveres for meldingen, eller i det minste hvor mange bytes som må hoppes over når disse utdataene ikke er den siste datadelen i strømmen.
En annen vanlig bruk av svnlook er å
faktisk vise innholdet i et revisjons- eller transaksjonstre.
Kommandoen svnlook tree viser katalogene og
filene i det forespurte treet.
Hvis du angir valget --show-ids, vil den også
vise noderevisjons-ID for hver av disse stiene (som vanligvis
er mer nyttige for utviklere enn vanlige brukere).
$ svnlook tree /sti/til/depot --show-ids
/ <0.0.1>
A/ <2.0.1>
B/ <4.0.1>
lambda <5.0.1>
E/ <6.0.1>
alpha <7.0.1>
beta <8.0.1>
F/ <9.0.1>
mu <3.0.1>
C/ <a.0.1>
D/ <b.0.1>
gamma <c.0.1>
G/ <d.0.1>
pi <e.0.1>
rho <f.0.1>
tau <g.0.1>
H/ <h.0.1>
chi <i.0.1>
omega <k.0.1>
psi <j.0.1>
iota <1.0.1>
Når du har sett på layouten for kataloger og filer i treet ditt, kan du bruke kommandoer som svnlook cat, svnlook propget og svnlook proplist for å grave dypere i detaljene om disse filene og katalogene.
svnlook kan utføre en rekke andre forespørsler, vise delsett av biter av informasjon som vi har nevnt tidligere, rapportere hvilke stier som ble modifisert i en gitt revisjon eller transaksjon, vise tekst- og egenskapsforskjeller gjort med filer og kataloger og så videre. Det følgende er en rask beskrivelse av den nåværende listen med delkommandoer som svnlook aksepterer, og utdataene fra disse delkommandoene:
authorSkriv treets forfatter.
catSkriv innholdet av ei fil i treet.
changedList alle filer og kataloger som forandret seg i treet.
dateSkriv dato og klokkeslett for treet.
diffLag unified diff (patch) av forandrede filer.
dirs-changedList katalogene i treet som enten selv forandret seg, eller der en fil under den forandret seg.
historyVis interessante punkter i historien for en versjonert sti (steder der modifiseringer eller kopieringer skjedde).
infoSkriv treets forfatter, tidspunkt, antall tegn i loggmeldingen og selve loggmeldingen.
lockHvis en sti er låst, beskriv låseattributtene.
logVis loggmeldingen for treet.
propgetSkriv verdien for en egenskap på en sti i treet.
proplistSkriv navnene og verdiene til egenskapene satt på stier i treet.
treeSkriv en liste over treet, med valgfri visning av filsystemets noderevisions-IDer som er assosiert med hver sti.
uuidSkriv depotets UUID – Universal Unique IDentifier.
youngestSkriv det yngste revisjonsnummeret.
Programmet svnadmin er depotadministratorens beste venn. Ved siden av å gi muligheten til å opprette Subversiondepoter, tillater dette programmet deg å utføre flere vedlikeholdsoperasjoner på disse depotene. Syntaksen på svnadmin er lik den i svnlook:
$ svnadmin help general usage: svnadmin SUBCOMMAND REPOS_PATH [ARGS & OPTIONS ...] Type "svnadmin help <subcommand>" for help on a specific subcommand. Available subcommands: create deltify dump help (?, h) …
Vi har allerede nevnt delkommandoen
create i svnadmin (se
“Opprettelse og konfigurering av depotet”).
De fleste andre vil vi gå grundigere gjennom senere i dette
kapitlet.
Nå nøyer vi oss med å ta en rask kikk på hva de forskjellige
delkommandoene tilbyr.
createOpprett et nytt Subversiondepot.
deltifyGå over et spesifisert revisjonsområde og utfør
forløper-deltifisering på stiene som forandret seg i
disse revisjonene.
Hvis ingen revisjoner er spesifisert, vil denne
kommandoen rett og slett bare deltifisere
HEAD-revisjonen.
dumpDump innholdet av depotet, begrenset av et spesifisert sett av revisjoner, i et portabelt dumpformat.
hotcopyLag en “varm kopi” av et depot. Du kan kjøre denne kommandoen til enhver tid og lage en trygg kopi av depotet, selv om andre prosesser bruker depotet.
list-dblogs(Bare Berkeley DB-depot.) List stiene for Berkeley DB-loggfiler assosiert med depotet. Denne listen inkluderer alle loggfiler ― de som fortsatt brukes av Subversion, sammen med de som ikke lenger er i bruk.
list-unused-dblogs(Bare Berkeley DB-depot.) List stiene for Berkeley DB-loggfiler assosiert med, men ikke lenger brukt av depotet. Du kan trygt fjerne disse loggfilene fra depotet og muligens arkivere dem for senere bruk i tilfelle du en gang får bruk for katastrofe-gjenoppretting av depotet.
loadLast et sett revisjoner inn i et depot fra en strøm
av data som bruker det samme portable dumpformatet
generert av
dump-delkommandoen.
lslocksList og beskriv enhver lås som eksisterer i depotet.
lstxnsList navnene på Subversiontransaksjonene som ikke er lagt inn, men som eksisterer i depotet.
recoverUtfør gjenoppretting på et depot som trenger det, vanligvis etter at en fatal feil er oppstått som forhindret en prosess fra å lukke kommunikasjonen med depotet på en skikkelig måte.
rmlocksFjern låser fra listede stier betingelsesløst.
rmtxnsFjern Subversiontransaksjoner fra depotet på en
renslig måte (kan bruke utdataene fra
lstxns-delkommandoen).
setlogErstatt den nåværende verdien i
svn:log-egenskapen (loggmelding) for
en angitt revisjon i depotet med en ny verdi.
verifyVerifiser innholdet i et depot. Dette inkluderer blant annet sjekk av kontrollsummer til de versjonerte dataene som er lagret i depotet.
Siden Subversion lagrer alt i et skjult databasesystem, er det å prøve på manuelle forandringer ikke spesielt lurt, for ikke å si vanskelig. Og når dataene er lagret i depotet, har ikke Subversion noen enkel måte å fjerne disse dataene.[29] Men det er ikke til å komme forbi at det er noen ganger du vil manipulere historien til depotet ditt. Det kan være at du vil fjerne alle spor etter ei fil som ble lagt til ved en ulykke (og som av en eller annen grunn ikke skal være der). Eller du har kanskje flere prosjekter som deler et enkelt depot, og du bestemmer deg for å dele dem opp i sine egne depoter. For å utføre oppgaver som dette, trenger administratorer en mer håndterlig og formbar representasjon av dataene i deres egne depot – dumpformatet for Subversiondepot.
Dumpformatet for Subversiondepot er en representasjon av forandringene som du har gjort i dine versjonerte data over tid, i et menneskelig lesbart format. Du bruker kommandoen svnadmin dump for å generere dumpdataene og svnadmin load for å legge disse dataene inn i et nytt depot (se “Flytte et depot”). Den fine tingen med det menneskelesbare dumpformatet er at du kan inspisere og modifisere det hvis du er forsiktig. Selvfølgelig, bakdelen er at hvis du har to år med depotaktivitet pakket inn i en stor dumpfil, vil det ta deg lang, lang tid å manuelt inspisere og modifisere den.
Selv om det ikke vil være det vanligste verktøyet til bruk for depotadministratoren, gir svndumpfilter en veldig spesiell type nyttig funksjonalitet – muligheten til å raskt og enkelt modifisere disse dumpdataene ved å fungere som et stibasert filter. Du gir ganske enkelt programmet en liste over stier som du vil beholde, eller en liste med stier som du vil fjerne, og sender deretter dumpdataene fra depotet via et rør gjennom dette filteret. Resultatet er en modifisert strøm av dumpdata som kun inneholder de versjonerte stiene som du (eksplisitt eller implisitt) ba om.
Syntaksen for svndumpfilter er som følger:
$ svndumpfilter help general usage: svndumpfilter SUBCOMMAND [ARGS & OPTIONS ...] Type "svndumpfilter help <subcommand>" for help on a specific subcommand. Available subcommands: exclude include help (?, h)
Her er det bare to interessante delkommandoer. De gir deg valget mellom eksplisitt eller implisitt inkludering av stier i strømmen:
excludeFiltrer bort et sett med stier fra dumpdatastrømmen.
includeTillat bare de angitte stiene å slippe gjennom dumpdatastrømmen.
La oss se på et realistisk eksempel på hvordan du vil bruke dette programmet. Vi diskuterer en annen plass (se “Velge en depot-layout”) prosessen med å bestemme hvordan dataene i depotene dine skal legges opp – om du vil bruke ett depot for hvert prosjekt eller kombinere dem, hvordan du arrangerer ting innenfor depotet og så videre. Men noen ganger etter at nye revisjoner begynner å komme inn, tenker du på nytt over layouten og vil gjøre noen forandringer. En vanlig forandring er å bestemme seg for å flytte flere prosjekter som deler et enkelt depot inn i separate depot for hvert prosjekt.
Vårt hypotetiske depot inneholder tre prosjekter:
calc,
calendar og spreadsheet.
De har levd ved siden av hverandre som følger:
/
calc/
trunk/
branches/
tags/
calendar/
trunk/
branches/
tags/
spreadsheet/
trunk/
branches/
tags/
For å få disse tre prosjektene inn i deres egne depot, dumper vi først hele depotet:
$ svnadmin dump /path/to/repos > depot-dumpfil * Dumped revision 0. * Dumped revision 1. * Dumped revision 2. * Dumped revision 3. … $
Så kjører vi denne dumpfila gjennom filteret og for hver gang inkluderer vi bare en av katalogene på toppnivå, noe som resulterer i tre nye dumpfiler:
$ cat depot-dumpfil | svndumpfilter include calc > calc-dumpfil … $ cat depot-dumpfil | svndumpfilter include calendar > cal-dumpfil … $ cat depot-dumpfil | svndumpfilter include spreadsheet > ss-dumpfil … $
På dette punktet må du ta en avgjørelse.
Hver av dumpfilene fine vil lage et gyldig depot, men vil
gjenskape stiene nøyaktig som de var i det opprinnelige
depotet.
Dette betyr at selv om du vil ha et depot kun for
calc-prosjektet, vil dette depotet fortsatt
ha en toppkatalog kalt calc.
Hvis du vil at katalogene trunk,
tags og branches
skal være i roten av depotet, vil du kanskje ønske å redigere
dumpfilene og forandre Node-path og
Node-copyfrom-path i headerne så de ikke
lengre inneholder denne calc/-komponenten
i stien.
I tillegg ønsker du å fjerne seksjonen i dumpdataene som
oppretter calc-katalogen.
Det vil se ut omtrent som dette:
Node-path: calc Node-action: add Node-kind: dir Content-length: 0
![]() | Advarsel |
|---|---|
Hvis du planlegger å redigere dumpfila manuelt for å fjerne en toppkatalog, vær sikker på at tekstbehandleren din ikke er satt til å automatisk konvertere linjeslutt til det lokale formatet (det vil si \r\n til \n). Dette vil føre til at innholdet ikke vil samsvare med metadataene og dumpfila vil dermed bli ubrukelig. |
Alt som gjenstår nå er å opprette dine tre nye depot og laste hver dumpfil inn i det riktige depotet:
$ svnadmin create calc; svnadmin load calc < calc-dumpfil
<<< Started new transaction, based on original revision 1
* adding path : Makefile ... done.
* adding path : button.c ... done.
…
$ svnadmin create calendar; svnadmin load calendar < cal-dumpfil
<<< Started new transaction, based on original revision 1
* adding path : Makefile ... done.
* adding path : cal.c ... done.
…
$ svnadmin create spreadsheet; svnadmin load spreadsheet < ss-dumpfil
<<< Started new transaction, based on original revision 1
* adding path : Makefile ... done.
* adding path : ss.c ... done.
…
$
Begge delkommandoene til svndumpfilter godtar valg for å bestemme hva de skal gjøre med “tomme” revisjoner. Hvis en gitt revisjon bare inneholdt forandringer i stier som ble filtrert bort kan denne revisjonen som nå er tom bli betraktet som uinteressant eller til og med uønsket. Så for å gi brukeren kontroll over hva som skal gjøres med disse revisjonene, har svndumpfilter disse kommandolinjevalgene:
--drop-empty-revsIkke lag tomme revisjoner i det hele tatt – utelat dem.
--renumber-revsHvis tomme revisjoner er droppet (ved bruk av valget
--drop-empty-revs), forandres
revisjonsnumrene på de gjenværende revisjonene så det
ikke blir mellomrom i den numeriske sekvensen.
--preserve-revpropsHvis tomme revisjoner ikke droppes, ta vare på revisjonsegenskaper (loggmelding, forfatter, dato, egendefinerte egenskaper og så videre) for disse tomme revisjonene. Tomme revisjoner vil ellers bare inneholde det originale tidspunktet og en generert loggmelding som indikerer at denne revisjonen ble tømt av svndumpfilter.
Selv om svndumpfilter kan være veldig
nyttig og sparer masse tid, er det dessverre et par ting å
passe på.
For det første er dette verktøyet overfølsom for sti-semantikk.
Legg merke til om stiene i dumpfila er spesifisert med eller
uten skråstreker i starten.
Dette vil du se i Node-path og
Node-copyfrom-path i headerne.
… Node-path: spreadsheet/Makefile …
Hvis stiene har innledende skråstreker, skal du også ha innledende skråstreker i stiene som du leverer til svndumpfilter include og svndumpfilter exclude (og hvis de ikke har det, skal du ikke gjøre det). Videre, hvis dumpfila di har inkonsekvent bruk av innledende skråstreker av en eller annen grunn,[30] bør du normalisere disse stiene så de alle enten har eller mangler innledende skråstreker.
I tillegg kan kopierte stier gi deg litt trøbbel. Subversion støtter kopioperasjoner i depotet, der en ny sti blir opprettet ved å kopiere en allerede eksisterende sti. Det er mulig at på et eller annet punkt i livsløpet til depotet blir ei fil eller katalog kopiert fra en plass som svndumpfilter utelater, til en plass som programmet inkluderer. For å gjøre dumpdataene selvforsynt, må svndumpfilter vise tilleggingen av den nye stien – inkludert innholdet av alle filer opprettet av kopieringen – og ikke vise denne tilleggingen som en kopiering fra en kilde som ikke eksisterer i den filtrerte dumpdatastrømmen. Men fordi dumpformatet i Subversion bare viser hva som ble forandret i hver revisjon, kan det være at innholdet i kilden for kopien ikke er tilgjengelig. Hvis du har mistanke om at du har denslags kopier i depotet ditt, vil du kanskje tenke gjennom valget ditt av inkluderte/utelatte stier på nytt.
Hvis du bruker et Berkeley DB-depot, vil alle strukturer
og data være i et sett med databasetabeller i katalogen
db i depotet ditt.
Denne underkatalogen er en vanlig Berkeley DB miljøkatalog, og
kan derfor bli brukt i forbindelse med alle Berkeley
databaseverktøy (du kan se dokumentasjonen for disse
verktøyene på Sleepycats hjemmeside, http://www.sleepycat.com/).
For daglig Subversionbruk er disse verktøyene unødvendige. Mesteparten av funksjonaliteten som vanligvis er nødvendig for Subversiondepot er blitt duplisert i svnadmin-verktøyet. For eksempel, svnadmin list-unused-dblogs og svnadmin list-dblogs utfører en del av hva Berkeley-kommandoen db_archive gjør, og svnadmin recover gjenspeiler de vanlige bruksmåter for db_recover-programmet.
Det er fortsatt noen få Berkeley DB-programmer som du kan finne nyttige. Programmene db_dump og db_load skriver og leser henholdsvis et tilpasset filformat som beskriver nøkler og verdier i en Berkeley DB-database. Siden Berkeley DB-databaser ikke er portable på tvers av maskinarkitekturer, er dette formatet en nyttig måte å overføre disse databasene fra maskin til maskin, uavhengig av arkitektur eller operativsystem. I tillegg kan programmet db_stat gi deg nyttig informasjon om statusen til Berkeley DB-miljøet, inkludert detaljert statistikk om undersystemer som tar seg av låsing og lagring.
Subversiondepotet ditt vil vanligvis kreve veldig lite tilsyn når det er konfigurert sånn som du vil ha det. Det er imidlertid enkelte ganger en administrator må trå til med manuell assistanse. Verktøyet svnadmin gir nyttig funksjonalitet for å hjelpe deg med å utføre oppgaver som:
modifisere loggmeldinger
fjerne døde transaksjoner
gjenopprette “fastkilte” depoter, og
flytte depotinnholdet til et annet depot.
Den delkommandoen som kanskje blir brukt mest i
svnadmin er setlog.
Når en transaksjon er lagt inn i depotet og forfremmet til en
revisjon, blir den beskrivende loggmeldingen assosiert med denne
nye revisjonen lagret som en uversjonert egenskap vedlagt selve
revisjonen.
Med andre ord, depotet husker bare den seneste verdien til
egenskapen, og forkaster tidligere versjoner.
Noen ganger skjer det at det blir feil i en loggmelding (en
skrivefeil eller kanskje noe feilinformasjon).
Hvis depotet er satt opp (ved bruk av påhakningene
pre-rev-prop-change og
post-revprop-change; se “Påhakningsskript”) til å akseptere
forandringer i denne loggmeldingen etter at innleggingen er
ferdig, kan brukeren “fikse” loggmeldingen fra en annen maskin ved bruk av
svn-programmets
propset-kommando (se Kapittel 9, Subversion Complete Reference).
Men fordi det her er en potensiell sjanse for å miste
informasjon for alltid, er standard oppsett på et
Subversiondepot å ikke godta forandringer i uversjonerte
egenskaper – unntatt av en administrator.
Hvis en loggmelding må forandres av en administrator, kan
dette gjøres ved å bruke svnadmin setlog.
Denne kommandoen forandrer loggmeldingen
(svn:log-egenskapen) på en gitt revisjoen i
et depot, ved å lese den nye verdien fra ei fil.
$ echo "Her er den nye, korrekte loggmeldingen" > nylogg.txt $ svnadmin setlog mittdepot nylogg.txt -r 388
Kommandoen svnadmin setlog alene er
fortsatt bundet av den samme beskyttelsen mot å modifisere
uversjonerte egenskaper som en klient på en annen maskin er –
påhakningsskriptene pre-revprop-change og
post-revprop-change blir fortsatt aktivisert
og må derfor settes opp til å godta denne typen forandringer.
Men en administrator kan gå rundt denne beskyttelsen ved å angi
valget --bypass-hooks til svnadmin
setlog-kommandoen.
![]() | Advarsel |
|---|---|
Men husk at ved å omgå påhakningsskriptene unngår du også utføring av ting som meldinger via email om forandringer i egenskaper, backupsystemer som følger med på egenskapsforandringer og så videre. Med andre ord, vær meget forsiktig med hva du forandrer og hvordan du forandrer det. |
En annen vanlig måte å bruke svnadmin på er å spørre depotet om utestående – muligens døde – Subversiontransaksjoner. Hvis en innlegging feiler, blir transaksjonen vanligvis ryddet opp i. Det vil si, selve transaksjonen blir fjernet fra depotet, og alle dataene assosiert med (og bare med) denne transaksjonen blir fjernet i samme slengen. Men enkelte ganger kan det skje en feil på en måte som gjør at oppryddingen av transaksjonen aldri skjer. Dette kan skje av flere grunner: Kanskje ble klientoperasjonen uelegant avsluttet av brukeren, eller en nettverksfeil kan ha skjedd midt i en operasjon og så videre. Uansett grunnen, døde transaksjoner kan skje. De gjør ingen reell skade utenom å okkupere en liten del av diskplassen, og en pertentlig administrator vil nok ønske å fjerne dem.
Du kan bruke svnadmins
lstxns-kommando for å liste navnene på
utestående transaksjoner som ligger i depotet for
øyeblikket.
$ svnadmin lstxns mittdepot 19 3a1 a45 $
Hvert element i de resulterende utdataene kan deretter bli
brukt sammen med svnlook (og dens valg
--transaction) for å finne ut hvem som lagde
transaksjonen, når den ble laget, hvilke typer forandringer som
ble gjort i transaksjonen – med andre ord, om transaksjonen er
eller ikke er en trygg kandidat for sletting!
Hvis den er det, kan transaksjonens navn leveres til
svnadmin rmtxns som vil utføre fjerning av
transaksjonen.
rmtxns-delkommandoen kan faktisk motta
dataene direkte fra det som lstxns
genererer!
$ svnadmin rmtxns mittdepot `svnadmin lstxns mittdepot` $
Hvis du bruker disse to delkommandoene som dette, bør du vurdere å gjøre depotet midlertidig utilgjengelig for klienter. På denne måten kan ingen starte på en legitim transaksjon før du starter på opprenskningen. Det følgende er en skallsnutt som raskt kan generere informasjon om hver utestående transaksjon i depotet ditt:
Eksempel 5.1. txn-info.sh (Rapporterer utestående transaksjoner)
#!/bin/sh
### Generer informasjon om alle utestående transaksjoner i et
### Subversiondepot.
REPOS="${1}"
if [ "x$REPOS" = x ] ; then
echo "bruk: $0 STI_TIL_DEPOT"
exit
fi
for TXN in `svnadmin lstxns ${REPOS}`; do
echo "---[ Transaksjon ${TXN} ]-------------------------------------------"
svnlook info "${REPOS}" --transaction "${TXN}"
done
Du kan kjøre det foregående skriptet ved å bruke /sti/til/txn-info.sh /sti/til/depot. Utdataene er hovedsaklig flere biter av utdataene fra svnlook info som er satt sammen (se “svnlook”), og vil se ut som noe i denne retningen:
$ txn-info.sh mittdepot ---[ Transaksjon 19 ]------------------------------------------- sally 2001-09-04 11:57:19 -0500 (Tue, 04 Sep 2001) 0 ---[ Transaksjon 3a1 ]------------------------------------------- harry 2001-09-10 16:50:30 -0500 (Mon, 10 Sep 2001) 39 Prøver å legge inn over et skrøpelig nettverk. ---[ Transaksjon a45 ]------------------------------------------- sally 2001-09-12 11:09:28 -0500 (Wed, 12 Sep 2001) 0 $
En transaksjon som har vært avbrutt over lengre tid representerer vanligvis en feilet eller avbrutt innlegging. Tidspunktet til en transaksjon kan bidra med interessant informasjon – for eksempel, hvor sannsynlig er det at en operasjon som begynte for ni måneder siden fortsatt er aktiv?
Kort sagt er det ikke nødvendig å foreta ukloke beslutninger angående fjerning av transaksjoner. Forskjellige kilder til informasjon – inkludert Apaches feil- og adgangslogg, loggene med gjennomførte Subversioninnlegginger og så videre – kan bli tatt med i beslutningsprosessen. Til sist kan administratoren rett og slett kommunisere med eieren av en tilsynelatende død transaksjon (via email, for eksempel) for å fastslå om transaksjonen faktisk er i en zombietilstand.
Selv om prisen på datalagring har stupt de siste årene, er bruken av diskplass fortsatt noe administratorer må tenke på hvis de vil versjonere store mengder data. Hver eneste ekstra byte konsumert av det aktive depotet er en byte som må tas backup av utenfor maskinen, kanskje flere ganger som del av roterende backuper. Hvis du bruker et Berkeley DB-depot, er den primære lagringsmekanismen et komplekst databasesystem og det er nyttig å vite hvilke deler av dataene som må forbli på den aktive siten, hvilke som det må tas sikkerhetskopi av, og hva som trygt kan fjernes. Denne seksjonen handler spesifikt om Berkeley DB, FSFS-depot har ingen ekstra data som kan ryddes opp i eller brukes om igjen.
Inntil nylig var de største synderne når det gjelder diskplass som brukes av Subversiondepoter loggfilene der Berkeley DB utfører skrivingen på forhånd før de aktuelle databasefilene modifiseres. Disse filene inneholder alle operasjonene som blir utført når databasen skal forandres fra en tilstand til en annen – mens databasefilene til enhver tid avspeiler en viss tilstand, inneholder loggfilene alle de mange småforandringene langs veien mellom tilstander. Derfor kan de øke i omfang ganske fort.
Heldigvis, fra og med 4.2-versjonen av Berkeley DB har
databasemiljøet muligheten til å fjerne sine egne ubrukte
loggfiler uten eksterne prosedyrer.
Ethvert depot som er laget med en svnadmin
som er kompilert mot Berkeley DB 4.2 eller større vil bli
konfigurert for denne automatiske slettingen av loggfiler.
Hvis du ikke vil ha denne funksjonaliteten aktivisert, kan du
ganske enkelt angi valget --bdb-log-keep til
svnadmin create-kommandoen.
Hvis du glemmer å gjøre dette, eller forandrer mening på et
senere tidspunkt, kan du redigere fila
DB_CONFIG som ligger i katalogen
db i depotet.
Du kommenterer bort linjen som inneholder direktivet
set_flags DB_LOG_AUTOREMOVE og kjører
deretter svnadmin recover på depotet ditt
for å aktivisere forandringene i konfigrasjonen.
Se “Konfigurasjon av Berkeley DB” for mer
informasjon om databasekonfigurasjon.
Uten noen form for automatisk sletting av loggfiler på plass, vil loggfilene samle seg opp etterhvert som du bruker depotet. Dette er faktisk en form for God Ting i databasesystemet – du vil være i stand til å gjenopprette hele databasen ved bruk av loggfilene alene, så disse filene kan være nyttige for gjenoppretting etter en katastrofe. Men vanligvis vil du arkivere loggfilene som ikke lenger er i bruk av Berkeley DB og deretter fjerne dem fra disken for å spare plass. Bruk kommandoen svnadmin list-unused-dblogs for å liste ut de ubrukte loggfilene:
$ svnadmin list-unused-dblogs /sti/til/depot /sti/til/depot/log.0000000031 /sti/til/depot/log.0000000032 /sti/til/depot/log.0000000033 $ svnadmin list-unused-dblogs /sti/til/depot | xargs rm ## diskplassen er frigjort!
For å holde størrelsen på depotet så liten som mulig, bruker Subversion deltifisering (eller “deltifisert lagring”) inne i selve depotet. Deltifisering involverer å kode representasjonen av en porsjon data som en samling av forskjeller mot en annen porsjon data. Hvis de to delene med data er veldig like, resulterer denne deltifiseringen i sparing av lagringsplass for den deltifiserte porsjonen – istedenfor å ta opp plass lik størrelsen av de originale dataene, brukes nå nok plass for å si: “Jeg ser ut akkurat som de dataene der borte, unntatt de følgende forandringene”. Mer spesifikt, hver gang en ny versjon av ei fil blir lagt inn i depotet, koder Subversion den forrige versjonen (egentlig flere tidligere versjoner) som en delta mot den nye versjonen. Resultatet er at mesteparten av depotdataene som har en tendens til å forandre seg i størrelse – innholdet av versjonerte filer – blir lagret med en mye mindre datamengde enn den originale “fulltekst”-representasjonen av disse dataene.
![]() | Notat |
|---|---|
Fordi alle Subversions depotdata som blir deltifisert blir lagret i en enkelt Berkeley DB-databasefil, vil ikke nødvendigvis det å redusere størrelsen på de lagrede verdiene nødvendigvis redusere størrelsen på selve databasefila. Berkeley DB vil imidlertid ha interne poster med ubrukte områder i databasefila, og vil bruke disse områdene først før den øker størrelsen på databasefila. Så selv om deltifisering ikke medfører øyeblikkelig sparing av diskplass, kan det redusere fremtidig økning i databasestørrelsen ganske drastisk. |
Som nevnt i “Berkeley DB”, kan et Berkeley DB-depot noen ganger bli etterlatt i en frosset tilstand hvis det ikke blir skikkelig lukket. Når dette skjer, må en administrator rulle databasen tilbake i funksjonell stand.
For å beskytte dataene i depotet ditt, bruker Berkeley DB en låsemekanisme. Denne mekanismen forsikrer at deler av databasen ikke blir oppdatert samtidig av flere sin aksesserer databasen, og at hver prosess ser dataene i den korrekte tilstanden som da disse dataene ble lest fra databasen. Når en prosess må forandre noe i databasen sjekker den først om det eksisterer en lås på måldataene. Hvis dataene ikke er låst, låser denne prosessen dataene, gjør forandringene som den ønsker å gjøre, og låser deretter opp dataene. Andre prosesser blir tvunget til å vente inntil denne låsen er fjernet før de får lov til å fortsette med tilgangen til denne seksjonen av databasen. (Dette har ingenting å gjøre med de låsene som du, brukeren, kan bruke på versjonerte filer i depotet; se Three meanings of “lock” for mer informasjon.)
Under bruk av Subversiondepotet kan fatale feil (som å gå tom for diskplass eller tilgjengelig hukommelse) eller avbrytelser forhindre en prosess fra å fjerne låsene som den har plassert i databasen. Resultatet er at det bakenforliggende databasesystemet blir “fastkilt”. Når dette skjer, vil ethvert forsøk på å aksessere depotet henge til evig tid (siden hver ny tilgang vil vente på at en lås skal forsvinne – noe som ikke kommer til å skje).
For det første, hvis dette skjer med depotet ditt, ingen panikk. Berkeley DB-filsystemet benytter seg av databasetransaksjoner og sjekkpunkter og forhåndsskriver journaler for å forsikre at bare de mest katastrofale hendelser[31] kan ødelegge databasen permanent. En tilstrekkelig paranoid depotadministrator vil ta sikkerhetskopier av depotet til en annen maskin på en eller annen måte, men ikke få systemadministratoren din til å hente tilbake det som er på backuptapen helt enda.
For det andre, bruk den følgende oppskriften for å forsøke å “fjerne fastkilingen” av depotet:
Sjekk at det ikker er noen prosesser som aksesserer (eller forsøker å få tilgang) til depotet. For depot på nettverket betyr dette at Apache HTTP også må kjøres ned.
Bli brukeren som eier og vedlikeholder depotet. Dette er viktig fordi en gjenoppretting av depotet med gal bruker kan forandre rettighetene på filene i depotet så det fortsatt vil være utilgjengelig selv etter at det er “reparert”.
Kjør kommandoen svnadmin recover /sti/til/depot. Du vil nå se noe i likhet med dette:
Repository lock acquired. Please wait; recovering the repository may take some time... Recovery completed. The latest repos revision is 19.
Denne kommandoen kan ta flere minutter å fullføre.
Start Subversionserveren på nytt.
Denne prosedyren reparerer nesten ethvert tilfelle av låste
databaser.
Pass på at du kjører denne kommandoen som brukeren som eier og
vedlikeholder databasen, ikke bare som root.
Deler av gjenopprettingsprosessen kan føre til at diverse
databasefiler blir opprettet på nytt (delte områder av
hukommelsen, for eksempel).
Gjenoppretting som root vil lage disse filene
som om de er eid av root, noe som betyr at
til og med etter at du setter opp forbindelsen til databasen
igjen, klarer ikke vanlige brukere å få tilgang til den.
Hvis den nevnte prosedyren av en eller annen grunn ikke
klarer å reparere depotet ditt, skal du gjøre to ting.
Først flytter du det ødelagte depotet ut av veien og legger inn
den siste sikkerhetskopien av den.
Deretter, send en email til Subversionbrukerlisten (på
<users@subversion.tigris.org>) der du beskriver
problemet i detalj.
Dataintegritet har ekstremt høy prioritet for
Subversionutviklerne.
Et Subversionfilsystem har dataene sine spredt over flere
databasetabeller på en måte som generelt bare er forstått av (og
som bare har interesse for) selve Subversionutviklerne.
Ting kan imidlertid skje som gjør at alt eller litt av disse
dataene må samles i et enkeltstående og portabelt
“flatt” filformat.
Subversion har en slik mekanisme, implementert som et par
svnadmin-delkommandoer:
dump og load.
Den vanligste grunnen til å dumpe og laste et Subversiondepot er på grunn av forandringer i selve Subversion. Etterhvert som Subversion modnes, skjer det noen ganger at det blir gjort forandringer i det bakenforliggende databaseoppsettet som fører til at Subversion blir inkompatibel med tidligere versjoner av depotet. Andre grunner for dumping og lasting kan være å flytte et Berkeley DB-depot til et annet operativsystem eller en annen CPU-arkitektur, eller for å bytte mellom Berkeley DB- og FSFS-lagringsformat. Den anbefalte måten å gjøre dette på er relativt enkel:
Bruk din nåværende versjon av svnadmin, dump depotene dine til dumpfiler.
Oppgrader til den nye versjonen av Subversion.
Flytt de gamle depotene ut av veien, og opprett nye på plassen deres ved å bruke den nye versjonen av svnadmin.
Så laster du dumpfilene inn i de respektive nyopprettede depotene ved å bruke den nye versjonen av svnadmin.
Pass på å kopiere alle egne tilpasninger fra de gamle
depotene til de nye, inkludert
DB_CONFIG-filer og påhakningsskript.
Det kan være lurt å lese hva som er forandret i den nye
versjonen av Subversion for å se om det er noen forandringer
der som gjør at du må gjøre forandringer i
påhakningsskriptene eller konfigurasjonen.
Hvis flytteprosessen gjør depotet ditt tilgjengelig på en annen URL (for eksempel flyttet til en annen maskin eller blir aksessert på en annen måte), bør du be alle brukerne dine om å kjøre svn switch --relocate på sine eksisterende arbeidskopier. Se svn switch.
svnadmin dump vil generere utdata med en
rekke depotrevisjoner som er i Subversions spesiallagde
filsystemdumpformat.
Dumpformatet sendes til standard ut-strømmen
(stdout), mens informative meldinger sendes
til standardfeil-strømmen (stderr).
Dette gjør at du kan omdirigere utdatastrømmen til ei fil mens
du holder øye med statusen i terminalvinduet.
$ svnlook youngest mittdepot 26 $ svnadmin dump mittdepot > dumpfil * Dumped revision 0. * Dumped revision 1. * Dumped revision 2. … * Dumped revision 25. * Dumped revision 26.
Når denne prosessen er ferdig, vil du ha en enkelt fil
(dumpfil i det foregående eksempelet) som
inneholder alle dataene som er lagret i depotet ditt i det
forespurte området med revisjoner.
Legg merke til at svnadmin dump leser
revisjonstrær fra depotet akkurat som enhver annen leseprosess
ville gjort det (svn checkout, for eksempel),
så det er trygt å kjøre denne kommandoen når som helst.
Den andre delkommandoen i dette radarparet, svnadmin load, tolker inndatastrømmen som en Subversiondumpfil og “spiller av” disse dumpede revisjonene inn i måldepotet for denne operasjonen. Den gir også informativ feedback, denne gangen ved å bruke standard ut-strømmen:
$ svnadmin load newrepos < dumpfile
<<< Started new txn, based on original revision 1
* adding path : A ... done.
* adding path : A/B ... done.
…
------- Committed new rev 1 (loaded from original rev 1) >>>
<<< Started new txn, based on original revision 2
* editing path : A/mu ... done.
* editing path : A/D/G/rho ... done.
------- Committed new rev 2 (loaded from original rev 2) >>>
…
<<< Started new txn, based on original revision 25
* editing path : A/D/gamma ... done.
------- Committed new rev 25 (loaded from original rev 25) >>>
<<< Started new txn, based on original revision 26
* adding path : A/Z/zeta ... done.
* editing path : A/mu ... done.
------- Committed new rev 26 (loaded from original rev 26) >>>
Resultatet av en lasting er at nye revisjoner blir lagt til
et depot – det samme som skjer når du legger inn revisjoner i
depotet fra en vanlig Subversionklient.
Og akkurat som i en innlegging kan du bruke påhakningsskript for
å utføre oppgaver før og etter hver av innleggingene som blir
gjort under en lasteprosess.
Ved å angi valgene --use-pre-commit-hook og
--use-post-commit-hook sammen med
svnadmin load, kan du instruere Subversion
til å utføre henholdsvis pre-commit- og post-commit-skriptene
for hver lastede revisjon.
Du kan for eksempel bruke disse til å forsikre deg om at de
lastede revisjonene går gjennom de samme valideringsstegene som
vanlige innlegginger går gjennom.
Selvfølgelig bør du bruke disse valgene med forsiktighet – hvis
post-commit-påhakningen sender epost til en postliste for hver
ny revisjon, vil du nok ikke sende ut hundre- eller tusenvis av
innleggingsmeldinger i rask rekkefølge til denne listen for hver
eneste lastede revisjon!
Du kan lese mer om bruken av påhakningsskript i “Påhakningsskript”.
Legg merke til at fordi svnadmin bruker standard inn- og standard ut-strømmer for depotdumpen og lasteprosessen, kan folk som vet hva de driver på med prøve på ting som dette (kanskje til og med bruke forskjellige versjoner av svnadmin på hver side av røret):
$ svnadmin create nyttdepot $ svnadmin dump mittdepot | svnadmin load nyttdepot
Vanligvis vil dumpfila bli ganske stor – mye
større enn selve depotet.
Dette er fordi hver eneste versjon av hver fil blir representert
som fulltekst i dumpfila.
Dette er den raskeste og enkleste oppførselen, og fin hvis du
sender dumpdataene gjennom et rør direkte til en annen prosess
(som for eksempel et pakkeprogram, filterprogram eller inn i en
lasteprosess).
Men hvis du lager en dumpfil som er ment for langtidslagring,
vil du nok ønske å spare diskplass ved å bruke valget
--deltas.
Med dette valget vil etterfølgende revisjoner av filer bli
generert som pakkede, binære forskjeller – akkurat som
filrevisjoner er lagret i et depot.
Dette valget er langsommere, men resulterer i en dumpfil mer lik
størrelsen til det originale depotet.
Vi nevnte tidligere at svnadmin dump
sender en rekke revisjoner til standard ut.
Bruk --revision-valget for å spesifisere en
enkelt revisjon som skal dumpes, eller et område med revisjoner.
Hvis du utelater dette valget, vil alle eksisterende
depotrevisjoner bli dumpet.
$ svnadmin dump mittdepot --revision 23 > rev-23.dumpfil $ svnadmin dump mittdepot --revision 100:200 > rev-100-200.dumpfil
Når Subversion dumper hver ny revisjon, lagres akkurat nok informasjon til at et framtidig lasteprogram kan gjenskape denne revisjonen basert på en tidligere revisjon. Med andre ord, for enhver gitt revisjon i dumpfila vil bare de elementene som ble forandret i den revisjonen havne i dumpen. Det eneste unntaket fra denne regelen er den første revisjonen som blir dumpet med den nåværende svnadmin dump-kommandoen.
Vanligvis vil Subversion ikke uttrykke den første dumpede revisjonen bare som forskjeller som skal legges til den forrige revisjonen. En grunn til dette er at det ikke er noen tidligere revisjon i dumpfila! For det andre kan ikke Subversion vite tilstanden til depotet som dumpdataene vil bli lastet inn i (hvis det i det hele tatt noen gang blir et). For å garantere at utdataene etter hver kjøring av svnadmin dump er selvforsynt, er den første dumpede revisjonen vanligvis en full representasjon av hver katalog, fil og egenskap i denne revisjonen i depotet.
Denne standardoppførselen kan du imidlertid forandre.
Hvis du legger til --incremental-valget når du
dumper depotet ditt, vil svnadmin sammenligne
den første dumpede revisjonen mot den forrige revisjonen i
depotet, på den samme måten som den behandler alle andre
revisjoner som blir dumpet.
Programmet vil deretter generere den første revisjonen nøyaktig
som det gjør med resten av revisjonene i dumpområdet – det tar
bare med de forandringene som oppsto i den revisjonen.
Fordelen med dette er at du kan lage flere små dumpfiler som kan
bli lastet etter hverandre istedenfor en stor fil.
Dette gjøres på denne måten:
$ svnadmin dump mittdepot --revision 0:1000 > dumpfil1 $ svnadmin dump mittdepot --revision 1001:2000 --incremental > dumpfil2 $ svnadmin dump mittdepot --revision 2001:3000 --incremental > dumpfil3
Disse dumpfilene kan så bli lastet inn i et nytt depot med den følgende kommandosekvensen:
$ svnadmin load nyttdepot < dumpfil1 $ svnadmin load nyttdepot < dumpfil2 $ svnadmin load nyttdepot < dumpfil3
Et annet lurt triks du kan utføre med dette
--incremental-valget går ut å legge til en
rekke revisjoner til en eksisterende dumpfil.
For eksempel kan du ha en
post-commit-påhakning som rett og slett
legger til depotdumpen av den spesifikke revisjonen som utførte
påhakningsskriptet.
Eller du kan ha et skript som kjøres om natten for å legge til
dumpdata for alle revisjonene som ble lagt til depotet siden
forrige gang skriptet ble kjørt.
Brukt på denne måten kan dump- og
load-kommandoen til
svnadmin tilby verdifull hjelp med å ta
sikkerhetskopi av forandringer i depotet over tid i tilfelle
systemkrasj eller andre katastrofer.
Dumpformatet kan også brukes til å flette innholdet av flere
forskjellige depot inn i et enkelt depot.
Ved å bruke valget --parent-dir når du kjører
svnadmin load, kan du spesifisere en ny
virtuell rotkatalog for lasteprosessen.
Dette betyr at hvis du har dumpfiler for tre depoter, la oss si
tekst-dumpfil,
kalender-dumpfil og
regneark-dumpfil, kan du først opprette et
nytt depot som skal inneholde alle sammen:
$ svnadmin create /sti/til/prosjekter $
Deretter, lag nye kataloger i depotet som vil “pakke inn” innholdet av hver av de tre foregående depotene:
$ svn mkdir -m "Opprettet røtter for prosjektene" \
file:///sti/til/prosjekter/tekst \
file:///sti/til/prosjekter/kalender \
file:///sti/til/prosjekter/regneark
Committed revision 1.
$
Til sist, last de individuelle dumpfilene inn i deres respektive plasseringer i det nye depotet:
$ svnadmin load /sti/til/prosjekter --parent-dir tekst < tekst-dumpfil … $ svnadmin load /sti/til/prosjekter --parent-dir kalender < kalender-dumpfil … $ svnadmin load /sti/til/prosjekter --parent-dir regneark < regneark-dumpfil … $
Vi vil nevne en siste måte å bruke depotdumpformatet i Subversion på – konvertering fra en annen lagringsmekanisme eller et annen versjonskontrollsystem. Fordi dumpfilformatet for det meste er lesbart for mennesker,[32] skulle det være relativt enkelt å beskrive generelle sett med forandringer – der hver av dem blir behandlet som en ny revisjon – ved å bruke dette filformatet. Faktisk bruker programmet cvs2svn (se “Konvertere et depot fra CVS til Subversion”) dumpformatet for å representere innholdet i et CVS-depot så dette innholdet kan bli kopiert inn i et Subversiondepot.
Tross utallige forbedringer i teknologien siden den moderne datamaskinen ble født, gjør fortsatt en ting seg sterkt gjeldende – noen ganger går ting forferdelig galt. Strømbrudd, nettverksbrudd, ødelagte minnebrikker og krasjede harddisker er bare en forsmak på ondskapen som Skjebnen er troende til å øse over selv den mest samvittighetsfulle administrator. Vi lander derfor på et meget viktig tema – hvordan du tar sikkerhetskopier av depotdataene dine.
Det er generelt sett to backupmetoder som er tilgjengelig for administratorer av Subversiondepot – inkrementell og fullstendig. Vi diskuterte i en tidligere seksjon i dette kapittelet hvordan svnadmin dump --incremental kan brukes til å utføre en inkrementell backup (se “Flytte et depot”). Essensen i idéen er at på det punktet kopien lages blir kun forandringene i depotet siden forrige backup tatt med.
En fullstendig kopi av depotet er bokstavelig talt en duplisering av hele depotkatalogen (som inkluderer enten en Berkeley-database eller et FSFS-miljø). Hvis du nå tar en kopi uten å midlertidig sperre all tilgang til depotet, vil det å bare ta en rekursiv katalogkopi kanskje føre til at det blir feil i kopien, siden noen kan skrive til databasen på samme tidspunkt.
I tilfellet med Berkeley DB beskriver dokumenter laget av
Sleepycat en viss rekkefølge databasefiler kan kopieres i som
vil garantere en gyldig sikkerhetskopi.
Og en lignende rekkefølge eksisterer for FSFS-data.
Enda bedre, du trenger ikke selv å implementere disse
algoritmene fordi det er allerede gjort av Subversionutviklerne.
Skriptet hot-backup.py ligger i
tools/backup/-katalogen i den distribuerte
Subversionkildekoden.
Ved å gi en depotsti og en backupplassering til
hot-backup.py – som egentlig bare er en mer
intelligent innpakning rundt svnadmin
hotcopy-kommandoen – vil den utføre de nødvendige
stegene for å ta backup av det aktive depotet ditt – uten at du
må sperre den offentlige tilgangen – og vil deretter rense bort
de døde Berkeleyloggfilene fra det aktive depotet.
Selv om du også har en inkrementell backup, vil du
sannsynligvis ville kjøre dette programmet med jevne mellomrom.
For eksempel vil du kanskje vurdere å legge til
hot-backup.py til en automatisk
programkjøring (som cron på Unix-systemer).
Eller, hvis du foretrekker finjusterte backupløsninger, kan du
sette post-commit-skriptet til å kalle
hot-backup.py (se “Påhakningsskript”), som vil lage en ny
kopi av depotet for hver ny revisjon som er opprettet.
Bare legg det følgende inn i
hook/post-commit-skriptet i katalogen til
det aktive depotet:
(cd /sti/til/påhakningsskript; \
./hot-backup.py ${REPOS} /sti/til/sikkerhetskopier &)
Den resulterende backupen er et fullstendig fungerende Subversiondepot som du kan legge inn som en erstatning for det aktive depotet i tilfelle noe skulle gå forferdelig galt.
Det er fordeler med begge backupmetodene. Den letteste er helt klart å ta en full sikkerhetskopi, som alltid vil resultere i en fullstendig funksjonell duplikat av depotet ditt. Dette betyr igjen at hvis noe stygt skulle skje med det aktive depotet, kan du hente det tilbake fra sikkerhetskopien med en enkel rekursiv katalogkopiering. Uheldigvis, hvis du har flere kopier av depotet, vil disse fullstendige kopiene spise opp like mye diskplass som det aktive depotet.
Inkrementelle backuper som bruker depotdumpformatet er utmerket å ha for hånden hvis oppbygningen av databasen forandrer seg mellom versjonene av selve Subversion. Siden en komplett depotdump og depotlasting vanligvis er nødvendig for å oppgradere depotet ditt til det nye formatet, er det veldig enkelt å allerede ha halvparten av denne prosessen (dumpdelen) overstått. Uheldigvis tar opprettelsen av – og gjenoppretting fra – inkrementelle backuper lengre tid, fordi hver innlegging enten blir spilt av inn i dumpfila eller depotet.
I begge disse backupscenariene må depotadminstratorer være oppmerksom på hvordan forandringer i uversjonerte revisjonsegenskaper påvirker sikkerhetskopiene. Siden disse forandringene ikke selv lager nye revisjoner, vil de ikke aktivisere post-commit-påhakninger, og kanskje heller ikke aktivisere pre-revprop-change- og post-revprop-change-skriptene.[33] Og siden du kan forandre revisjonsegenskaper som går på tvers av den kronolgiske rekkefølgen – du kan forandre enhver egenskap for en revisjon når som helst – vil en inkrementell backup av de seneste få revisjonene kanskje ikke fange opp en egenskapsforandring i en revisjon som ble inkludert som del av en tidligere backup.
Vanligvis vil bare den helt paranoide trenge å ta backup av hele depotet, la oss si, hver gang en innlegging skjer. Imidlertid, hvis vi antar at et gitt depot har noen ganske finjusterte mekanismer på plass (som utsending av epost for hver innlegging), vil en varm backup av databasen være noe som en depotadministrator vil ønske å inkludere som del av en nattlig systembackup. For de fleste depot vil arkiverte eposter alene gi nok informasjon som gjenopprettelseskilde, i hvert fall for de siste få innleggingene. Men det er dine data – beskytt dem i den grad du vil.
Ofte er den beste tilnærmingsmåten til kopier av depotet delt. Du kan sette opp kombinasjoner av fullstendige og inkrementelle backuper, pluss et arkiv med innleggingsmeldinger. Subversionutviklerne tar for eksempel backup av kildekodedepotet etter hver ny revisjon som opprettes, og tar vare på et arkiv med alle eposter som varsler om innlegginger og forandringer i revisjoner og egenskaper. Løsningen din kan være noe lignende, men bør tilpasses dine behov og følge den fine linjen mellom bekvemmelighet og paranoia. Og selv om dette ikke vil redde hardwaren din fra Skjebnens jernhånd, vil det helt sikkert hjelpe deg å komme deg på fote igjen etter harde tider som dette.
Når depotet ditt er opprettet og konfigurert, er alt som
gjenstår å begynne å bruke det.
Hvis du har en samling med eksisterende data som er klar til å bli
plassert under versjonskontroll, vil du mest sannsynlig bruke
svn-klientens
import-delkommando for å gjøre dette.
Men før du setter i gang bør du gå nøye gjennom planene for
depotet på lang sikt.
I denne seksjonen vil vi gi noen råd om hvordan du planlegger
oppbygningen av depotet, og hvordan du får lagt inn dataene dine i
dette oppsettet.
Selv om Subversion lar deg flytte rundt versjonerte filer og kataloger uten tap av informasjon, kan det forstyrre arbeidsflyten til de som ofte aksesserer depotet og forventer at ting er på sine respektive plasser. Prøv å se litt inn i fremtiden; planlegg på forhånd før du plasserer dataene dine under versjonskontroll. Ved å sette opp strukturen på innholdet i depotene dine på en effektiv måte den første gangen, kan du forhindre en drøss med fremtidige hodepiner.
Det er noen få ting å tenke over når du setter opp Subversiondepoter. La oss anta at som depotadministrator, vil du være ansvarlig for å vedlikeholde versjonskontrollsystemet for flere prosjekter. Det første du må bestemme deg for er om du vil bruke et enkelt depot for flere prosjekter, om du vil gi hvert prosjekt sitt eget depot, eller en kombinasjon av disse løsningene.
Det er fordeler med å bruke et enkelt depot for flere prosjekter, først og fremst at du slipper duplisert vedlikehold. Et enkelt depot betyr at det er ett sett med påhakningsskript, én ting å ta backup av, én ting å dumpe og laste hvis Subversion kommer i en ny inkompatibel versjon og så videre. I tillegg kan du lett flytte data mellom prosjekter uten å miste historisk versjonsinformasjon.
Bakdelen med å bruke et enkelt depot er at forskjellige prosjekter kan ha forskjellige postlister eller forskjellige autentiserings- og autorisasjonskrav. Husk også at Subversion bruker globale revisjonsnumre i depotet. Noen liker ikke at selv om ingen forandringer er blitt gjort i deres prosjekt den senere tid, fortsetter likevel det yngste revisjonsnummeret å øke fordi andre prosjekter legger til nye revisjoner.
En kompromissløsning kan også bli brukt. For eksemel kan prosjekter bli gruppert sammen etter hvor relaterte de er til hverandre. Du kan ha noen få depoter med en håndfull prosjekter i hvert av dem. På denne måten kan prosjekter som kan komme til å dele data gjøre dette ganske enkelt, og etterhvert som nye revisjoner blir lagt til depotet, vet utviklerne at disse nye revisjonene ihvertfall er fjernt relaterte på en eller annen måte til alle som bruker dette depotet.
Etter å ha avgjort hvordan du vil organisere prosjektene i
henhold til depotene, vil du kanskje tenke over
kataloghierarkier i selve depotene.
Fordi Subversion bruker vanlige katalogkopier til forgrening og
merking (se Kapittel 4, Forgrening og fletting), anbefaler
Subversionmiljløet at du velger en katalogplassering for hver
prosjektrot – den “øverste”
katalogen som inneholder data relatert til det prosjektet – og
deretter oppretter tre kataloger under denne roten:
trunk som er katalogen der hovedutviklingen
av prosjektet foregår; branches som er en
katalog som er ment for å lage diverse navngitte grener av
hovedutviklingen; tags som er en katalog av
grener som er laget, og kanskje ødelagt, men aldri
forandret.[34]
For eksempel kan depotet ditt se ut som dette:
/
calc/
trunk/
tags/
branches/
calendar/
trunk/
tags/
branches/
spreadsheet/
trunk/
tags/
branches/
…
Legg merke til at det har ingenting å si hvor i depotet hver prosjektrot er. Hvis du har bare ett prosjekt per depot, er den logiske plassen å putte hver prosjektrot i roten av det prosjektets respektive depot. Hvis du har flere prosjekter, vil du kanskje ønske å arrangere dem i grupper innenfor depotet, kanskje legge prosjekter med likelydende mål eller delt kode i den samme underkatalogen, eller kanskje rett og slett gruppere dem alfabetisk. Et slikt system kan se ut som dette:
/
utils/
calc/
trunk/
tags/
branches/
calendar/
trunk/
tags/
branches/
…
office/
spreadsheet/
trunk/
tags/
branches/
…
Legg opp depotet ditt på den måten du synes passer best. Subversion forventer ikke eller påtvinger deg ikke en spesiell layout – hva Subversion angår, er en katalog en katalog en katalog. Ideelt sett skal du kunne velge det depotoppsettet som fyller behovet til folkene som arbeider på prosjektet som bor der.
Etter at du har bestemt deg for hvordan du vil arrangere prosjektene i depotet ditt, vil du sannsynligvis ønske å fylle depotet med dette oppsettet og de innledende prosjektdataene. Det er et par måter du kan gjøre dette i Subversion. Du kan bruke svn mkdir-kommandoen (se Kapittel 9, Subversion Complete Reference) for å opprette hver katalog i skjelettet av depotlayouten, en etter en. En raskere måte å utføre den samme oppgaven på er å bruke kommandoen svn import (se “svn import”). Ved å først opprette layouten i en midlertidig plassering på harddisken, kan du importere hele katalogtreet inn i depotet i en enkelt innlegging:
$ mkdir tmpdir $ cd tmpdir $ mkdir prosjektA $ mkdir prosjektA/trunk $ mkdir prosjektA/branches $ mkdir prosjektA/tags $ mkdir prosjektB $ mkdir prosjektB/trunk $ mkdir prosjektB/branches $ mkdir prosjektB/tags … $ svn import . file:///sti/til/depot --message "Innledende oppsett av depotet" Adding prosjektA Adding prosjektA/trunk Adding prosjektA/branches Adding prosjektA/tags Adding prosjektB Adding prosjektB/trunk Adding prosjektB/branches Adding prosjektB/tags … Committed revision 1. $ cd .. $ rm -rf tmpdir $
Du kan kontrollere resultatene etter importen ved å kjøre kommandoen svn list:
$ svn list --verbose file:///sti/til/depot
1 harry May 08 21:48 prosjektA/
1 harry May 08 21:48 prosjektB/
…
$
Når du har skjelettet til oppsettet på plass, kan du begynne å importere selve prosjektdataene inn i depotet ditt, hvis noen slike data allerede eksisterer. Som sagt, det er flere måter å gjøre dette på. Du kan bruuke svn import-kommandoen. Du kan hente ut en arbeidskopi fra det nye depotet ditt, flytte og arrangere prosjektdataene inne i arbeidskopien og bruke svn add- og svn commit-kommandoene. Men når vi begynner å snakke om slike ting snakker vi ikke lengre om depotadministrasjon. Hvis du ikke allerede er kjent med svn-klientprogrammet, se Kapittel 2, Grunnleggende bruk.
Nå skal du ha fått en grunnleggende forståelse av hvordan du oppretter, konfigurerer og vedlikeholder Subversiondepoter. Vi har introdusert deg for de forskjellige verktøyene som vil hjelpe deg med denne oppgaven. Gjennom kapittelet har vi gjort oppmerksom på noen feller en administrator kan gå i og hvordan disse fellene kan unngås.
Alt som gjenstår nå er å bestemme hvilke spennende data som du vil lagre i depotet ditt, og til sist, hvordan du vil gjøre det tilgjengelig over nettverket. Det neste kapittelet handler kun om nettverk.
[27] Dette kan høres råflott ut, men vi snakker bare om alle som er interesserte i dette mystiske området hvor alles data ligger.
[28] Uttales “fuzz-fuzz”, hvis Jack Repenning har noe å si angående det.
[29] Og det er forøvrig en funksjonalitet og ikke en feil.
[30] Selv om svnadmin dump har en konsekvent regel om innledende skråstreker – å ikke inkludere dem – kan det være at andre programmer som genererer dumpdata ikke er like konsekvente.
[31] Som for eksempel: Harddisk + kjempemagnet = krise.
[32] Dumpformatet i Subversion ligner et RFC-882-format, den samme typen format som vanligvis brukes i eposter.
[33] svnadmin setlog kan bli kjørt på en måte som går helt utenom påhakningsgrensesnittet.
[34] Trioen trunk,
tags og branches
blir noen ganger referert til som
“TTB-katalogene”.
Innholdsfortegnelse
Et Subversiondepot kan bli aksessert samtidig av klienter som
kjører på den samme maskinen der depotet ligger ved å bruke
file:///-metoden.
Men det typiske Subversionoppsettet involverer en enkelt
servermaskin som blir aksessert fra klienter på maskiner over hele
kontoret – eller kanskje over hele verden.
Denne seksjonen beskriver hvordan du kan gjøre Subversiondepotet ditt tilgjengelig utenfra servermaskinen så fjerntliggende klienter kan bruke det. Vi vil dekke servermekanismene som Subversion har tilgjengelig og diskutere konfigurasjonen og bruken av hver av disse. Etter å ha lest denne seksjonen vil du være i stand til å avgjøre hvilket nettverksoppsett som er det riktige for dine behov, og forstå hvordan du skal sette dette opp på servermaskinen.
Subversion ble designet med et abstrakt nettverkslag. Dette betyr at et depot kan bli aksessert av alle typer serverprosesser, og klientens API for depottilgangen gir programmerere anledning til å lage programtillegg som forstår relevante nettverksprotokoller. I teorien kan Subversion bruke et uendelig antall nettverksimplementasjoner. I praksis er det for tiden bare to servermodeller tilgjengelig.
Apache er en ekstremt populær webserver. Ved å bruke mod_dav_svn-modulen kan Apache aksessere et depot og gjøre det tilgjengelig for klienter via WebDAV/DeltaV-protokollen, som er en utvidelse av HTTP. I det andre hjørnet er svnserve: Et lite, enkeltstående serverprogram som kommuniserer med klientene ved hjelp av en egendefinert protokoll. Tabell 6.1, “Sammenligning av nettverksservere” viser en sammenligning av de to servermodellene.
Tabell 6.1. Sammenligning av nettverksservere
| Funksjonalitet | Apache + mod_dav_svn | svnserve |
|---|---|---|
| Autentiseringsvalg | vanlig HTTP(S)-autentisering, X.509-sertifikater, LDAP, NTLM eller enhver annen mekaniske som er tilgjengelig for Apache httpd | CRAM-MD5 eller SSH |
| Valg for brukerkontoer | privat fil med brukerliste | privat fil med brukerliste eller eksisterende systemkontoer (SSH) |
| Authorization options | read/write access can be granted over whole repository, or specified per-path. | read/write access can be granted over whole repository, or specified per-path. |
| Kryptering | via valgfri SSL | via valgfri SSH-tunnel |
| Logging | full Apache logs of each HTTP request, with optional “high-level” logging of general client operations | no logging |
| Samspillsevne | delvis brukbar for andre WebDAV-klienter | Kommuniserer bare med svn-klienter |
| Visning på web | begrenset innebygget støtte, eller via tredjeparts verktøy som for eksempel ViewVC | kun via tredjeparts verktøy som for eksempel ViewVC |
| Hastighet | Noe langsommere | Noe raskere |
| Innledende oppsett | Noe komplekst | Ganske enkelt |
Install and configure a standard Apache 2.0 server, then activate a special subversion-server module. Clients speak to server via HTTP or HTTPS, using the WebDAV protocol.
Allows Subversion to use any of the numerous authentication systems already integrated with Apache.
No need to create system accounts on server.
Full Apache logging.
Network traffic can be encrypted via SSL.
HTTP(S) can usually go through corporate firewalls.
Built-in repository browsing via web browser.
Repository can be mounted as a network drive for transparent version control. (See “Autoversioning”.)
Noticeably slower than svnserve, because HTTP is a stateless protocol and requires more turnarounds.
Initial setup can be complex.
A lightweight serve process which can run either as a persistent daemon, or as something automatically launched by inetd when necessary. Clients authenticate via CRAM-MD5 algorithm and speak a custom network protocol.
Quick and easy to set up.
Network protocol is stateful and noticeably faster than WebDAV.
No need to create system accounts on server.
Password is not passed over the network.
Network protocol is not encrypted.
Only one choice of authentication method.
Password is stored in the clear on the server.
No logging of any kind, not even errors.
Each client uses an existing SSH (system) account to spawn a temporary svnserve process (running as themselves) on the server machine. The svnserve process accesses the repository, communicates with the client over the SSH tunnel, then dies when the SSH connection is closed. (There is no long-running svnserve process.)
Network protocol is stateful and noticeably faster than WebDAV.
You can take advantage of existing ssh accounts and user infrastructure.
All network traffic is encrypted.
Only one choice of authentication method.
No logging of any kind, not even errors.
Requires users to be in same system group, or use a shared ssh key.
Can lead to file permissions problems.
So, which server should you use? Which is best?
Obviously, there's no right answer to that question. Every team has different needs, and the different servers all represent different sets of tradeoffs. The Subversion project itself doesn't endorse one server or another, or consider either server more “official” than another.
In general, the authors of this book recommend a vanilla svnserve installation for small teams just trying to get started with a Subversion server; it's the simplest to set up, and has the fewest maintenance issues. Remember, you can always switch to a more complex server deployment as your needs change.
Here are some general recommendations, based on years of supporting users:
If you're trying to set up the simplest possible server for your group, then a vanilla svnserve installation is the easiest, fastest route. Note, however, that your repository data will be transmitted in the clear over the network. If your deployment is entirely within your company's LAN or VPN, this isn't an issue. If the repository is exposed to the wide-open internet, then you might want to make sure the repository's contents aren't sensitive (e.g. it contains only open-source code.)
If you need to integrate with existing identity systems (LDAP, Active Directory, NTLM, X.509, etc.), then an Apache-based server is your only real option. Similarly, if you absolutely need server-side logs of either server errors or client activities, then an Apache-based server is required.
If you've decided to use either Apache or stock
svnserve, create a
single svn user on your system and run
the server process as that user. Be sure to make the
repository directory wholly owned by
the svn user as well. From a security
point of view, this keeps the repository data nicely
siloed and protected by operating system filesystem
permissions, changeable by only the Subversion server
process itself.
If you have an existing infrastructure heavily based on SSH accounts, and if your users already have system accounts on your server machine, then it makes sense to deploy an svnserve-over-ssh solution. Otherwise, we don't widely recommend this option to the public. It's generally considered safer to have your users access the repository via (imaginary) accounts managed by svnserve or Apache, rather than by full-blown system accounts. If your deep desire for encrypted communication still draws you to this option, we recommend using Apache with SSL instead.
Do not be seduced by the simple
idea of having all of your users access a repository
directly via file:/// URLs. Even if
the repository is readily available to everyone via
network share, this is a bad idea. It removes any layers
of protection between the users and the repository: users
can accidentally (or intentionally) corrupt the repository
database, it becomes hard to take the repository offline
for inspection or upgrade, and it can lead to a mess of
file-permissions problems (see
“Støtte for flere metoder for
tilgang til depotet”.) Note
that this is also one of the reasons we warn against
accessing repositories via svn+ssh://
URLs — from a security standpoint, it's effectively
the same as local users accessing
via file:///, and can entail all the
same problems if the administrator isn't careful.
Programmet svnserve er en lettvektsserver
som er i stand til å snakke med klienter over TCP/IP ved å bruke en
tilpasset, stateful
protokoll.
Klienter kontakter en svnserve-server ved å
bruke URL-er som begynner med svn://- eller
svn+ssh://-skjemaet.
Denne seksjonen vil forklare de forskjellige måtene å kjøre
svnserve på, hvordan klienter autentiserer seg
selv ovenfor serveren, og hvordan du setter opp en passende
adgangskontroll til depotene dine.
There are a few different ways to run the svnserve program:
Run svnserve as a standalone daemon, listening for requests.
Have the Unix inetd daemon temporarily spawn svnserve whenever a request comes in on a certain port.
Have SSH invoke a temporary svnserve over an encrypted tunnel.
Run svnserve as a Windows service.
The easiest option is to run svnserve
as a standalone “daemon” process. Use the
-d option for this:
$ svnserve -d $ # svnserve is now running, listening on port 3690
Når svnserve kjøres i daemon-modus, kan
du bruke valgene --listen-port= og
--listen-host= for å sette den eksakte porten
og servernavn som den skal “bindes” til:
Når svnserve-programmet kjører, gjør det
alle depotene på systemet tilgjengelig på nettverket.
En klient må spesifisere en absolutt sti i
depot-URLen.
Hvis for eksempel et depot ligger i
/usr/local/depoter/prosjekt1, kan en klient
nå det via
svn://server.example.com/usr/local/depoter/prosjekt1.
For å øke sikkerheten kan du angi -r-valget til
svnserve som begrenser den til å kun
ekportere depoter som ligger under denne stien.
For eksempel:
$ svnserve -d -r /usr/local/depot …
Bruken av -r-valget forandrer plasseringen
av roten som programmet bruker på det fjerntliggende
filsystemet.
Klienter bruker dermed URLer som har fjernet denne delen av
stien, noe som gir mye kortere (og mindre avslørende)
URLer:
$ svn checkout svn://server.example.com/prosjekt1 …
If you want inetd launch the process,
then you can pass the -i
(--inetd) option:
$ svnserve -i ( success ( 1 2 ( ANONYMOUS ) ( edit-pipeline ) ) )
Når programmet blir startet med
--inetd-valget, prøver
svnserve å snakke med en Subversionklient via
standard inn og standard
ut ved å bruke en tilpasset protokoll.
Dette er den vanlige oppførselen for et program som blir kjørt
via inetd.
IANA har reservert port 3690 for Subversionprotokollen, så på et
Unix-lignende system kan du legge til linjer som dette i
/etc/services (hvis de ikke allerede
eksisterer):
svn 3690/tcp # Subversion svn 3690/udp # Subversion
Og hvis systemet ditt bruker en klassisk Unix-lignende
inetd-daemon, kan du legge denne linjen til
/etc/inetd.conf:
svn stream tcp nowait svnbruker /usr/bin/svnserve svnserve -i
Pass på at “svnbruker” er en bruker som har
tilstrekkelige rettigheter til å få tilgang til depotene dine.
Når nå en klientforbindelse kommer inn til serveren på port
3690, vil inetd starte en egen
svnserve-prosess for å ta seg av den.
Du vil selvfølgelig også ønske å legge til -r
til konfigurasjonslinja også, for å begrense hvilke depot som
eksporteres.
En tredje måte å starte svnserve på, er i
“tunnelmodus”, med valget -t.
Denne modusen forutsetter at et fjerntjenesteprogram som
RSH eller SSH har klart å
autentisere som en bruker og nå skal starte en privat
svnserve-prosess som denne
brukeren.
svnserve-programmet oppfører seg normalt
(kommuniserer via standard inn og
standard ut), og går ut i fra at trafikken
blir automatisk omdirigert gjennom en form for tunnel tilbake
til klienten.
Når svnserve blir startet av en tunnelagent som dette, pass på at den autentiserte brukeren
har full skrive- og leseaksess til databasefilene i depotet.
Det er hovedsaklig det samme prinsippet som når en lokal bruker
får tilgang til depotet via
file:///-URLer.
This option is described in much more detail in “Autentisering og autorisasjon via SSH”.
If your Windows system is a descendant of Windows NT (2000, 2003, XP, Vista), then you can run svnserve as a standard Windows service. You'll need to define the service using a command-line tool SC.EXE. Much like the inetd configuration line, you must specify an exact invocation of svnserve for Windows to run at start-up time:
C:\> sc create svn
binpath= "C:\svn\bin\svnserve.exe --service [args]"
displayname= "Subversion Server"
depend= Tcpip
start= auto
This defines a new Windows service named “svn”, and which executes a particular svnserve.exe command when started. There are a number of caveats in the prior example, however.
First, notice that the svnserve.exe
program is always invoked with
the --service option. You must always
specify this option, and you may not
specify other conflicting options such
as --daemon, --tunnel,
or --inetd. Options such
as -r or --listen-port are
fine. Second, be careful about spaces when invoking
the SC.EXE command: the
key= value patterns must have no
spaces between key= and exactly one
space before the value. Lastly, be
careful about spaces in your command-line to be invoked. If
a directory name contains spaces (or other characters that
need escaping), place the entire inner value
of binpath in double-quotes, by escaping
them:
C:\> sc create svn
binpath= "\"C:\program files\svn\bin\svnserve.exe\" --service [args]"
displayname= "Subversion Server"
depend= Tcpip
start= auto
Once the service is defined, it can stopped, started, or queried using standard GUI tools (The Services administrative control panel), or at the command line as well:
C:\> net stop svn C:\> net start svn
The service can also be uninstalled (i.e. undefined) by
deleting its definition: sc delete svn.
Just be sure to stop the service first!
The SC.EXE program has many other
subcommands and options, run sc /? to
learn more about it.
Når en klient kobler seg til en svnserve-prosess, skjer de følgende tingene:
Klienten velger et spesifikt depot.
Serveren går gjennom depotets
conf/svnserve.conf-fil og begynner å
gjennomføre alle autentiserings- og autorisasjonsregler som
er definert i den.
Avhengig av situasjonen og autorisasjonsreglene,
kan klienten få lov til å foreta forespørsler anonymt, uten noen gang å motta en autentiseringsforespørsel, ELLER
klienten kan bli spurt etter autentiseringsinfo til enhver tid, ELLER
hvis den opererer i “tunnelmodus”, vil klienten erklære seg selv som å allerede være eksternt autentisert.
Når dette skrives, vet serveren bare hvordan den skal sende en CRAM-MD5[35]-autentiseringsforespørsel. I hovedsak sender serveren litt data til klienten. Klienten bruker MD5-algoritmen for å lage et fingeravtrykk av de kombinerte dataene og passordet og sender fingeravtrykket som svar. Serveren foretar den samme utregningen med det lagrede passordet for å sjekke at resultatet er identisk. Passordet blir ikke på noe tidspunkt sendt over nettverket.
Det er også selvfølgelig mulig for klienten å bli eksternt autentisert via en tunnelagent, som for eksempel SSH. I dette tilfellet sjekker serveren rett og slett bare brukeren den kjører som, og bruker den som det autentiserte brukernavnet. For mer om dette, se “Autentisering og autorisasjon via SSH”.
Som du allerede har gjettet, er
svnserve.conf-fila i et depot den sentrale
mekanismen for å kontrollere autentiserings- og
autorisasjonsregler.
Fila har det samme formatet som andre konfigurasjonsfiler (se
“Konfigurasjonsområdet for bruk under kjøring”):
Seksjonsnavn er markert med klammeparenteser
([ og ]), kommentarer
begynner med hashtegn (#), og hver
seksjon inneholder spesifikke variabler som kan settes
(variabel = verdi).
La oss gå gjennom denne fila og lære hvordan vi bruker
dem.
For øyeblikket har [general]-seksjonen
i svnserve.conf alle variablene som du
trenger.
Start ved å definere en fil som inneholder brukernavn og
passord, og et autentiseringsområde:
[general] password-db = brukerfil realm = eksempelområde
realm er et navn som du definerer.
Det forteller klienter hvilket
“autentiseringsnavnerom” de kobler seg til;
Subversionklienten viser det når den spør etter
autentiseringsinfo, og bruker det som en nøkkel (sammen med
serverens vertsnavn og port) for å lagre legitimasjonsinfo
på disken (se “Lagring av klientlegitimasjon”).
Variabelen password-db peker til en separat
fil som inneholder en liste med brukernavn og passord, som
bruker det samme kjente formatet.
For eksempel:
[users] harry = foopassord sally = barpassord
Verdien i password-db kan være en
absolutt eller relativ sti til brukerfila.
For mange administratorer er det enkelt å lagre fila i
conf/-området i depotet, sammen med
svnserve.conf.
På den annen side er det mulig at du vil ha to eller flere
depoter som deler den samme brukerfila; i så tilfelle bør fila
kanskje ligge på en mer offentlig plass.
Depotene som deler brukerfila bør også settes opp til å ha
samme område (realm) siden
brukerlista hovedsaklig definerer et
autentiseringsområde.
Hvor fila enn ligger, pass på å sette lese- og
skriverettighetene på den.
Hvis du vet hvilke(n) bruker(e) svnserve
vil kjøre som, begrens lesetilgangen til brukerfila etter hva
som er nødvendig.
Det er to variabler til som må settes i
svnserve.conf-fila, de avgjør hva
uautentiserte (anonyme) og autentiserte brukere får lov til å
gjøre.
Variablene anon-access og
auth-access kan settes til verdiene
none, read eller
write.
Ved å sette verdien til none begrenses alle
typer tilganger; read tillater bare lesing
fra depotet, og write gir fullstendig
lese/skrive-tilgang til depotet.
For eksempel:
[general] password-db = userfile realm = example realm # anonyme brukere kan bare lese depotet anon-access = read # autentiserte brukere kan både lese og skrive auth-access = write
Oppsettet i dette eksempelet viser standardverdiene som variablene har, i tilfelle du glemmer å definere dem. Hvis du vil være enda mer konservativ, kan du blokkere anonym tilgang fullstendig:
[general] password-db = brukerfil realm = eksempelområde # anonyme brukere forbudt anon-access = none # autentiserte brukere kan både lese og skrive auth-access = write
The server process not only understands
these “blanket” access controls to the
repository, but also finer-grained access restrictions placed
on specific files and directories within the repository. To
make use of this feature, you need to define a file containing
more detailed rules, and then set
the authz-db variable to point to it:
[general] password-db = userfile realm = example realm # Specific access rules for specific locations authz-db = authzfile
The syntax of the authzfile file is
discussed in detail in
“Path-Based Authorization”. Note
that the authz-db variable isn't mutually
exclusive with the anon-access
and auth-access variables; if all the
variables are defined at once, then all
of the rules must be satisfied before access is allowed.
svnserves innebyggede autentisering kan være veldig grei å ha med å gjøre, fordi man ikke trenger å opprette virkelige brukerkontoer på systemet. På den annen side har noen administratorer allerede et veletablert rammeverk for SSH-autentisering på plass. I disse situasjonene har alle brukerne på prosjektet allerede systemkontoer og muligheten til å koble seg til via SSH på servermaskinen.
Det er enkelt å bruke SSH sammen med
svnserve.
Klienten bruker ganske enkelt URL-skjemaet
svn+ssh:// for å koble seg til:
$ whoami harry $ svn list svn+ssh://server.example.com/repos/prosjekt harry@server.example.com's password: ***** foo bar baz …
I dette eksempelet starter Subversionklienten en lokal
ssh-prosess, kobler seg opp mot
server.example.com, autentiserer seg som
brukeren harry, starter en privat
svnserve-prosess på den fjerntliggende
maskinen som kjører som brukeren harry.
svnserve-kommandoen blir startet i
tunnelmodus (-t) og nettverksprotokollen som
den bruker blir “lagt i tunnel” over den krypterte
forbindelsen via ssh, tunnelagenten.
svnserve vet at den kjører som brukeren
harry, og hvis klienten foretar en
innlegging, vil det autentiserte brukernavnet bli kreditert som
forfatteren av den nye revisjonen.
Den viktige tingen å forstå her er at Subversionklienten ikke kobler seg til en kjørende svnserve-daemon. Denne tilkoblingsmetoden krever ingen daemon, og den legger heller ikke merke til om noen slike finnes. Den stoler fullt og helt på evnen til ssh å starte en midlertidig svnserve-prosess, som avsluttes når nettverksforbindelsen lukkes.
Når du bruker svn+ssh://-URLer til å
aksessere et depot, husk at det er
ssh-programmet som spør etter autentisering,
og ikke svn-klienten.
Dette betyr at det er ingen automatisk lagring av passord (se
“Lagring av klientlegitimasjon”).
Subversionklienten foretar ofte flere tilkoblinger til depotet,
selv om brukere vanligvis ikke legger merke til dette på grunn
av funksjonen som lagrer passord.
Men ved bruk av svn+ssh:// kan brukere bli
plaget med at ssh spør etter passord for hver
eneste utgående tilkobling.
Løsningen er å bruke et separat passordlagringssystem for SSH
som for eksempel ssh-agent på et
Unix-lignende system eller pageant i
Windows.
Når tilkobling skjer gjennom en tunnel, blir autorisering
for databasefilene i depotet hovedsaklig kontrollert av
tilgangsrettigheter i operativsystemet; det er mye det samme som
om Harry aksesserer depotet direkte via en file:///-URL.
Hvis flere systembrukere skal aksessere depotet direkte, vil du
kanskje plassere dem i en felles gruppe, og alt du trenger å
tenke på er å være forsiktig med umask.
(Pass på å lese “Støtte for flere metoder for
tilgang til depotet”.)
Men selv i tilfellet med bruk av tunnel kan
svnserve.conf bli brukt til å blokkere
tilgang ved å sette auth-access = read eller
auth-access = none.[36]
Man skulle tro at historien om SSH ender her, men det gjør
den ikke.
Subversion lar deg opprette tilpasset tunneloppførsel i kjøringsfila config (se “Konfigurasjonsområdet for bruk under kjøring”).
I [tunnels]-seksjonen i
config-fila kan du enkelt definere det på
denne måten:
[tunnels] rsh = rsh
Og nå kan du bruke denne nye tunneldefinsjonen ved å bruke
et URL-skjema som samsvarer med navnet på den nye variabelen:
svn+rsh://server/sti.
Ved bruk av det nye URL-skjemaet vil Subversionklienten faktisk
kjøre kommandoen rsh server svnserve -t
i bakgrunnen.
Hvis du inkluderer et brukernavn i URLen (for eksempel
svn+rsh://brukernavn@server/sti), vil
klienten også ta dette med i kommandoen (rsh
brukernavn@server svnserve -t).
Men du kan definere nye tunnelskjema til å være mye mer
avanserte enn som så:
[tunnels] joessh = $JOESSH /opt/alternate/ssh -p 29934
Dette eksempelet demonstrerer et par ting.
For det første viser det hvordan du lar Subversionklienten kjøre
en spesifikk binærfil som oppretter tunnelen (den som ligger som
/opt/alternate/ssh med spesifikke valg.
I dette tilfellet vil det å aksessere en
svn+joessh://-URL starte denne SSH-binærfila
med -p 29934 som parameter – nyttig hvis du vil
at tunnelprogrammet skal koble seg til en ustandard port.
For det andre viser det hvordan en tilpasset miljøvariabel
kan overstyre navnet på et tunnelprogram.
Det å sette miljøvariabelen SVN_SSH er en
behagelig måte å overstyre den vanlige SSH-tunnelagenten.
Men hvis du må ha flere forskjellige overstyringer for
forskjellige servere, der hver av dem kanskje kontakter en
forskjellig port eller sender et annet sett med parametere til
SSH, kan du bruke mekanismen som er demonstrert i dette
eksempelet.
Hvis vi nå setter miljøvariabelen JOESSH til
noe, vil innholdet av denne variabelen overstyre hele innholdet
av tunnelvariabelen – $JOESSH vil bli kjørt
istedenfor /opt/alternate/ssh -p
29934.
Det er ikke bare mulig å kontrollere måten klienten starter ssh på, men også å kontrollere oppførselen til sshd på servermaskinen. I denne seksjonen vil vi vise hvordan du kontrollerer den eksakte svnserve-kommandoen som blir kjørt av sshd, og også hvordan du får flere brukere til å dele en enkel systemkonto.
Til å begynne med, finn fram til hjemmekatalogen for
kontoen som du skal bruke til å kjøre
svnserve.
Vær sikker på at kontoen har et offentlig/privat SSH-nøkkelpar
installert, og at brukeren kan logge inn via autentisering med
offentlig nøkkel.
Autentisering via passord vil ikke fungere, siden alle de
følgende SSH-triksene baserer seg på bruk av
authorized_keys-fila som brukes av
SSH.
Hvis den ikke allerede finnes, opprett fila
authorized_keys (i Unix er den vanligvis
kalt ~/.ssh/authorized_keys).
Hver linje i denne fila beskriver en offentlig nøkkel som får
lov til å koble seg til.
Linjene har vanligvis dette formatet:
ssh-dsa AAAABtce9euch… bruker@example.com
Det første feltet beskriver nøkkeltypen, det andre feltet
er selve den uuencodede nøkkelen, og det tredje feltet er en
kommentar.
En lite kjent funksjonalitet er at hele linjen kan bli
innledet av et command-felt:
command="program" ssh-dsa AAAABtce9euch… bruker@example.com
Når command-feltet er definert, vil
SSH-daemonen kjøre det navngitte programmet istedenfor den
typiske svnserve -t-prosessen som
Subversionklienten spør etter.
Dette åpner døra til en rekke triks på serversiden.
I de følgende eksemplene forkorter vi linjene i fila
som:
command="program" TYPE NØKKEL KOMMENTAR
Fordi vi kan spesifisere kommandoen som kjøres på serversiden, er det lett å navngi en spesifikk svnserve-binærfil som skal kjøres og levere et ekstra parameter til den:
command="/sti/til/svnserve -t -r /virtuell/rot" TYPE NØKKEL KOMMENTAR
I dette eksempelet kan
/sti/til/svnserve være et spesiallaget
innkapslingsskript rundt svnserve som
setter umask-verdien (se “Støtte for flere metoder for
tilgang til depotet”).
Det viser også hvordan svnserve kan
forankres i en virtuell rotkatalog akkurat som man ofte gjør
når svnserve kjøres som en daemonprosess.
Dette kan gjøres enten ved å begrense adgangen til deler av
systemet, eller ganske enkelt spare brukeren for å måtte
skrive inn en absolutt sti i
svn+ssh://-URLen.
Det er også mulig å la flere brukere dele en enkel konto.
Istedenfor å lage en egen systemkonto for hver bruker, lag et
offentlig/privat nøkkelpar for hver person.
Legg deretter hver offentlig nøkkel inn i
authorized_users-fila, en per linje, og
bruk valget --tunnel-user:
command="svnserve -t --tunnel-user=harry" TYPE1 NØKKEL1 harry@example.com command="svnserve -t --tunnel-user=sally" TYPE2 NØKKEL2 sally@example.com
Dette eksempelet lar både Harry og Sally få koble seg til
den samme kontoen via offentlig nøkkel-autentisering.
Hver av dem har en spesiallaget kommando som vil bli kjørt;
valget --tunnel-user ber svnserve
-t om å gå ut i fra at den spesifiserte verdien er
den autentiserte brukeren.
Uten --tunnel-user vil det se ut som om alle
innlegginger kommer fra en delt systemkonto.
En siste advarsel:
Det å gi en bruker tilgang til serveren via en offentlig
nøkkel på en delt konto kan fortsatt gi andre former for
SSH-tilgang, selv om du har definert
command-verdien i
authorized_keys.
Brukeren kan for eksempel fortsatt få kommandolinjetilgang via
SSH, eller være i stand til å utføre X11- eller generell
port-forwarding gjennom serveren.
For å gi brukeren så lite rettigheter som mulig, vil du
kanskje spesifisere et antall begrensningsvalg like etter
command:
command="svnserve -t --tunnel-user=harry",no-port-forwarding,\
no-agent-forwarding,no-X11-forwarding,no-pty \
TYPE1 NØKKEL1 harry@example.com
HTTP-serveren Apache er en nettverksserver i tungvektsklassen som Subversion kan bruke. Ved hjelp av en spesiallaget modul gjør httpd Subversiondepoter tilgjengelig for klienter via WebDAV/DeltaV-protokollen, som er en utvidelse av HTTP 1.1 (se http://www.webdav.org/ for mer informasjon). Denne protokollen tar HTTP-protokollen som vi finner over alt, kjernen av World Wide Web, og legger til muligheter for skriving – mer spesifikt, versjonert skriving. Resultatet er et standardisert, robust system som går godt sammen med Apache 2.0-programvaren, støttet av et stort antall operativsystemer og tredjeparts programvare. Og systemadministratorer trenger ikke å åpne enda en port på systemet.[37] En Apache/Subversion-server har større funksjonalitet enn svnserve, men er også vanskeligere å sette opp. Med fleksibilitet kommer det ofte mer kompleksitet med på kjøpet.
Mye av den følgende diskusjonen inneholder referanser til konfigurasjonsdirektiver for Apache. Selv om noen eksempler inneholder bruk av disse direktivene, er det å beskrive dem i full detalj utenfor det som dette kapittelet dekker. Utviklerne bak Apache vedlikeholder fortreffelig dokumentasjon, offentlig tilgjengelig på hjemmesiden http://httpd.apache.org. En generell oversikt over konfigurasjonsdirektivene er for eksempel tilgjengelig på http://httpd.apache.org/docs-2.0/mod/directives.html.
I tillegg, etter hvert som du gjør forandringer til
Apacheoppsettet, kan det skje at en feil blir gjort på veien.
Hvis du ikke allerede kjenner til Apaches loggesystem, bør du bli
kjent med det.
I httpd.conf-fila di er det direktiver som
spesifiserer plasseringer på disken av aksess- og
feilmeldingsloggene som genereres av Apache (henholdsvis
direktivene CustomLog og
ErrorLog).
Subversions mod_dav_svn bruker også Apaches logging av
feilmeldinger.
Du kan alltids gå gjennom innholdet av disse filene etter
informasjon som kan vise kilden til et problem som ellers ikke er
lett å få øye på.
For å få depotet ditt på nettverk over HTTP, trenger du hovedsaklig fire komponenter, tilgjengelig i to pakker. Du trenger Apache httpd 2.0, DAV-modulen mod_dav som følger med Apache, Subversion og filsystemmodulen mod_dav_svn som kommer sammen med Subversion. Når du har alle disse komponentene er prosessen å få depotet på nett så enkel som å:
få httpd 2.0 opp og kjøre med mod_dav-modulen,
installere programtillegget mod_dav_svn til mod_dav, som bruker Subversions biblioteker til å aksessere depotet, og
konfigurere httpd.conf-fila di til
å eksportere (eller vise) depotet.
Du kan sette opp de første to elementene enten ved å
kompilere httpd og Subversion fra kildekode
eller ved å installere ferdigbygde pakker med dem på systemet.
For den mest oppdaterte informasjonen om hvordan du kompilerer
Subversion for bruk sammen med Apache HTTP-serveren og
hvordan kompilere og sette opp selve Apache for dette, se
INSTALL-fila på toppnivået av
kildekodetreet til Subversion.
Når du har alle de nødvendige komponentene installert på
systemet ditt, er alt som gjenstår å konfigurere Apache ved
hjelp av httpd.conf-fila.
Få Apache til å laste mod_dav_svn-modulen ved å bruke
LoadModule-direktivet.
Dette direktivet må komme foran alle andre Subversion-relaterte
elementer.
Hvis Apache ble installert med standard filplasseringer, er
mod_dav_svn-modulen plassert i
modules-katalogen der Apache er installert
(ofte /usr/local/apache2).
LoadModule-direktivet har en enkel syntaks
som kobler en navngitt modul til plasseringen
av et delt bibliotek på disken:
LoadModule dav_svn_module modules/mod_dav_svn.so
Legg merke til at hvis mod_dav ble
kompilert som et delt objekt (istedenfor å bli statisk linket
direkte til binærfila httpd) vil du også
trenge en tilsvarende LoadModule-linje for
dette.
Pass på at den kommer før
mod_dav_svn-linjen:
LoadModule dav_module modules/mod_dav.so LoadModule dav_svn_module modules/mod_dav_svn.so
På en senere plassering i konfigurasjonsfila må du fortelle
Apache hvor du har lagt Subversiondepotet (eller depotene).
Location-direktivet har en XML-lignende
notasjon som starter med et åpningselement og slutter med et
sluttelement med diverse andre konfigurasjonsdirektiver i
midten.
Formålet med Location-direktivet er å
instruere Apache til å gjøre noe spesielt når den behandler
forespørsler som går til en gitt URL eller et av dens barn.
I tilfellet med Subversion vil du at Apache gir støtte for URLer
som peker til en versjonert ressurs i DAV-laget.
Du kan instruere Apache til å delegere håndteringen av alle
URLer der en del av stien (den delen av URLen som kommer etter
servernavnet og det valgfrie portnummeret) som begynner med
/repos/ til en DAV-tjeneste som har depotet
plassert som /absolutt/sti/til/depotet ved
å bruke den følgende
httpd.conf-syntaksen:
<Location /repos> DAV svn SVNPath /absolutt/sti/til/depotet </Location>
Hvis du planlegger å ha flere Subversiondepoter som vil
ligge i den samme foreldrekatalogen på en lokal disk, kan du
bruke et alternativt direktiv,
SVNParentPath-direktivet, for å indikere
denne felles foreldrekatalogen.
Hvis du for eksempel vet at du vil opprette flere
Subversiondepoter i katalogen
/usr/local/svn som vil bli aksessert vie
URLer som http://min.server.com/svn/depot1,
http://min.server.com/svn/depot2 og så videre, kan
du bruke httpd.conf-konfigurasjonssyntaksen
i det følgende eksempelet:
<Location /svn> DAV svn # alle "/svn/foo"-URLer vil kobles til katalogen /usr/local/svn/foo SVNParentPath /usr/local/svn </Location>
Ved å bruke den foregående syntaksen vil Apache delegere
håndteringen av alle URLer der stien begynner med
/svn/ til DAV-tjenesten for Subversion som
deretter vil gå ut i fra at alle elementer i katalogen
spesifisert med SVNParentPath-direktivet
faktisk er Subversiondepoter.
Dette er en spesielt lettvint syntaks fordi i motsetning til
bruken av SVNPath-direktivet trenger du ikke
å starte Apache på nytt for å opprette nye depoter og få dem på
nett.
Pass på at den nye Location-defineringen
ikke overlapper med andre eksporterte plasseringer.
For eksempel, hvis hovedplasseringen av
DocumentRoot eksporteres til
/www, ikke eksporter et Subversiondepot med
<Location /www/repos>.
Hvis en forespørsel kommer for URIen
/www/repos/foo.c, vet ikke Apache om den
skal se etter fila repos/foo.c i
DocumentRoot eller om den skal delegere
jobben til mod_dav_svn for å returnere
foo.c fra Subversiondepotet.
På dette steget bør du sterkt vurdere spørsmålet angående rettigheter. Hvis du har kjørt Apache en stund som din vanlige webserver, har du sannsynligvis en samling med innhold – hjemmesider, skript og lignende. Disse elementene er allerede blitt satt opp med et sett rettigheter som gjør at de fungerer med Apache, eller rettere sagt, som gjør at Apache virker med disse filene. Når Apache brukes som en Subversionserver vil den også trenge de riktige rettighetene for å lese og skrive til Subversiondepotet.
Du må finne fram til et oppsett for rettighetssystemet som
tilfredsstiller Subversions krav uten å rote til noen av de
nettsidene eller skriptene som er installert fra før.
Dette kan bety å forandre rettighetene på Subversiondepotet til
å samsvare med de som brukes av andre ting som Apache håndterer
for deg, eller det kan innebære å bruke direktivene
User og Group i
httpd.conf for å spesifisere at Apache må
kjøre som den brukeren og gruppen som eier Subversiondepotet.
Det er ingen enkelt universalløsning for å sette opp
rettighetene, og hver administrator vil ha forskjellige grunner
for å gjøre ting på en spesiell måte.
Bare husk at rettighetsrelaterte problemer kanskje er det som
oftest blir oversett når et Subversiondepot settes opp for bruk
med Apache.
På dette punktet, hvis du satte opp
httpd.conf til å inneholde noe som
<Location /svn> DAV svn SVNParentPath /usr/local/svn </Location>
…er depotet ditt “anonymt” tilgjengelig for
hele verden.
Inntil du setter opp regler for autentisering og autorisasjon,
vil Subversiondepotene som du gjør tilgjengelig via
Location-direktivet generelt være
tilgjengelig for alle.
Med andre ord,
alle kan bruke Subversionklienten sin til å hente ut e arbeidskopi av en URL i depotet (eller enhver underkatalog under det),
alle kan interaktivt bla igjennom depotets seneste revisjon ved å bare gå til depot-URLen med nettleseren, og
alle kan foreta innlegginger i depotet.
Den enkleste måten å autentisere en klient er via den grunnleggende HTTP-autentiseringsmekanismen som rett og slett bruker et brukernavn og passord for å kontrollere at en bruker er den som hun sier at hun er. Apache har et program kalt htpasswd for å vedlikeholde listen med akseptable brukernavn og passord for de som du vil gi spesialtilgang til Subversiondepotet ditt. La oss gi Sally og Harry tilgang til å legge inn forandringer i depotet. Først må vi legge dem til passordfila.
$ ### Første gang: Bruk -c for å opprette fila $ ### Bruk -m for å bruke MD5-kryptering av passordet, noe som er sikrere $ htpasswd -cm /etc/svn-passord-fil harry New password: ***** Re-type new password: ***** Adding password for user harry $ htpasswd -m /etc/svn-passord-fil sally New password: ******* Re-type new password: ******* Adding password for user sally $
Det neste som du må gjøre er å legge til noen flere
httpd.conf-direktiver inne i
Location-blokken for å fortelle Apache hva
den skal gjøre med den nye passordfila.
AuthType-direktivet spesifiserer hvilken
type autentiseringssystem som skal brukes.
I dette tilfellet vil vi spesifisere
Basic-autentiseringssystemet.
AuthName er et vilkårlig navn som du angir
for autentiseringsområdet.
De fleste nettleserne vil vise dette navnet i et
oppsprettsvindu når nettleseren spør brukeren etter navn og
passord.
Til sist, bruk AuthUserFile-direktivet for
å angi plasseringen til passordfila som du opprettet ved å
bruke htpasswd.
Etter at du har lagt til disse tre direktivene, skal
<Location>-blokken din se ut omtrent
som dette:
<Location /svn> DAV svn SVNParentPath /usr/local/svn AuthType Basic AuthName "Subversiondepot" AuthUserFile /etc/svn-passord-fil </Location>
Denne <Location>-blokken er ikke
komplett enda, og vil ikke gjøre noe nyttig.
Den forteller bare Apache at hver gang det kreves autorisasjon
skal Apache hente et brukernavn og passord fra
Subversionklienten.
Det som mangler her er direktiver som forteller Apache
hvilke typer klientforespørsler som
krever autorisasjon.
Der autorisasjon kreves, vil Apache også forlange
autentisering.
Den enkleste tingen er å beskytte alle forespørsler.
Ved å legge til Require valid-user
forteller vi Apache at alle forespørsler må komme fra en
autentisert bruker:
<Location /svn> DAV svn SVNParentPath /usr/local/svn AuthType Basic AuthName "Subversiondepot" AuthUserFile /etc/svn-passord-fil Require valid-user </Location>
Pass på å lese den neste seksjonen (“Autorisasjonsvalg”) for flere detaljer
om Require-direktivet og andre måter å
sette opp autorisasjonsregler på.
En advarsel:
“HTTP Basic Auth”-passord blir sendt
omtrent i klartekst over nettverket, og er derfor ekstremt
usikkert.
Hvis du er bekymret for passordsniffing, er det best å bruke
en form for SSL-kryptering, så klienter autentiserer via
https:// istedenfor
http://; som et minimum kan du
sette opp Apache til å bruke et selvsignert
sertifikat.[38]
Konsulter Apaches dokumentasjon (og dokmentasjon om OpenSSL)
om hvordan det gjøres.
Forretninger som har behov for å utsette depotene for tilgang fra utsiden av firmabrannveggen bør være bevisst på muligheten for at uautoriserte parter kan “sniffe” nettverkstrafikken deres. SSL minsker sjansen for at denne formen for uønsket oppmerksomhet resulterer i sensitive datalekkasjer.
Hvis en Subversionklient er kompilert for å kunne bruke
OpenSSL, gir det muligheten til å snakke til en Apacheserver
via http://-URLer.
Neon-biblioteket som brukes av Subversionklienten er ikke bare
i stand til å kontrollere serversertifikater, men kan også
oppgi klientsertifikater når den blir spurt om det.
Når klienten og serveren har vekslet SSL-sertifikater og
klart å autentisere hverandre, vil all videre kommunikasjon
bli kryptert med en sesjonsnøkkel.
Det er utenfor temaet for denne boka å beskrive hvordan man lager klient- og serversertifikater, og hvordan Apache settes opp for å bruke dem. Mange andre bøker, inkludert Apaches egen dokumentasjon, beskriver denne oppgaven. Men det som kan bli dekket her er hvordan man vedlikeholder server- og klientsertifikater fra en vanlig Subversionklient.
Mens det snakkes med Apache via
https:// kan en Subversionklient motta to
typer informasjon:
et serversertifikat
krav om et klientsertifikat
Hvis klienten mottar et serversertifikat, må den sjekke at den stoler på sertifikatet – er serveren virkelig den som den påstår at den er? OpenSSL-biblioteket gjør dette ved å undersøke signatøren av serversertifikatet eller godkjenningsinstansen – certifying authority (CA). Hvis OpenSSL ikke er i stand til å automatisk stole på godkjenningsinstansen, eller hvis et annet problem oppstår (som et utgått sertifikat eller at servernavnet ikke stemmer), vil Subversionkommandolinjeklienten vil spørre deg om du vil stole på serversertifikatet uansett:
$ svn list https://server.example.com/repos/prosjekt Error validating server certificate for 'https://server.example.com:443': - The certificate is not issued by a trusted authority. Use the fingerprint to validate the certificate manually! Certificate information: - Hostname: server.example.com - Valid: from Jan 30 19:23:56 2004 GMT until Jan 30 19:23:56 2006 GMT - Issuer: CA, example.com, Sometown, California, US - Fingerprint: 7d:e1:a9:34:33:39:ba:6a:e9:a5:c4:22:98:7b:76:5c:92:a0:9c:7b (R)eject, accept (t)emporarily or accept (p)ermanently?
Denne dialogen skulle se kjent ut, det er hovedsaklig det
samme spørsmålet som du har sett i nettleseren din (som jo
bare er en annen HTTP-klient lik Subversion!).
Hvis du velger det (p)ermanente valget, vil
serversertifikatet bli lagret i ditt private
auth/-område som brukes under kjøring på
omtrent den samme måten som brukernavnet og passordet ditt
blir lagret (se “Lagring av klientlegitimasjon”).
Hvis det blir lagret, vil Subversion automatisk huske dette
sertifikatet i framtidige forhandlinger.
servers-fila som brukes under kjøring
gir deg også muligheten til å la Subversionklienten automatisk
stole på spesifikke godkjenningsinstanser, enten globalt eller på en “per server”-basis.
Sett ganske enkelt variabelen
ssl-authority-files til en
semikolonseparert liste med PEM-kodede sertifikater:
[global] ssl-authority-files = /sti/til/CAcert1.pem;/sti/til/CAcert2.pem
Mange OpenSSL-installasjoner har også et forhåndsdefinert
sett av “standardiserte” godkjenningsinstanser
som det stoles omtrent universelt på.
Får å få Subversionklienten til å automatisk stole på disse
standardautoritetene, sett variabelen
ssl-trust-default-ca til
true.
Mens den snakker med Apache, kan en Subversionklient også motta et krav om et klientsertifikat. Apache spør klienten om å identifisere seg selv: Er klienten virkelig den som den sier at den er? Hvis alt går riktig for seg, sender Subversionklienten tilbake et privat sertifikat signert av en godkjenningsinstans som Apache stoler på. Et klientsertifikat blir vanligvis lagret på disken i et kryptert format, beskyttet av et lokalt passord. Når Subversion mottar denne forespørselen, vil den spørre deg etter både en sti til sertifikatet og passordet som beskytter det:
$ svn list https://server.example.com/repos/prosjekt Authentication realm: https://server.example.com:443 Client certificate filename: /sti/til/mitt/cert.p12 Passphrase for '/sti/til/mitt/cert.p12': ******** …
Legg merke til at klientsertifikatet er en “p12”-fil. For å bruke et klientsertifikat med Subversion, må det være i PKCS#12-format som er en portabel standard. De fleste nettlesere klarer allerede å importere og eksportere sertifikater i dette formatet. En annen mulighet er å bruke kommandolinjeverktøyene i OpenSSL for å konvertere eksisterende sertifikater til PKCS#12.
servers-fila som brukes under kjøring
lar deg automatisere denne forespørselen på en
per-server-basis.
En av eller begge delene informasjon kan bli
beskrevet med kjørevariabler:
[groups] examplehost = server.example.com [examplehost] ssl-client-cert-file = /sti/til/mitt/cert.p12 ssl-client-cert-password = etellerannetpassord
Når du har satt variablene
ssl-client-cert-file og
ssl-client-cert-password, kan
Subversionklienten automatisk svare på en
klientsertifikatforespørsel uten å spørre deg.[39]
På dette punktet har du konfigurert autentisering, men ikke autorisasjon. Apache er i stand til å foreta spørring mot klienter og godkjenne identiteter, men er ikke blitt fortalt hvordan adgangen skal begrenses eller hva disse klientene som har disse identitetene skal få lov til. Denne seksjonen beskriver to strategier for å kontrollere tilgangen til depotene dine.
Den enkleste formen for adgangskontroll er å autorisere visse brukere enten for leseaksess til et depot eller lese/skrive-tilgang til et depot.
Du kan begrense tilgangen til alle depotoperasjoner ved å
legge til Require valid-user-direktivet i
<Location>-blokken.
Ved å bruke det foregående eksempelet vil dette bety at bare
klienter som påstår å være enten harry
eller sally og som oppga korrekt passord
for de respektive brukernavnene vil få tilgang til å gjøre
noe med
Subversiondepotet:
<Location /svn> DAV svn SVNParentPath /usr/local/svn # hvordan brukeren autentiseres AuthType Basic AuthName "Subversiondepot" AuthUserFile /sti/til/brukerfil # bare autentiserte brukere får tilgang til depotet Require valid-user </Location>
Noen ganger trenger du ikke å ha en like streng
adgangskontroll.
Depotet til Subversions kildekodedepot på http://svn.collab.net/repos/svn tillater alle i verden
å utføre leseoperasjoner i depotet (som å hente ut
arbeidskopier og bla gjennom depotet med en nettleser), men
begrenser alle skriveoperasjoner til autentiserte brukere.
For å få til denne typen selektiv begrensning kan du bruke
konfigurasjonsdirektivene Limit og
LimitExcept.
I likhet med Location-direktivet har disse
blokkene start- og sluttelementer, og du legger dem inn i
<Location>-blokken.
Parametrene som brukes sammen med direktivene
Limit og LimitExcept er
typer av HTTP-forespørsler som blir påvirket av den blokken.
Hvis du for eksempel vil forby all tilgang til depotet unntatt
de foreløpig støttede leseoperasjonene, vil du bruke
LimitExcept-direktivet sammen med
forespørselstypene GET,
PROPFIND, OPTIONS og
REPORT.
Deretter plasseres det tidligere nevnte direktivet
Require valid-user inne i
<LimitExcept>-blokken istedenfor bare
inne i <Location>-blokken.
<Location /svn>
DAV svn
SVNParentPath /usr/local/svn
# hvordan brukeren skal autentiseres
AuthType Basic
AuthName "Subversiondepot"
AuthUserFile /sti/til/brukerfil
# For alle andre operasjoner enn disse kreves en autentisert bruker.
<LimitExcept GET PROPFIND OPTIONS REPORT>
Require valid-user
</LimitExcept>
</Location>
Dette er bare noen få enkle eksempler.
For informasjon som går mer i dybden om Apaches
adgangskontroll og Require-direktivet, ta
en kikk på Security-seksjonen i
dokmentasjonssamlingen for Apache på http://httpd.apache.org/docs-2.0/misc/tutorials.html.
Det er mulig å sette opp mer finjusterte rettigheter ved å bruke en annen Apache httpd-modul, mod_authz_svn. Denne modulen tar for seg de forskjellige “uklare” URLene som blir sendt fra klienten til serveren, spør mod_dav_svn om å dekode dem og avgjør etter dette om forespørsler skal nektes, basert på tilgangsregler som er definert i en konfigurasjonsfil.
Hvis du har bygget Subversion fra kildekode, blir
mod_authz_svn automatisk bygget og
installert sammen med mod_dav_svn.
Mange binærdistribusjoner installerer den også automatisk.
For å kontrollere at den er riktig installert, pass på at den
kommer rett etter mod_dav_svns
LoadModule-direktiv i
httpd.conf:
LoadModule dav_module modules/mod_dav.so LoadModule dav_svn_module modules/mod_dav_svn.so LoadModule authz_svn_module modules/mod_authz_svn.so
For å aktivere denne modulen må du sette opp
Location-blokken til å bruke
AuthSVNAccessFile-direktivet, som
spesifiserer en fil som inneholder regler for rettigheter til
stier i depotene dine.
(Vil vil diskutere formatet på denne fila om et
øyeblikk.)
Apache er fleksibel, så du har muligheten til å sette opp blokken etter ett av tre generelle mønstre. For å begynne, velg ett av disse grunnleggende konfigurasjonsmønstrene. (Eksemplene nedenfor er veldig enkle; se på Apaches egen dokumentasjon for mange flere detaljer om autentiserings- og autorisasjonsvalg i Apache.)
Den enkleste blokken gir tilgang til alle. I dette scenariet sender Apache aldri autentiseringsforespørsler, så alle brukerne blir behandlet som anonyme.
Eksempel 6.1. Et eksempel på oppsett for anonym tilgang.
<Location /repos>
DAV svn
SVNParentPath /usr/local/svn
# våre regler for tilgang
AuthzSVNAccessFile /sti/til/aksessfil
</Location>
I den andre enden av paranoiaskalaen kan du sette opp
blokken din til å forlange autentisering av alle.
Alle klienter må oppgi legitimasjon for å identifisere seg.
Blokken krever betingelsesløst autentisering via
Require valid-user-direktivet og definerer
en autentiseringsmåte.
Eksempel 6.2. Eksempel på oppsett for autentisert tilgang.
<Location /repos>
DAV svn
SVNParentPath /usr/local/svn
# våre regler for tilgang
AuthzSVNAccessFile /sti/til/aksessfil
# kun autentiserte brukere får tilgang til depotet
Require valid-user
# hvordan brukeren skal autentiseres
AuthType Basic
AuthName "Subversiondepot"
AuthUserFile /sti/til/brukerfil
</Location>
Et tredje, meget populært mønster er å tillate en
kombinasjon av autentisert og anonym tilgang.
For eksempel ønsker mange administratorer å tillate alle
anonyme brukere å lese visse depotkataloger, men vil at kun
autentiserte brukere kan lese (eller skrive til) mer sensitive
områder.
Med dette oppsettet starter alle brukerne med å aksessere
depotet anonymt.
Hvis reglene for adgangskontrollen på et eller annet punkt
krever et brukernavn, vil Apache forlange autentisering av
klienten.
For å gjøre dette, bruker du både Satisfy
Any og Require
Valid-user-direktivene sammen.
Eksempel 6.3. Eksempel på oppsett for blandet autentisert/anonym tilgang.
<Location /repos>
DAV svn
SVNParentPath /usr/local/svn
# våre regler for tilgang
AuthzSVNAccessFile /sti/til/aksessfil
# prøv først anononym tilgang og fall tilbake på skikkelig
# autentisering hvis det er nødvendig.
Satisfy Any
Require valid-user
# hvordan brukeren skal autentiseres
AuthType Basic
AuthName "Subversiondepot"
AuthUserFile /sti/til/brukerfil
</Location>
Once you've settled on one of these three
basic httpd.conf templates, you need to
create your file containing access rules for particular
paths within the repository. This is described in
“Path-Based Authorization”.
mod_dav_svn-modulen går gjennom en masse arbeid for å forsikre seg om at dataene som du har markert som “uleselig” ikke blir lekket ved en ulykke. Dette betyr at den må passe nøye på alle stiene og filinnhold som blir returnert av kommandoer som svn checkout eller svn update. Hvis disse kommandoene kommer over en sti som ikke er lesbar i følge en eller annen autorisasjonsregel, blir stien vanligvis totalt utelatt. Når det gjelder tråling av historien og navneskifter – for eksempel å kjøre en kommando som svn cat -r GAMMELREV foo.c på en fil som skiftet navn for lenge siden – vil trålingen av navneskiftet ganske enkelt stoppe hvis et av objektets tidligere navn blir anslått til å være beskyttet mot lesing.
Alle disse kontrollene av stier kan noen ganger være
ganske dyrekjøpte, spesielt i tilfellet med svn
log.
Når det hentes en liste med revisjoner, ser serveren på
alle stier som har forandret seg i hver revisjon og sjekker om
stien er leselig.
Hvis en uleselig sti blir funnet, utelates den fra listen med
forandrede stier i revisjonen (som man vanligvis ser med
--verbose-valget), og hele loggmeldingen blir
utelatt.
Dette kan føre til at mye tid blir brukt på revisjoner som
påvirker et stort antall filer.
Dette er prisen for sikkerhet:
Selv om du ikke har satt opp en modul som
mod_authz_svn i det hele tatt, ber
mod_dav_svn-modulen fortsatt Apache
httpd om å kjøre autorisasjonssjekker på
hver eneste sti.
mod_dav_svn-modulen har ingen formening om
hvilke autorisasjonsmoduler som er installert, så alt den kan
gjøre er å be Apache om å utføre alle som kan
eksistere.
På den annen side finnes det en slags nødløsning for dette, en som lar deg bytte
sikkerhetsfunksjonalitet mot hastighet.
Hvis du ikke gjennomfører noen form for katalogbasert
autorisasjon (det vil si at mod_authz_svn
eller en lignende modul ikke brukes) kan du slå av alt av
stikontroller.
Bruk SVNPathAuthz-direktivet i
httpd.conf-fila:
Eksempel 6.4. Slå av alle filstikontroller
<Location /repos>
DAV svn
SVNParentPath /usr/local/svn
SVNPathAuthz off
</Location>
SVNPathAuthz-direktivet er
“on” (aktivt) som standard.
Når det settes til “off”, slås all stibasert
autorisasjonskontroll av; mod_dav_svn lar
være å utføre autorisasjonssjekker på hver sti som den
finner.
Vi har dekket mesteparten av autentiserings- og autorisasjonsvalg for Apache og mod_dav_svn. Men det er noen andre fine ting som Apache tilbyr.
En av de nyttigste fordelene med å bruke et
Apache/WebDAV-oppsett for Subversiondepotet ditt er at de
yngste revisjonene av de versjonerte filene og katalogene er
øyeblikkelig tilgjengelig for visning gjennom en vanlig
nettleser.
Siden Subversion bruker URLer til å identifisere versjonerte
ressurser, kan disse URLene for HTTP-basert depottilgang bli
skrevet direkte inn i en nettleser.
Nettleseren vil foreta en HTTP
GET-forespørsel for denne URLen, og
avhengig om denne URLen representerer en versjonert katalog
eller fil vil mod_dav_svn svare med en katalogutlisting eller
innholdet av en fil.
Siden URLene ikke inneholder noen informasjon om hvilken versjon av ressursen du ønsker å se, vil mod_dav_svn alltid svare med den yngste versjonen. Denne funksjonaliteten har den ytterst stilfulle bieffekten at du kan sende Subversion-URLer til mottakere som referanser til dokumenter, og disse URLene vil alltid peke til den nyeste versjonen av dette dokumentet. Du kan selvfølgelig også til og med bruke URLene som hyperlinker fra andre hjemmesider.
When browsing a Subversion repository, the web browser
gets a clue about how to render a file's contents by
looking at the Content-Type: header
returned in Apache's response to the
HTTP GET request. The value of this
header is some sort of MIME type. By default, Apache will
tell the web browsers that all repository files are of
the “default” MIME type,
typically text/plain. This can be
frustrating, however, if a user wishes repository files to
render as something more meaningful — for example,
it might be nice to have a foo.html file
in the repository actually render as HTML when
browsing.
To make this happen, you only need to make sure that
your files have the
proper svn:mime-type set. This is
discussed in more detail in
“File Content Type”,
and you can even configure your client to automatically
attach proper svn:mime-type properties
to files entering the repository for the first time; see
“Automatic Property Setting”.
So in our example, if one were to set
the svn:mime-type property
to text/html on
file foo.html, then Apache would
properly tell your web browser to render the file as
HTML. One could also attach
proper image/* mime-type properties to
images, and by doing this, ultimately get an entire web
site to be viewable directly from a repository! There's
generalyl no problem with doing this, as long as the
website doesn't contain any dynamically-generated
content.
Vanligvis vil du få mer ut av URLer til versjonerte
filer – det er jo der alt det interessante innholdet har for
vane å ligge.
Men noen ganger må du bla direkte gjennom en katalogliste i
Subversion, og da legger du merke til at den genererte
HTML-en som brukes i utlistingen er ganske enkel, og i
hvertfall ikke ment å være en nytelse for øyet.
For å gjøre det mulig å tilpasse disse katalogvisningene,
har Subversion en XML-basert innholdsfunksjonalitet.
Et enkelt SVNIndexXSLT-direktiv i
depotets Location-blokk i
httpd.conf vil instruere mod_dav_svn
til å generere XML-data når den viser en katalogutlisting og
referere til XSLT-stilsettet som du har valgt:
<Location /svn> DAV svn SVNParentPath /usr/local/svn SVNIndexXSLT "/svnindex.xsl" … </Location>
Ved å bruke SVNIndexXSLT-direktivet og
et kreativt XSLT-stilsett, kan du få katalogutlistingene til
å følge fargevalgene og utseendet til andre deler av
hjemmesiden din.
Eller du kan bruke eksempelstilsettene som ligger i
Subversionkildekodens
tools/xslt-katalog.
Husk på at stien som gis til
SVNIndexXSLT-direktivet egentlig er en URL
— nettlesere må være i stand til å lese stilsettene dine for
å kunne bruke dem!
If you're serving a colllection of repositories from a
single URL via the SVNParentPath
directive, then it's also possible to have Apache display
all available repositories to a web browser. Just
activate the SVNListParentPath
directive:
<Location /svn> DAV svn SVNParentPath /usr/local/svn SVNListParentPath on … </Location>
If a user now points her web browser to the
URL http://host.example.com/svn/, she'll
see list of all Subversion repositories sitting
in /usr/local/svn. Obviously, this can
be a security problem, so this feature is turned off by
default.
Because Apache is an HTTP server at heart, it contains
fantastically flexible logging feature. It's beyond the
scope of this book to discuss all ways logging can be
configured, but we should point out that even the most
generic httpd.conf file will cause
Apache to produce two logs:
error_log
and access_log. These logs may appear
in different places, but are typically created in the
logging area of your Apache installation. (On Unix, they
often live
in /usr/local/apache2/logs/.)
The error_log describes any interal
errors that Apache runs into as it works.
The access_log file records every
incoming HTTP request received by Apache. This makes it
easy to see, for example, which IP addresses Subversion
clients are coming from, how often particular clients use
the server, which users are authenticating properly, and
which requests succeed or fail.
Unfortunately, because HTTP is a stateless protocol,
even the simplest Subversion client operation generates
multiple network requests. It's very difficult to look at
the access_log and deduce what the
client was doing — most operations look like a series
of cryptic PROPPATCH, GET,
PUT, and REPORT
requests. To make things worse, many client operations send
nearly-identical series of requests, so it's even harder to
tell them apart.
mod_dav_svn, however, can come to
your aid. By activating an “operational
logging” feature, you can
ask mod_dav_svn to create a separate log
file describing what sort of high-level operations your
clients are performing.
To do this, you need to make use of
Apache's CustomLog directive (which is
explained in more detail in Apache's own documentation).
Be sure to invoke this
directive outside of your
Subversion Location block:
<Location /svn>
DAV svn
…
</Location>
CustomLog logs/svn_logfile "%t %u %{SVN-ACTION}e" env=SVN-ACTION
In this example, we're asking Apache to create a special
logfile svn_logfile in the standard
Apache logs directory.
The %t and %u
variables are replaced by the time and username of the
request, respectively. The really important part are the
two instances of SVN-ACTION.
When Apache sees that variable, it substitutes the value of
the SVN-ACTION environment variable,
which is automatically set by mod_dav_svn
whenever it detects a high-level client action.
So instead of having to interpret a
traditional access_log like
this:
[26/Jan/2007:22:25:29 -0600] "PROPFIND /svn/calc/!svn/vcc/default HTTP/1.1" 207 398 [26/Jan/2007:22:25:29 -0600] "PROPFIND /svn/calc/!svn/bln/59 HTTP/1.1" 207 449 [26/Jan/2007:22:25:29 -0600] "PROPFIND /svn/calc HTTP/1.1" 207 647 [26/Jan/2007:22:25:29 -0600] "REPORT /svn/calc/!svn/vcc/default HTTP/1.1" 200 607 [26/Jan/2007:22:25:31 -0600] "OPTIONS /svn/calc HTTP/1.1" 200 188 [26/Jan/2007:22:25:31 -0600] "MKACTIVITY /svn/calc/!svn/act/e6035ef7-5df0-4ac0-b811-4be7c823f998 HTTP/1.1" 201 227 …
… you can instead peruse a much more
intelligible svn_logfile like this:
[26/Jan/2007:22:24:20 -0600] - list-dir '/' [26/Jan/2007:22:24:27 -0600] - update '/' [26/Jan/2007:22:25:29 -0600] - remote-status '/' [26/Jan/2007:22:25:31 -0600] sally commit r60
Mye av funksjonaliteten som Apache tilbyr i sin rolle som
en robust webserver kan i tillegg bli satt opp for økt funksjonalitet eller sikkerhet
i Subversion.
Subversion kommuniserer med Apache ved bruk av Neon, som er et
generelt HTTP/WebDAV-bibliotek med støtte for mekanismer som
SSL (Secure Socket Layer, som
tidligere diskutert).
Hvis Subversionklienten din er bygget med støtte for SSL, kan
den aksessere Apacheservere via
https://.
Like nyttige funksjonaliteter i forholdet mellom Apache og Subversion er muligheten til å spesifisere en spesiell port (istedenfor den vanlige HTTP-porten 80) eller virtuelle domenenavn som Subversiondepoter skal aksesseres via, eller muligheten til å aksessere depotet gjennom en HTTP-mellomserver. Alle disse tingene støttes av Neon, så denne støtten får Subversion helt gratis.
Til sist, fordi mod_dav_svn forstår et utvalg av WebDAV/DeltaV-protokollen, er det mulig å aksessere depotet vie tredjeparts DAV-klienter. De fleste moderne operativsystemer (Win32, OS X og Linux) har muligheten til å montere en DAV-server som en standard delt ressurs på nettverket. Dette er et komplisert tema; for detaljer, les Tillegg C, WebDAV and Autoversioning.
Both Apache and svnserve are capable of granting (or denying) permissions to users. Typically this is done over the entire repository: a user can read the repository (or not), and she can write to the repository (or not). It's also possible, however, to define finer-grained access rules. One set of users may have permssion to write to a certain directory in the repository, but not others; another directory might not even be readable by all but a few special people.
Both servers use a common file format to describe these
path-based access rules. In the case of Apache, one needs to
load the mod_authz_svn module and then add
the AuthzSVNAccessFile directive (within
the httpd.conf file) pointing to your own
rules-file. (For a full explanation, see
“Adgangskontroll på katalognivå”.) If
you're using svnserve, then you need to make
the authz-db variable
(within svnserve.conf) point to your
rules-file.
Once your server knows where to find your rules-file, it's time to define the rules.
Syntaksen til fila er den samme kjente som brukes
av svnserve.conf og konfigurasjonsfilene
som brukes under kjøring.
Linjer som starter med en hash (#)
ignoreres.
I sin enkleste form navngir hver seksjon et depot og
en sti i det, og de autentiserte brukernavnene er valgnavnene innenfor hver seksjon.
Verdien til hvert valg beskriver brukerens adgangsnivå til
depotstien:
Enten r (kun lesing) eller
rw (både skriving og lesing).
Hvis brukeren ikke nevnes i det hele tatt, gis ingen tilgang i
det hele tatt.
For å være mer spesifikk:
Verdien til seksjonsnavnene er enten på formen
[depotnavn:sti] eller på formen
[sti].
Hvis du bruker SVNParentPath-direktivet, er det
viktig å spesifisere depotnavnet i seksjonene dine.
Hvis du utelater dem, vil en seksjon som
[en/katalog] samsvare med stien
en/katalog i hvert
eneste depot.
Hvis du bruker imidlertid bruker
SVNPath-direktivet, er det greit å bare
definere stier i seksjonene dine — når alt kommer til alt, finnes
det bare ett depot.
[calc:/branches/calc/bug-142] harry = rw sally = r
I dette første eksempelet har brukeren
harry full lese- og skrivetilgang i katalogen
/branches/calc/big-142 i
calc-depotet, men brukeren
sally har kun lesetilgang.
Alle andre brukere nektes tilgang til depotet.
Alle tilganger arves selvfølgelig fra foreldrekataloger til underkataloger. Dette betyr at vi kan spesifisere en underkatalog med en forskjellig adgangsregel for Sally:
[calc:/branches/calc/bug-142] harry = rw sally = r # gi sally skrivetilgang kun til underkatalogen «testing» [calc:/branches/calc/bug-142/testing] sally = rw
Nå kan Sally skrive til underkatalogen
testing på grenen, men kan fortsatt bare lese
andre deler.
Imens fortsetter Harry å ha både lese- og skrivetilgang til hele
grenen.
Det er også mulig å eksplisitt nekte adgang til noen ved hjelp av arveregler, ved å sette brukernavnvariabelen til ingenting:
[calc:/branches/calc/bug-142] harry = rw sally = r [calc:/branches/calc/bug-142/hemmelig] harry =
I dette eksempelet har Harry både lese- og skrivetilgang til
hele bug-142-treet, men har absolutt ingen
tilgang i det hele tatt til underkatalogen
hemmelig innenfor det.
Tingen å huske på er at den mest spesifikke stien alltid samsvarer først. Serveren prøver å få selve stien til å stemme, deretter forelderen til stien, så forelderen til den, og så videre. Netteffekten er at det å nevne en spesifikk sti i aksessfila alltid vil overstyre alle rettigheter som er arvet fra foreldrekataloger.
Som standard har ingen noen tilgang til depotet i det hele
tatt.
Det betyr at hvis du starter med en tom fil, vil du sannsynligvis
ønske å i det minste gi leserettigheter til alle brukere ved roten
av depotet.
Du kan gjøre dette ved å bruke asteriskvariabelen
(*), som betyr “alle
brukere”:
[/] * = r
Dette er et vanlig oppsett; legg merke til at det ikke nevnes noen depotnavn i seksjonsnavnet. Dette gjør alle depotene fullstendig lesbare for alle brukerne. Når alle brukerne har lesetilgang til depotene, kan du gi eksplisitt lese/skrive-rettigheter til visse brukere i spesifikke underkataloger inne i spesifikke depoter.
Asteriskvariabelen (*) er også verdt litt
spesiell omtale her:
Det er det eneste mønsteret som samsvarer med
en anonym bruker.
Hvis du har satt opp serverblokken din til å tillate en blanding
av anonym og autentisert tilgang, starter alle brukere med å
kommunisere anonymt.
Serveren ser etter en *-verdi for stien som
blir aksessert; hvis den ikke finner noen, forlanger den skikkelig
autentisering fra klienten.
Aksessfila lar deg også definere hele grupper med brukere,
ganske likt /etc/group på
Unix-systemer:
[groups] calc-utviklere = harry, sally, joe paint-utviklere = frank, sally, jane alle = harry, sally, joe, frank, sally, jane
Grupper kan bli gitt tilgang akkurat som brukere.
Skill mellom dem ved å sette en krøllalfa (@)
foran gruppenavnet:
[calc:/prosjekter/calc] @calc-utviklere = rw [paint:/prosjekter/paint] @paint-utviklere = rw jane = r
Grupper kan også bli definert til å inneholde andre grupper:
[groups] calc-utviklere = harry, sally, joe paint-utviklere = frank, sally, jane alle = @calc-utviklere, @paint-utviklere
…og det er omtrent det som er å si om den saken.
Du har sett hvordan et depot kan bli aksessert på mange forskjellige måter. Men er det mulig – eller trygt – for depotet å bli aksessert på flere forskjellige måter samtidig?
Til enhver tid kan disse prosessene kreve lese- og skriveaksess til depotet:
vanlige brukere som bruker en Subversionklient (som seg
selv) for å aksessere depotet direkte via file:///-URLer,
vanlige brukere som kobler seg til private SSH-startede svnserve-prosesser (som kjører som brukeren selv) som aksesserer depotet,
en svnserve-prosess – enten en daemon eller en startet av inetd – som kjører som en spesiell bruker,
en Apache httpd-process, som kjører som en spesiell bruker.
Det vanligste problemer administratorer får med å gjøre er
eierskap og rettigheter for depotene.
Har alle prosesser (og brukere) i den forrige listen rettigheter
til å lese og skrive til Berkeley DB-filene?
Hvis du har et Unix-lignende operativsystem er en grei måte å plassere hver eneste potensiell
depotbruker i en ny svn-gruppe og gjøre denne
gruppen til eier av hele depotet.
Men til og med dette er ikke nok, fordi en prosess kan skrive til
databasefilene med en utrivelig umask – en som forbyr tilgang for
andre brukere.
Så det neste steget etter å sette opp en felles gruppe for
depotbrukerne er å tvinge alle prosesser som aksesserer depotet
til å bruke en fornuftig umask.
For brukere som aksesserer depotet direkte kan du kapsle
svn-programmet inn i et skript som først setter
umask 002 og deretter kjører det egentlige
svn-programmet.
Du kan skrive et lignende innkapslingsskript for
svnserve-programmet, og legge til en
umask 002 til Apaches eget oppstartsskript
apachectl.
For eksempel:
$ cat /usr/bin/svn #!/bin/sh umask 002 /usr/bin/svn-real "$@"
Et annet vanlig problem oppstår ofte på Unix-lignende
systemer.
Når et depot blir brukt, lager Berkeley DB noen ganger nye
loggfiler for å journalføre det som den gjør.
Selv om hele depotet eies av svn-gruppen, vil
ikke disse nye filene nødvendigvis eies av den samme gruppen, som
i sin tur fører til flere rettighetsproblemer for brukerne.
En grei måte å ordne dette på er å sette gruppens SUID-bit på
db-katalogen i depotet.
Dette gjør at alle nyopprettede loggfiler tilhører den samme
gruppen som foreldrekatalogen.
Når du har gjort alt dette, skal depotet være tilgjengelig for alle de nødvendige prosessene. Det kan se rotete og komplisert ut, men problemene med å ha flere brukere som skal dele skrivetilgang til vanlige filer er klassiske og må løses på måter som ikke er spesielt elegante.
Heldigvis vil de fleste administratorer ikke ha behov for et
slikt komplisert oppsett.
Brukere som ønsker tilgang til depoter som er på den samme
maskinen er ikke begrenset til å bruke URLer av
file://-typen, de kan vanligvis kontakte Apache
HTTP-serveren eller svnserve ved å bruke
localhost som servernavnet i
http://- og svn://-URLene.
Og det å vedlikeholde flere serverprosesser for
Subversiondepotene har en tendens til å skaffe mer hodebry enn
nødvendig.
Vi anbefaler at du velger den serveren som passer best til
dine behov og holder deg til den!
[35] Se RFC 2195.
[36] Note that using any sort of svnserve-enforced access control at all is a bit pointless; the user already has direct access to the repository database.
[37] Det er noe som de virkelig hater.
[38] Selv om selvsignerte serversertifikater også er sårbare for “mann-i-midten”-angrep, vil et slikt angrep for en vanlig observatør være mye vanskeligere å få til, sammenlignet med å sniffe ubeskyttede passord
[39] Mer sikkerhetsbevisste folk vil kanskje ikke lagre
klientsertifikatpassordet i kjørefila
servers.
[40] På den tiden ble den kalt “ViewCVS”.
[41] A common theme in this book!
Innholdsfortegnelse
### TODO: Chapter opening ###
### TODO: Gut the runtime config stuff like I did the property stuff, making larger topical sections to which the runtime config stuff generally refers. Like already exists for external diff/diff3, add, for example, a section on external editors. ###
Subversion inneholder mange valg for å modifisere oppførselen under kjøring, og dette kan kontrolleres av brukeren. Mange av disse valgene er av typen som en bruker ønsker å bruke ved alle Subversionoperasjoner. Så, istedenfor å tvinge brukere til å huske kommandolinjeargumenter for å spesifisere disse valgene, og å bruke dem for hver eneste operasjon som utføres, bruker Subversion konfigurasjonsfiler som er lagt for seg selv i et eget konfigurasjonsområde.
Subversions konfigurasjonsområde er et to-lags hierarki med valgnavn og deres verdier. Vanligvis koker dette ned til en spesiell katalog som inneholder konfigurasjonsfiler (første lag) som er rene tekstfiler i standard INI-format (med “seksjoner” som er det andre laget). Disse filene kan enkelt redigeres med favoritt-tekstbehandleren din (som for eksempel Emacs eller vi), og inneholder direktiver som leses av klienten for å anslå hvilken av de valgfrie oppførslene brukeren foretrekker.
Den første gangen kommandolinjeklienten
svn kjøres, lages et eget
konfigurasjonsområde for brukeren.
På Unix-lignende systemer opptrer dette området som en katalog
kalt .subversion i brukerens hjemmekatalog.
På Win32-systemer oppretter Subversion en katalog kalt
Subversion, vanligvis i Application
Data-området til brukerens profilkatalog (som
forresten er en skjult katalog).
På denne plattformen varierer imidlertid den eksakte
plasseringen fra system til system, og bestemmes av
registryen.[42]
Vi vil referere til brukerkonfigurasjonsområdet ved å bruke
navnet som brukes under Unix,
.subversion.
I tillegg til konfigurasjonsområdet som brukes på
brukernivå, kjenner også Subversion til eksistensen av et
konfigurasjonsområde som gjelder for hele systemet på maskinen.
Dette gir systemadministratorer muligheten til å opprette
standardinnstillinger for alle brukerne på en gitt maskin.
Legg merke til at det felles konfigurasjonsområdet på maskinen
ikke alene bestemmer standardoppførselen – oppsettet i konfigurasjonsområdet for
brukeren overstyrer de som er i området som er felles for alle
brukerne, og kommandolinjeargumenter som gis til
svn-programmet har det siste ordet hva
oppførsel angår.
På Unix-lignende plattformer forventes det at
konfigurasjonsområdet som er felles for alle brukerne er i
katalogen /etc/subversion; på MS
Windows-maskiner letes det etter en
Subversion-katalog i det felles Application Data-området
(og igjen, som spesifisert i Windowsregistryen).
Ulikt med det brukerbaserte tilfellet, vil ikke
svn-klienten prøve å opprette et nytt
maskinkonfigurasjonsområde.
Konfigurasjonsområdet for hver bruker inneholder for tiden
tre filer – to konfigurasjonsfiler (config
og servers) og en
README.txt-fil som beskriver INI-formatet.
På tidspunktet de ble laget, inneholder filene standardverdier
for alle valgene som Subversion støtter.
For det meste er de kommentert ut og gruppert sammen med
beskrivelser om hvordan verdiene påvirker oppførselen til
Subversion.
For å forandre en viss oppførsel, trenger du bare å forandre
verdien til et valg med en vanlig teksteditor.
Hvis du en eller annen gang du vil ha tilbake
standardinnstillingene, kan du fjerne (eller skifte navn på)
katalogen med konfigurasjonsfilene og deretter kjøre noen
uskyldige svn-kommandoer som for eksempel
svn --version som oppretter en ny
konfigurasjonskatalog som inneholder
standardinnstillingene.
Brukerkonfigurasjonsområdet inneholder også et lager med
autentiseringsdata.
auth-katalogen inneholder et sett med
underkataloger som inneholder deler av lagret informasjon som
brukes av Subversions forskjellige autentiseringsmetoder.
Denne katalogen er laget på en måte som gjør at kun den ene
brukeren har tillatelse til å lese innholdet.
I tillegg til det vanlige INI-baserte konfigurasjonsområdet, kan Subversionklienter som kjører på MS Windows-plattformer også bruke registryen til å lagre konfigurasjonsdataene. Valgnavnene og deres verdier er de samme som i INI-filene. “fil/seksjon”-hierarkiet blir også tatt vare på, selv om det noteres på en litt annen måte – i dette skjemaet er filer og seksjoner kun nivåer i nøkkeltreet i registryen.
Subversion ser etter konfigurasjonsverdier for hele systemet
under nøkkelen
HKEY_LOCAL_MACHINE\Software\Tigris.org\Subversion.
For eksempel, valget global-ignores som er i
miscellany-seksjonen i
config-fila finnes i
HKEY_LOCAL_MACHINE\Software\Tigris.org\Subversion\Config\Miscellany\global-ignores.
Konfigurasjonsverdier for hver enkelt bruker bør lagres under
HKEY_CURRENT_USER\Software\Tigris.org\Subversion.
Registry-based configuration options are parsed before their file-based counterparts, so are overridden by values found in the configuration files. Med andre ord er dette rekkefølgen konfigurasjonen blir prioritert på et MS Windows-system:
Valg på kommandolinja
Brukerbaserte INI-filer
Brukerbaserte verdier i registryen
INI-filer som gjelder for hele systemet
Registry-verdier for hele systemet
I tillegg støtter ikke Windows-registryen at noe kan
“kommenteres ut”.
Subversion vil imidlertid ignorere valg der navnet begynner med
et hash-tegn
(#),
Dette lar deg kommentere bort et Subversionvalg uten å slette
hele nøkkelen fra registryen, noe som selvfølgelig gjør det
lettere å hente tilbake dette valget.
Kommandolinjeklienten svn vil aldri prøve
å skrive til Windowsregistryen, og vil ikke prøve å lage et område der.
Du kan lage nøklene du trenger ved å bruke
REGEDIT-programmet.
Alternativt kan du lage en .reg-fil og
deretter dobbeltklikke på denne fila i Utforskeren, noe som vil
flette dataene inn i registryen.
Eksempel 7.1. Eksempel på registryposter i ei
.reg-fil.
REGEDIT4 [HKEY_LOCAL_MACHINE\Software\Tigris.org\Subversion\Servers\groups] [HKEY_LOCAL_MACHINE\Software\Tigris.org\Subversion\Servers\global] "#http-proxy-host"="" "#http-proxy-port"="" "#http-proxy-username"="" "#http-proxy-password"="" "#http-proxy-exceptions"="" "#http-timeout"="0" "#http-compression"="yes" "#neon-debug-mask"="" "#ssl-authority-files"="" "#ssl-trust-default-ca"="" "#ssl-client-cert-file"="" "#ssl-client-cert-password"="" [HKEY_CURRENT_USER\Software\Tigris.org\Subversion\Config\auth] "#store-passwords"="yes" "#store-auth-creds"="yes" [HKEY_CURRENT_USER\Software\Tigris.org\Subversion\Config\helpers] "#editor-cmd"="notepad" "#diff-cmd"="" "#diff3-cmd"="" "#diff3-has-program-arg"="" [HKEY_CURRENT_USER\Software\Tigris.org\Subversion\Config\tunnels] [HKEY_CURRENT_USER\Software\Tigris.org\Subversion\Config\miscellany] "#global-ignores"="*.o *.lo *.la #*# .*.rej *.rej .*~ *~ .#* .DS_Store" "#log-encoding"="" "#use-commit-times"="" "#no-unlock"="" "#enable-auto-props"="" [HKEY_CURRENT_USER\Software\Tigris.org\Subversion\Config\auto-props]
Det foregående eksemplet viser innholdet av ei
.reg-fil som inneholder noen av de mest
brukte konfigurasjonsvalgene og deres standardverdier.
Legg merke til tilstedeværelsen av både valg som gjelder for hele systemet
(for valg relatert til mellomservere i nettverket og
innstillinger for hver enkelt bruker (tekstbehandlingsprogrammer
og lagring av passord, blant annet).
Legg også merke til at alle valgene er kommentert ut.
Du trenger bare å fjerne hash-tegnet (#) fra
begynnelsen av valgnavnene og sette inn de verdiene du
vil.
### TODO: Rework and move this section to the Reference ###
I denne seksjonen vil vi diskutere de spesifikke konfigurasjonsvalgene som brukes av Subversion under kjøring.
servers-fila inneholder valg for
konfigurering av Subversion og som er relatert til
nettverkslag.
Det er to spesielle seksjonsnavn i denne fila –
groups og global.
groups-seksjonen er hovedsaklig en tabell
med kryssreferanser.
Nøklene i denne seksjonen er navnene til andre seksjoner i
fila; verdiene deres er globs
– tekstbaserte nøkkelord som kan inneholde
jokertegn — som blir sammenlignet med servernavnene til maskinen som det sendes
Subversionforespørsler til.
[groups] beanie-babies = *.red-bean.com collabnet = svn.collab.net [beanie-babies] … [collabnet] …
Når Subversion brukes over nettverket, forsøker den å
matche navnet til serveren som den prøver å nå med et
gruppenavn under groups-seksjonen.
Hvis dette stemmer, ser Subversion etter en seksjon i
servers-fila som stemmer med navnet i den
samsvarende gruppens navn.
Fra denne seksjonen leser den det faktiske
nettverksoppsettet.
global-seksjonen inneholder
innstillingene som er ment for alle serverne som ikke
samsvarer med en av søkestrengene i
groups-seksjonen.
Valgene som er tilgjengelig i denne seksjonen er nøyaktig de
samme som de som er gyldig for de andre serverseksjonene i
fila (selvfølgelig unntatt den spesielle
groups-seksjonen), og er som følger:
http-proxy-hostDette spesifiserer servernavnet til mellomserveren som de HTTP-baserte Subversionforespørslene som du foretar må gå gjennom. Standardverdien er en tom verdi, noe som betyr at Subversion ikke vil prøve å rute HTTP-forespørsler gjennom en mellomserver og vil istedenfor prøve å kontakte målmaskinen direkte.
http-proxy-portDette spesifiserer hvilket portnummer som skal brukes på mellomserveren. Standardverdien er en tom verdi.
http-proxy-usernameSpesifiserer brukernavnet som oppgis til mellomserveren. Standardverdien er tom.
http-proxy-passwordSpesifiserer passordet som oppgis til mellomserveren. Standardverdien er tom.
http-timeoutDette spesifiserer antall sekunder det ventes på
respons fra serveren.
Hvis du opplever problemer med en sen
nettvorksforbindelse som fører til at
Subversionoperasjoner blir avbrutt, bør du øke verdien
for dette valget.
Standardverdien er 0, som ber det
underliggende HTTP-biblioteket, Neon, til å bruke
standardverdien for tidsavbrudd.
http-compressionDette spesifiserer om Subversion skal prøve å
komprimere nettverksforespørsler som blir gjort til
servere som er klargjort for DAV.
Srandardverdien er yes (selv om
komprimering bare vil utføres hvis denne muligheten er
kompilert inn i nettverkslaget).
Sett denne til no for å unngå
komprimering, for eksempel når nettverkstrafikken skal
analyseres under debugging.
neon-debug-maskDette er en heltallsmaske som det underliggende
HTTP-biblioteket, Neon, bruker for å velge hvilke
debuggingsmeldinger som skal vises.
Standardverdien er 0, som vil
forhindre visning av alle debuggingsdata.
For mer informasjon om hvordan Subversion gjør bruk av
Neon, se Kapittel 8, Developer Information.
ssl-authority-filesDette er en semikolon-separert liste over stier til filer som inneholder sertifikater fra sertifikatutstedere som aksepteres av Subversionklienten under aksessering av depotet over HTTPS.
ssl-trust-default-caSett denne variabelen til yes
hvis du vil at Subversion skal automatisk stole på
settet med standard sertifikatutstedere som leveres med
OpenSSL.
ssl-client-cert-fileHvis en server (eller et sett av servere) krever et SSL-klientsertifikat, vil du normalt bli spurt etter en sti til sertifikatet ditt. Ved å sette denne variabelen til den samme stien, vil Subversion være i stand til å finne klientsertifikatet automatisk uten å spørre. Det finnes ingen standard plass der sertifikatene blir lagret på disken; Subversion vil hente det fra enhver sti som du spesifiserer.
ssl-client-cert-passwordHvis fila med SSL-klientsertifikatet er kryptert med
et passord, vil Subversion be deg om passordet hver gang
sertifikatet brukes.
Hvis du synes dette er irriterende (og synes det er
greit at passordet lagres i
servers-fila), kan du sette denne
variabelen til passordet for for sertifikatet.
Etter dette blir du ikke bedt om å skrive det flere
ganger.
config-fila inneholder resten av de
kjørevalgene som for øyeblikket er tilgjengelig i Subversion
og ikke er relatert til nettverk.
Det er bare noen få valg som er i bruk nå, men de er gruppert
i seksjoner med tanke på framtidige utvidelser.
auth-seksjonen inneholder innstillinger
relatert til Subversions autentisering og autorisasjon i
depotet.
Den inneholder:
store-passwordsDette ber Subversion om å lagre, eller ikke lagre,
passord som blir skrevet av brukeren som respons til
autentiseringskrav fra servere.
Standardverdien er yes.
Sett dette til no for å forhindre
lagring av passord på disken.
Du kan overstyre dette valget for en enkeltstående
svn-kjøring ved å bruke
kommanolinjevalget --no-auth-cache
sammen med de delkommandoene som støtter det.
For mer informasjon, se “Lagring av klientlegitimasjon”.
store-auth-credsDenne valget er det samme som
store-passwords, unntatt at det slår
av/på disklagring av all
autentiseringsinformasjon:
Brukernavn, passord, serversertifikater og alle andre
typer lagringsbar legitimasjon.
helpers-seksjonen kontrollerer hvilke
eksterne programmer Subversion bruker for å utføre oppgavene
sine.
Gyldige valig i denne seksjonen er:
editor-cmdDette spesifiserer hvilket program Subversion vil
kjøre når brukeren skal skrive inn en loggmelding under
en innleggingsoperasjon, som for eksempel ved bruk av
svn commit uten valgene
--message (-m) og
--file (-F).
Dette programmet brukes også sammen med kommandoen
svn propedit – en midlertidig fil
blir fylt med den nåværende verdien til egenskapen
brukeren vil redigere, og redigeringen skjer i
tekstbehandleren (se “Egenskaper”).
Standardverdien til dette valget er tom.
Prioriteringsrekkefølgen som brukes for å avgjøre
hvilken kommando for tekstbehandleren som skal brukes,
er:
Kommandolinjevalget
--editor-cmd
Miljøvariabelen
SVN_EDITOR
Konfigurasjonsvalget
editor-cmd
Miljøvariabelen VISUAL
Miljøvariabelen EDITOR
Muligens en standardverdi som er bygget inn i Subversion (ikke lagt inn i de offisielle versjonene)
Verdien til alle disse valgene eller variablene er
(i motsetning til diff-cmd)
begynnelsen av en kommandolinje som kjøres av skallet.
Subversion legger til et mellomrom og stien til den
midlertidige fila som skal redigeres.
Denne midlertidige fila redigeres med tekstbehandleren
som returnerer en avslutningskode med verdien 0 for å
indikere at operasjonen var vellykket.
diff-cmdDette spesifiserer den absolutte stien til et diff-program (viser forskjeller mellom filer) som blir brukt når Subversion lager “diff”-data (som når svn diff-kommandoen brukes). Vanligvis bruker Subversion et internt diff-bibliotek, men ved å sette dette valget brukes et eksternt program. Se “Using External Differencing Tools” for flere detaljer om bruk av sånne programmer.
diff3-cmdHer spesifiseres den absolutte stien til et treveis diff-program. Subversion bruker dette programmet til å flette forandringer gjort av brukeren sammen med de som mottas fra depotet. Vanligvis bruker Subversion et internt diff-bibliotek, men ved å sette dette valget brukes et eksternt program. Se “Using External Differencing Tools” for flere detaljer om bruk av sånne programmer.
diff3-has-program-argDette flagget bør settes til true
hvis programmet spesifisert i
diff3-cmd-valget aksepterer et
--diff-program-parameter på
kommandolinja.
tunnels-seksjonen lar deg definere nye
tunnelskjemaer for bruk sammen med svnserve
og klienttilkoblinger med svn://.
For flere detaljer, se “Autentisering og autorisasjon via SSH”.
miscellany-seksjonen er der alt som
ikke hører hjemme andre steder ender opp.
I denne seksjonen finner du:
global-ignoresVed kjøring av svn
status-kommandoen lister Subversion
uversjonerte filer og kataloger sammen med de
versjonerte og merker dem med et
?-tegn (se “svn status”).
Noen ganger kan det være plagsomt å se uinteressante,
uversjonerte elementer – for eksempel objektfiler som
ligger igjen etter at et program er kompilert – i denne
visningen.
Valget global-ignores er en liste med
blanktegn-separerte strenger som
beskriver navn på filer og kataloger som Subversion ikke
skal vise unntatt hvis de er versjonert.
Standardverdien er *.o *.lo *.la #*# .*.rej
*.rej .*~ *~ .#* .DS_Store.
I likhet med svn status ignorerer
svn add- og svn
import-kommandoen filer som samsvarer med
listen når de tråler en katalog.
Du kan overstyre denne oppførselen for en enkelt kjøring
av alle disse kommandoene ved å spesifisere filnavnet
eller ved å bruke kommandolinjevalget
--no-ignore.
For informasjon om mer finkontroll av ignorerte elementer, se “Ignoring Unversioned Items”.
enable-auto-propsDette ber Subversion om å automatisk sette
egenskaper på nye filer som legges til eller importeres.
Standardverdien er no, så sett denne
til yes for å slå på autoegenskaper.
Seksjonen auto-props i denne fila
spesifiserer hvilke egenskaper som skal settes på hvilke
filer.
log-encodingDenne variabelen setter standardtegnsettet for
loggmeldinger ved innlegging.
Det er en permanent form av
--encoding-valget (se “svn Switches”).
Subversiondepotet lagrer loggmeldinger i UTF-8, og går
ut i fra at loggmeldingene dine er skrevet med
operativsystemets lokale tegnsett.
Du bør spesifisere en annen koding hvis loggmeldingene
dine skrives med et annet tegnsett.
use-commit-timesNormalt har filene i arbeidskopien din fildatoer som viser forrige gang de ble rørt av en prosess, enten det er tekstbehandleren din eller av en eller annen delkommando i svn. Det er vanligvis praktisk for folk som utvikler programvare, fordi byggesystemer ofte ser på fildatoer som en måte å bestemme hvilke filer som trenger en ny kompilering.
I andre situasjoner, derimot, er det greit å la
filene i arbeidskopien ha fildatoen satt til tidspunktet
de sist ble forandret i depotet.
Kommandoen svn export setter alltid
disse “tidspunktene for siste innlegging”
på trær som den produserer.
Ved å sette denne konfigurasjonsvariabelen til
yes, vil kommandoene svn
checkout, svn update,
svn switch og svn
revert også sette fildatoen på filer som
berøres til forrige gangen de ble lagt inn i
depotet.
Seksjonen auto-props kontrollerer
Subversionklientens mulighet til å automatisk sette egenskaper
på filer når de legges til eller importeres.
Den inneholder et vilkårlig antall nøkkel/verdi-par på
formatet MØNSTER =
EGENSKAPSNAVN=EGENSKAPSVERDI der
MØNSTER er en filnavnsøkestreng som passer
med et sett av filnavn og resten av linja er egenskapen og
dens verdi.
Flere samsvar på en fil vil resultere i flere
egenskapsforandringer for denne fila; imidlertid er det ingen
garanti at autoegenskaper vil bli lagt til i den rekkefølgen
som de listes i konfigurasjonsfila.
Du kan derfor ikke la en regel “overstyre” en
annen.
Du kan finne flere eksempler på bruk av autoegenskaper i
config-fila.
Til sist, ikke glem å sette
enable-auto-props til
yes i
miscellany-seksjonen hvis du vil at
autoegenskaper skal brukes.
Localization is the act of making programs behave in a region-specific way. When a program formats numbers or dates in a way specific to your part of the world, or prints messages (or accepts input) in your native language, the program is said to be localized. This section describes steps Subversion has made towards localization.
Most modern operating systems have a notion of the “current locale”—that is, the region or country whose localization conventions are honored. These conventions—typically chosen by some runtime configuration mechanism on the computer—affect the way in which programs present data to the user, as well as the way in which they accept user input.
On Unix-like systems, you can check the values of the locale-related runtime configuration options by running the locale command:
$ locale LANG= LC_COLLATE="C" LC_CTYPE="C" LC_MESSAGES="C" LC_MONETARY="C" LC_NUMERIC="C" LC_TIME="C" LC_ALL="C"
The output is a list of locale-related environment
variables and their current values. In this example, the
variables are all set to the default C
locale, but users can set these variables to specific
country/language code combinations. For example, if one were
to set the LC_TIME variable to
fr_CA, then programs would know to present
time and date information formatted according a
French-speaking Canadian's expectations. And if one were to
set the LC_MESSAGES variable to
zh_TW, then programs would know to present
human-readable messages in Traditional Chinese. Setting the
LC_ALL variable has the effect of changing
every locale variable to the same value. The value of
LANG is used as a default value for any
locale variable that is unset. To see the list of available
locales on a Unix system, run the command locale
-a.
On Windows, locale configuration is done via the “Regional and Language Options” control panel item. There you can view and select the values of individual settings from the available locales, and even customize (at a sickening level of detail) several of the display formatting conventions.
The Subversion client, svn, honors the
current locale configuration in two ways. First, it notices
the value of the LC_MESSAGES variable and
attempts to print all messages in the specified language. For
example:
$ export LC_MESSAGES=de_DE $ svn help cat cat: Gibt den Inhalt der angegebenen Dateien oder URLs aus. Aufruf: cat ZIEL[@REV]... …
This behavior works identically on both Unix and Windows
systems. Note, though, that while your operating system might
have support for a certain locale, the Subversion client still
may not be able to speak the particular language. In order to
produce localized messages, human volunteers must provide
translations for each language. The translations are written
using the GNU gettext package, which results in translation
modules that end with the .mo filename
extension. For example, the German translation file is named
de.mo. These translation files are
installed somewhere on your system. On Unix, they typically
live in /usr/share/locale/, while
on Windows they're often found in the
\share\locale\ folder in Subversion's
installation area. Once installed, a module is named after
the program it provides translations for. For example, the
de.mo file may ultimately end up
installed as
/usr/share/locale/de/LC_MESSAGES/subversion.mo.
By browsing the installed .mo files, you
can see which languages the Subversion client is able to
speak.
The second way in which the locale is honored involves how svn interprets your input. The repository stores all paths, filenames, and log messages in Unicode, encoded as UTF-8. In that sense, the repository is internationalized—that is, the repository is ready to accept input in any human language. This means, however, that the Subversion client is responsible for sending only UTF-8 filenames and log messages into the repository. In order to do this, it must convert the data from the native locale into UTF-8.
For example, suppose you create a file named
caffè.txt, and then when committing the
file, you write the log message as “Adesso il caffè è
più forte”. Both the filename and log message contain
non-ASCII characters, but because your locale is set to
it_IT, the Subversion client knows to
interpret them as Italian. It uses an Italian character set
to convert the data to UTF-8 before sending them off to the
repository.
Note that while the repository demands UTF-8 filenames and log messages, it does not pay attention to file contents. Subversion treats file contents as opaque strings of bytes, and neither client nor server makes an attempt to understand the character set or encoding of the contents.
The presence of --diff-cmd and
--diff3-cmd options, and similarly named
runtime configuration parameters (see “Konfigurasjon”), can lead to a
false notion of how easy it is to use external differencing (or
“diff”) and merge tools with Subversion. While
Subversion can use most of popular such tools available, the
effort invested in setting this up often turns out to be
non-trivial.
The interface between Subversion and external diff and merge
tools harkens back to a time when Subversion's only contextual
differencing capabilities were built around invocations of the
GNU diffutils toolchain, specifically the
diff and diff3 utilities.
To get the kind of behavior Subversion needed, it called these
utilities with more than a handful of options and parameters,
most of which were quite specific to the utilities. Some time
later, Subversion grew its own internal differencing library,
and as a failover mechanism,
[43]
the --diff-cmd and --diff3-cmd
options were added to the Subversion command-line client so
users could more easily indicate that they preferred to use the
GNU diff and diff3 utilities instead of the newfangled internal
diff library. If those options were used, Subversion would
simply ignore the internal diff library, and fall back to
running those external programs, lengthy argument lists and all.
And that's where things remain today.
It didn't take long for folks to realize that having such easy configuration mechanisms for specifying that Subversion should use the external GNU diff and diff3 utilities located at a particular place on the system could be applied toward the use of other diff and merge tools, too. After all, Subversion didn't actually verify that the things it was being told to run were members of the GNU diffutils toolchain. But the only configurable aspect of using those external tools is their location on the system—not the option set, parameter order, etc. Subversion continues throwing all those GNU utility options at your external diff tool regardless of whether or not that program can understand those options. And that's where things get unintuitive for most users.
The key to using external diff and merge tools (other than GNU diff and diff3, of course) with Subversion is to use wrapper scripts which convert the input from Subversion into something that your differencing tool can understand, and then to convert the output of your tool back into a format which Subversion expects—the format that the GNU tools would have used. The following sections cover the specifics of those expectations.
![]() | Notat |
|---|---|
The decision on when to fire off a contextual diff or
merge as part of a larger Subversion operation is made
entirely by Subversion, and is affected by, among other
things, whether or not the files being operated on are
human-readable as determined by their
|
Subversion calls external diff programs with parameters suitable for the GNU diff utility, and expects only that the external program return with a successful error code. For most alternative diff program, only the sixth and seventh arguments, the paths of the files which represent the left and right sides of the diff, respectively, are of interest. Note that Subversion runs the diff program once per modified file covered by the Subversion operation, so if your program runs in an asynchronous fashion (or “backgrounded”), you might have several instances of it all running simultaneously. Finally, Subversion expects that your program return an errorcode of 1 if your program detected differences, or 0 if it did not—any other errorcode is considered a fatal error. [44]
Eksempel 7.2, “diffwrap.sh” and Eksempel 7.3, “diffwrap.bat” are templates for external diff tool wrappers in the Bourne shell and Windows batch scripting languages, respectively.
Eksempel 7.2. diffwrap.sh
#!/bin/sh
# Configure your favorite diff program here.
DIFF="/usr/local/bin/my-diff-tool"
# Subversion provides the paths we need as the sixth and seventh
# parameters.
LEFT=${6}
RIGHT=${7}
# Call the diff command (change the following line to make sense for
# your merge program).
$DIFF --left $LEFT --right $RIGHT
# Return an errorcode of 0 if no differences were detected, 1 if some were.
# Any other errorcode will be treated as fatal.
Eksempel 7.3. diffwrap.bat
@ECHO OFF REM Configure your favorite diff program here. SET DIFF="C:\Program Files\Funky Stuff\My Diff Tool.exe" REM Subversion provides the paths we need as the sixth and seventh REM parameters. SET LEFT=%6 SET RIGHT=%7 REM Call the diff command (change the following line to make sense for REM your merge program). %DIFF% --left %LEFT% --right %RIGHT% REM Return an errorcode of 0 if no differences were detected, 1 if some were. REM Any other errorcode will be treated as fatal.
Subversion calls external merge programs with parameters suitable for the GNU diff3 utility, expecting that the external program return with a successful error code and that the full file contents which result from the completed merge operation are printed on the standard output stream (so that Subversion can redirect them into the appropriate version controlled file). For most alternative merge programs, only the ninth, tenth, and eleventh arguments, the paths of the files which represent the “mine”, “older”, and “yours” inputs, respectively, are of interest. Note that because Subversion depends on the output of your merge program, you wrapper script must not exit before that output has been delivered to Subversion. When it finally does exit, it should return an errorcode of 0 if the merge was successful, or 1 if unresolved conflicts remain in the output—any other errorcode is considered a fatal error.
Eksempel 7.4, “diff3wrap.sh” and Eksempel 7.5, “diff3wrap.bat” are templates for external merge tool wrappers in the Bourne shell and Windows batch scripting languages, respectively.
Eksempel 7.4. diff3wrap.sh
#!/bin/sh
# Configure your favorite diff3/merge program here.
DIFF3="/usr/local/bin/my-merge-tool"
# Subversion provides the paths we need as the ninth, tenth, and eleventh
# parameters.
MINE=${9}
OLDER=${10}
YOURS=${11}
# Call the merge command (change the following line to make sense for
# your merge program).
$DIFF3 --older $OLDER --mine $MINE --yours $YOURS
# After performing the merge, this script needs to print the contents
# of the merged file to stdout. Do that in whatever way you see fit.
# Return an errorcode of 0 on successful merge, 1 if unresolved conflicts
# remain in the result. Any other errorcode will be treated as fatal.
Eksempel 7.5. diff3wrap.bat
@ECHO OFF REM Configure your favorite diff3/merge program here. SET DIFF3="C:\Program Files\Funky Stuff\My Merge Tool.exe" REM Subversion provides the paths we need as the ninth, tenth, and eleventh REM parameters. But we only have access to nine parameters at a time, so we REM shift our nine-parameter window twice to let us get to what we need. SHIFT SHIFT SET MINE=%7 SET OLDER=%8 SET YOURS=%9 REM Call the merge command (change the following line to make sense for REM your merge program). %DIFF3% --older %OLDER% --mine %MINE% --yours %YOURS% REM After performing the merge, this script needs to print the contents REM of the merged file to stdout. Do that in whatever way you see fit. REM Return an errorcode of 0 on successful merge, 1 if unresolved conflicts REM remain in the result. Any other errorcode will be treated as fatal.
[42] Miljøvariabelen APPDATA peker til
Application Data-området,
så du kan alltids henvise til denne katalogen som
%APPDATA%\Subversion.
[43] Subversion developers are good, but even the best make mistakes.
[44] The GNU diff manual page puts it this way: “An exit status of 0 means no differences were found, 1 means some differences were found, and 2 means trouble.”
Innholdsfortegnelse
Subversion has a modular design, implemented as a collection of C libraries. Each library has a well-defined purpose and interface, and those interfaces are available not only for Subversion itself to use, but for any software that wishes to embed or otherwise programmatically control Subversion. Most of those interfaces are available not only in C, but also in higher-level languages such as Python or Java.
This chapter is for those who wish to interact with Subversion through its public Application Programming Interface (API) or various language bindings. If you wish to write robust wrapper scripts around Subversion functionality to simplify your own life, are trying to develop more complex integrations between Subversion and other pieces of software, or just have an interest in Subversion's various library modules and what they offer, this chapter is for you. If, however, you don't foresee yourself participating with Subversion at such a level, feel free to skip this chapter with the confidence that your experience as a Subversion user will not be affected.
Each of Subversion's core libraries can be said to exist in one of three main layers—the Repository Layer, the Repository Access (RA) Layer, or the Client Layer. We will examine these layers shortly, but first, see our brief inventory of Subversion's libraries in Tabell 8.1, “A Brief Inventory of the Subversion Libraries”. For the sake of consistency, we will refer to the libraries by their extensionless Unix library names (e.g.: libsvn_fs, libsvn_wc, mod_dav_svn).
Tabell 8.1. A Brief Inventory of the Subversion Libraries
| Library | Description |
|---|---|
| libsvn_client | Primary interface for client programs |
| libsvn_delta | Tree and byte-stream differencing routines |
| libsvn_diff | Contextual differencing and merging routines |
| libsvn_fs | Filesystem commons and module loader |
| libsvn_fs_base | The Berkeley DB filesystem back-end |
| libsvn_fs_fs | The native filesystem (FSFS) back-end |
| libsvn_ra | Repository Access commons and module loader |
| libsvn_ra_dav | The WebDAV Repository Access module |
| libsvn_ra_local | The local Repository Access module |
| libsvn_ra_svn | The custom protocol Repository Access module |
| libsvn_repos | Repository interface |
| libsvn_subr | Miscellaneous helpful subroutines |
| libsvn_wc | The working copy management library |
| mod_authz_svn | Apache authorization module for Subversion repositories access via WebDAV |
| mod_dav_svn | Apache module for mapping WebDAV operations to Subversion ones |
The fact that the word “miscellaneous” only appears once in Tabell 8.1, “A Brief Inventory of the Subversion Libraries” is a good sign. The Subversion development team is serious about making sure that functionality lives in the right layer and libraries. Perhaps the greatest advantage of the modular design is its lack of complexity from a developer's point of view. As a developer, you can quickly formulate that kind of “big picture” that allows you to pinpoint the location of certain pieces of functionality with relative ease.
Another benefit of modularity is the ability to replace a given module with a whole new library that implements the same API without affecting the rest of the code base. In some sense, this happens within Subversion already. The libsvn_ra_dav, libsvn_ra_local, and libsvn_ra_svn all implement the same interface. And all three communicate with the Repository Layer—libsvn_ra_dav and libsvn_ra_svn do so across a network, and libsvn_ra_local connects to it directly. The libsvn_fs_base and libsvn_fs_fs libraries are another example of this.
The client itself also highlights modularity in the Subversion design. While Subversion itself comes with only a command-line client program, there are several third party programs which provide various forms of client GUI. These GUIs use the same APIs that the stock command-line client does. Subversion's libsvn_client library is the one-stop shop for most of the functionality necessary for designing a working Subversion client (see “Client Layer”).
When referring to Subversion's Repository Layer, we're generally talking about two libraries—the repository library, and the filesystem library. These libraries provide the storage and reporting mechanisms for the various revisions of your version-controlled data. This layer is connected to the Client Layer via the Repository Access Layer, and is, from the perspective of the Subversion user, the stuff at the “other end of the line.”
The Subversion Filesystem is accessed via the libsvn_fs API, and is not a kernel-level filesystem that one would install in an operating system (like the Linux ext2 or NTFS), but a virtual filesystem. Rather than storing “files” and “directories” as real files and directories (as in, the kind you can navigate through using your favorite shell program), it uses one of two available abstract storage backends—either a Berkeley DB database environment, or a flat-file representation. (To learn more about the two repository back-ends, see “Datalagring i depotet”.) However, there has been considerable interest by the development community in giving future releases of Subversion the ability to use other back-end database systems, perhaps through a mechanism such as Open Database Connectivity (ODBC).
The filesystem API exported by libsvn_fs contains the kinds of functionality you would expect from any other filesystem API: you can create and remove files and directories, copy and move them around, modify file contents, and so on. It also has features that are not quite as common, such as the ability to add, modify, and remove metadata (“properties”) on each file or directory. Furthermore, the Subversion Filesystem is a versioning filesystem, which means that as you make changes to your directory tree, Subversion remembers what your tree looked like before those changes. And before the previous changes. And the previous ones. And so on, all the way back through versioning time to (and just beyond) the moment you first started adding things to the filesystem.
All the modifications you make to your tree are done within the context of a Subversion transaction. The following is a simplified general routine for modifying your filesystem:
Begin a Subversion transaction.
Make your changes (adds, deletes, property modifications, etc.).
Commit your transaction.
Once you have committed your transaction, your filesystem modifications are permanently stored as historical artifacts. Each of these cycles generates a single new revision of your tree, and each revision is forever accessible as an immutable snapshot of “the way things were.”
Most of the functionality provided by the filesystem
interface comes as an action that occurs on a filesystem path.
That is, from outside of the filesystem, the primary mechanism
for describing and accessing the individual revisions of files
and directories comes through the use of path strings like
/foo/bar, just as if you were addressing
files and directories through your favorite shell program.
You add new files and directories by passing their paths-to-be
to the right API functions. You query for information about
them by the same mechanism.
Unlike most filesystems, though, a path alone is not enough information to identify a file or directory in Subversion. Think of a directory tree as a two-dimensional system, where a node's siblings represent a sort of left-and-right motion, and descending into subdirectories a downward motion. Figur 8.1, “Files and directories in two dimensions” shows a typical representation of a tree as exactly that.
Of course, the Subversion filesystem has a nifty third
dimension that most filesystems do not have—Time!
[45]
In the filesystem interface, nearly every function that has a
path argument also expects a
root argument. This
svn_fs_root_t argument describes
either a revision or a Subversion transaction (which is
usually just a revision-to-be), and provides that
third-dimensional context needed to understand the difference
between /foo/bar in revision 32, and the
same path as it exists in revision 98. Figur 8.2, “Versioning time—the third dimension!” shows revision history as an
added dimension to the Subversion filesystem universe.
As we mentioned earlier, the libsvn_fs API looks and feels like any other filesystem, except that it has this wonderful versioning capability. It was designed to be usable by any program interested in a versioning filesystem. Not coincidentally, Subversion itself is interested in that functionality. But while the filesystem API should be sufficient for basic file and directory versioning support, Subversion wants more—and that is where libsvn_repos comes in.
The Subversion repository library (libsvn_repos) is basically a wrapper library around the filesystem functionality. This library is responsible for creating the repository layout, making sure that the underlying filesystem is initialized, and so on. Libsvn_repos also implements a set of hooks—scripts that are executed by the repository code when certain actions take place. These scripts are useful for notification, authorization, or whatever purposes the repository administrator desires. This type of functionality, and other utilities provided by the repository library, are not strictly related to implementing a versioning filesystem, which is why it was placed into its own library.
Developers who wish to use the libsvn_repos API will find that it is not a complete wrapper around the filesystem interface. That is, only certain major events in the general cycle of filesystem activity are wrapped by the repository interface. Some of these include the creation and commit of Subversion transactions, and the modification of revision properties. These particular events are wrapped by the repository layer because they have hooks associated with them. In the future, other events may be wrapped by the repository API. All of the remaining filesystem interaction will continue to occur directly via the libsvn_fs API, though.
For example, here is a code segment that illustrates the
use of both the repository and filesystem interfaces to create
a new revision of the filesystem in which a directory is
added. Note that in this example, the
SVN_ERR() macro simply checks for a
non-successful error return from the function it wraps, and
returns that error if it exists.
Eksempel 8.1. Using the Repository Layer
/* Create a new directory at the path NEW_DIRECTORY in the Subversion
repository located at REPOS_PATH. Perform all memory allocation in
POOL. This function will create a new revision for the addition of
NEW_DIRECTORY. */
static svn_error_t *
make_new_directory (const char *repos_path,
const char *new_directory,
apr_pool_t *pool)
{
svn_error_t *err;
svn_repos_t *repos;
svn_fs_t *fs;
svn_revnum_t youngest_rev;
svn_fs_txn_t *txn;
svn_fs_root_t *txn_root;
const char *conflict_str;
/* Open the repository located at REPOS_PATH. */
SVN_ERR (svn_repos_open (&repos, repos_path, pool));
/* Get a pointer to the filesystem object that is stored in
REPOS. */
fs = svn_repos_fs (repos);
/* Ask the filesystem to tell us the youngest revision that
currently exists. */
SVN_ERR (svn_fs_youngest_rev (&youngest_rev, fs, pool));
/* Begin a new transaction that is based on YOUNGEST_REV. We are
less likely to have our later commit rejected as conflicting if we
always try to make our changes against a copy of the latest snapshot
of the filesystem tree. */
SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, pool));
/* Now that we have started a new Subversion transaction, get a root
object that represents that transaction. */
SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
/* Create our new directory under the transaction root, at the path
NEW_DIRECTORY. */
SVN_ERR (svn_fs_make_dir (txn_root, new_directory, pool));
/* Commit the transaction, creating a new revision of the filesystem
which includes our added directory path. */
err = svn_repos_fs_commit_txn (&conflict_str, repos,
&youngest_rev, txn, pool);
if (! err)
{
/* No error? Excellent! Print a brief report of our success. */
printf ("Directory '%s' was successfully added as new revision "
"'%ld'.\n", new_directory, youngest_rev);
}
else if (err->apr_err == SVN_ERR_FS_CONFLICT)
{
/* Uh-oh. Our commit failed as the result of a conflict
(someone else seems to have made changes to the same area
of the filesystem that we tried to modify). Print an error
message. */
printf ("A conflict occurred at path '%s' while attempting "
"to add directory '%s' to the repository at '%s'.\n",
conflict_str, new_directory, repos_path);
}
else
{
/* Some other error has occurred. Print an error message. */
printf ("An error occurred while attempting to add directory '%s' "
"to the repository at '%s'.\n",
new_directory, repos_path);
}
/* Return the result of the attempted commit to our caller. */
return err;
}
In the previous code segment, calls were made to both the
repository and filesystem interfaces. We could just as easily
have committed the transaction using
svn_fs_commit_txn(). But the filesystem
API knows nothing about the repository library's hook
mechanism. If you want your Subversion repository to
automatically perform some set of non-Subversion tasks every
time you commit a transaction (like, for example, sending an
email that describes all the changes made in that transaction
to your developer mailing list), you need to use the
libsvn_repos-wrapped version of that
function—svn_repos_fs_commit_txn().
This function will actually first run the
pre-commit hook script if one exists, then
commit the transaction, and finally will run a
post-commit hook script. The hooks provide
a special kind of reporting mechanism that does not really
belong in the core filesystem library itself. (For more
information regarding Subversion's repository hooks, see “Påhakningsskript”.)
The hook mechanism requirement is but one of the reasons for the abstraction of a separate repository library from the rest of the filesystem code. The libsvn_repos API provides several other important utilities to Subversion. These include the abilities to:
create, open, destroy, and perform recovery steps on a Subversion repository and the filesystem included in that repository.
describe the differences between two filesystem trees.
query for the commit log messages associated with all (or some) of the revisions in which a set of files was modified in the filesystem.
generate a human-readable “dump” of the filesystem, a complete representation of the revisions in the filesystem.
parse that dump format, loading the dumped revisions into a different Subversion repository.
As Subversion continues to evolve, the repository library will grow with the filesystem library to offer increased functionality and configurable option support.
If the Subversion Repository Layer is at “the other end of the line”, the Repository Access Layer is the line itself. Charged with marshalling data between the client libraries and the repository, this layer includes the libsvn_ra module loader library, the RA modules themselves (which currently includes libsvn_ra_dav, libsvn_ra_local, and libsvn_ra_svn), and any additional libraries needed by one or more of those RA modules, such as the mod_dav_svn Apache module with which libsvn_ra_dav communicates or libsvn_ra_svn's server, svnserve.
Since Subversion uses URLs to identify its repository
resources, the protocol portion of the URL schema (usually
file:, http:,
https:, or svn:) is used
to determine which RA module will handle the communications.
Each module registers a list of the protocols it knows how to
“speak” so that the RA loader can, at runtime,
determine which module to use for the task at hand. You can
determine which RA modules are available to the Subversion
command-line client, and what protocols they claim to support,
by running svn --version:
$ svn --version svn, version 1.2.3 (r15833) compiled Sep 13 2005, 22:45:22 Copyright (C) 2000-2005 CollabNet. Subversion is open source software, see http://subversion.tigris.org/ This product includes software developed by CollabNet (http://www.Collab.Net/). The following repository access (RA) modules are available: * ra_dav : Module for accessing a repository via WebDAV (DeltaV) protocol. - handles 'http' scheme - handles 'https' scheme * ra_svn : Module for accessing a repository using the svn network protocol. - handles 'svn' scheme * ra_local : Module for accessing a repository on local disk. - handles 'file' scheme
The libsvn_ra_dav library is designed for use by clients
that are being run on different machines than the servers
with which they communicating, specifically servers reached
using URLs that contain the http: or
https: protocol portions. To understand
how this module works, we should first mention a couple of
other key components in this particular configuration of the
Repository Access Layer—the powerful Apache HTTP
Server, and the Neon HTTP/WebDAV client library.
Subversion's primary network server is the Apache HTTP Server. Apache is a time-tested, extensible open-source server process that is ready for serious use. It can sustain a high network load and runs on many platforms. The Apache server supports a number of different standard authentication protocols, and can be extended through the use of modules to support many others. It also supports optimizations like network pipelining and caching. By using Apache as a server, Subversion gets all of these features for free. And since most firewalls already allow HTTP traffic to pass through, system administrators typically don't even have to change their firewall configurations to allow Subversion to work.
Subversion uses HTTP and WebDAV (with DeltaV) to communicate with an Apache server. You can read more about this in the WebDAV section of this chapter, but in short, WebDAV and DeltaV are extensions to the standard HTTP 1.1 protocol that enable sharing and versioning of files over the web. Apache 2.0 and later versions come with mod_dav, an Apache module that understands the DAV extensions to HTTP. Subversion itself supplies mod_dav_svn, though, which is another Apache module that works in conjunction with (really, as a back-end to) mod_dav to provide Subversion's specific implementations of WebDAV and DeltaV.
When communicating with a repository over HTTP, the RA
loader library chooses libsvn_ra_dav as the proper access
module. The Subversion client makes calls into the generic
RA interface, and libsvn_ra_dav maps those calls (which
embody rather large-scale Subversion actions) to a set of
HTTP/WebDAV requests. Using the Neon library, libsvn_ra_dav
transmits those requests to the Apache server. Apache
receives these requests (exactly as it does generic HTTP
requests that your web browser might make), notices that the
requests are directed at a URL that is configured as a DAV
location (using the <Location>
directive in httpd.conf), and hands the
request off to its own mod_dav module. When properly
configured, mod_dav knows to use Subversion's mod_dav_svn for
any filesystem-related needs, as opposed to the generic
mod_dav_fs that comes with Apache. So ultimately, the client
is communicating with mod_dav_svn, which binds directly to the
Subversion Repository Layer.
That was a simplified description of the actual exchanges taking place, though. For example, the Subversion repository might be protected by Apache's authorization directives. This could result in initial attempts to communicate with the repository being rejected by Apache on authorization grounds. At this point, libsvn_ra_dav gets back the notice from Apache that insufficient identification was supplied, and calls back into the Client Layer to get some updated authentication data. If the data is supplied correctly, and the user has the permissions that Apache seeks, libsvn_ra_dav's next automatic attempt at performing the original operation will be granted, and all will be well. If sufficient authentication information cannot be supplied, the request will ultimately fail, and the client will report the failure to the user.
By using Neon and Apache, Subversion gets free functionality in several other complex areas, too. For example, if Neon finds the OpenSSL libraries, it allows the Subversion client to attempt to use SSL-encrypted communications with the Apache server (whose own mod_ssl can “speak the language”). Also, both Neon itself and Apache's mod_deflate can understand the “deflate” algorithm (the same one used by the PKZIP and gzip programs), so requests can be sent in smaller, compressed chunks across the wire. Other complex features that Subversion hopes to support in the future include the ability to automatically handle server-specified redirects (for example, when a repository has been moved to a new canonical URL) and taking advantage of HTTP pipelining.
In addition to the standard HTTP/WebDAV protocol,
Subversion also provides an RA implementation that uses a
custom protocol. The libsvn_ra_svn module implements
its own network socket connectivity, and communicates with a
stand-alone server—the svnserve
program—on the machine that hosts the
repository. Clients access the repository using the
svn:// schema.
This RA implementation lacks most of the advantages of
Apache mentioned in the previous section; however, it may be
appealing to some system administrators nonetheless. It is
dramatically easier to configure and run; setting up an
svnserve process is nearly
instantaneous. It is also much smaller (in terms of lines
of code) than Apache, making it much easier to audit, for
security reasons or otherwise. Furthermore, some system
administrators may already have an SSH security
infrastructure in place, and want Subversion to use it.
Clients using ra_svn can easily tunnel the protocol over
SSH.
Not all communications with a Subversion repository
require a powerhouse server process and a network layer.
For users who simply wish to access the repositories on
their local disk, they may do so using
file: URLs and the functionality provided
by libsvn_ra_local. This RA module binds directly with the
repository and filesystem libraries, so no network
communication is required at all.
Subversion requires that the server name included as part
of the file: URL be either
localhost or empty, and that there be no
port specification. In other words, your URLs should look
like either
file://localhost/path/to/repos or
file:///path/to/repos.
Also, be aware that Subversion's
file: URLs cannot be used in a regular
web browser the way typical file: URLs
can. When you attempt to view a file:
URL in a regular web browser, it reads and displays the
contents of the file at that location by examining the
filesystem directly. However, Subversion's resources exist
in a virtual filesystem (see “Repository Layer”), and your browser will not
understand how to read that filesystem.
For those who wish to access a Subversion repository using still another protocol, that is precisely why the Repository Access Layer is modularized! Developers can simply write a new library that implements the RA interface on one side and communicates with the repository on the other. Your new library can use existing network protocols, or you can invent your own. You could use inter-process communication (IPC) calls, or—let's get crazy, shall we?—you could even implement an email-based protocol. Subversion supplies the APIs; you supply the creativity.
On the client side, the Subversion working copy is where all the action takes place. The bulk of functionality implemented by the client-side libraries exists for the sole purpose of managing working copies—directories full of files and other subdirectories which serve as a sort of local, editable “reflection” of one or more repository locations—and propagating changes to and from the Repository Access layer.
Subversion's working copy library, libsvn_wc, is directly
responsible for managing the data in the working copies. To
accomplish this, the library stores administrative information
about each working copy directory within a special
subdirectory. This subdirectory, named
.svn, is present in each working copy
directory and contains various other files and directories
which record state and provide a private workspace for
administrative action. For those familiar with CVS, this
.svn subdirectory is similar in purpose
to the CVS administrative directories
found in CVS working copies. For more information about the
.svn administrative area, see “Inside the Working Copy Administration Area”in this chapter.
The Subversion client library, libsvn_client, has the
broadest responsibility; its job is to mingle the
functionality of the working copy library with that of the
Repository Access Layer, and then to provide the highest-level
API to any application that wishes to perform general revision
control actions. For example, the function
svn_client_checkout() takes a URL as an
argument. It passes this URL to the RA layer and opens an
authenticated session with a particular repository. It then
asks the repository for a certain tree, and sends this tree
into the working copy library, which then writes a full
working copy to disk (.svn directories
and all).
The client library is designed to be used by any application. While the Subversion source code includes a standard command-line client, it should be very easy to write any number of GUI clients on top of the client library. New GUIs (or any new client, really) for Subversion need not be clunky wrappers around the included command-line client—they have full access via the libsvn_client API to same functionality, data, and callback mechanisms that the command-line client uses.
Developing applications against the Subversion library APIs
is fairly straightforward. All of the public header files live
in the subversion/include directory of the
source tree. These headers are copied into your system
locations when you build and install Subversion itself from
source. These headers represent the entirety of the functions
and types meant to be accessible by users of the Subversion
libraries.
The first thing you might notice is that Subversion's
datatypes and functions are namespace protected. Every public
Subversion symbol name begins with svn_,
followed by a short code for the library in which the symbol is
defined (such as wc,
client, fs, etc.),
followed by a single underscore (_) and
then the rest of the symbol name. Semi-public functions (used
among source files of a given library but not by code outside
that library, and found inside the library directories
themselves) differ from this naming scheme in that instead of a
single underscore after the library code, they use a double
underscore (__). Functions that are private
to a given source file have no special prefixing, and are declared
static. Of course, a compiler isn't
interested in these naming conventions, but they help to clarify
the scope of a given function or datatype.
Along with Subversion's own datatypes, you will see many
references to datatypes that begin with
apr_—symbols from the Apache
Portable Runtime (APR) library. APR is Apache's portability
library, originally carved out of its server code as an
attempt to separate the OS-specific bits from the
OS-independent portions of the code. The result was a library
that provides a generic API for performing operations that
differ mildly—or wildly—from OS to OS. While the
Apache HTTP Server was obviously the first user of the APR
library, the Subversion developers immediately recognized the
value of using APR as well. This means that there are
practically no OS-specific code portions in Subversion itself.
Also, it means that the Subversion client compiles and runs
anywhere that the server does. Currently this list includes
all flavors of Unix, Win32, BeOS, OS/2, and Mac OS X.
In addition to providing consistent implementations of
system calls that differ across operating systems,
[46]
APR gives Subversion immediate access to many custom
datatypes, such as dynamic arrays and hash tables. Subversion
uses these types extensively throughout the codebase. But
perhaps the most pervasive APR datatype, found in nearly every
Subversion API prototype, is the
apr_pool_t—the APR memory pool.
Subversion uses pools internally for all its memory allocation
needs (unless an external library requires a different memory
management schema for data passed through its API),
[47]
and while a person coding against the Subversion APIs is
not required to do the same, they are required to provide
pools to the API functions that need them. This means that
users of the Subversion API must also link against APR, must
call apr_initialize() to initialize the
APR subsystem, and then must create and manage pools for use with
Subversion API calls, typically by using
svn_pool_create(),
svn_pool_clear(), and
svn_pool_destroy().
With remote version control operation as the whole point
of Subversion's existence, it makes sense that some attention
has been paid to internationalization (i18n) support. After
all, while “remote” might mean “across the
office”, it could just as well mean “across the
globe.” To facilitate this, all of Subversion's public
interfaces that accept path arguments expect those paths to be
canonicalized, and encoded in UTF-8. This means, for example,
that any new client binary that drives the libsvn_client
interface needs to first convert paths from the
locale-specific encoding to UTF-8 before passing those paths
to the Subversion libraries, and then re-convert any resultant
output paths from Subversion back into the locale's encoding
before using those paths for non-Subversion purposes.
Fortunately, Subversion provides a suite of functions (see
subversion/include/svn_utf.h) that can be
used by any program to do these conversions.
Also, Subversion APIs require all URL parameters to be
properly URI-encoded. So, instead of passing
file:///home/username/My File.txt as the URL of a
file named My File.txt, you need to pass
file:///home/username/My%20File.txt. Again,
Subversion supplies helper functions that your application can
use—svn_path_uri_encode() and
svn_path_uri_decode(), for URI encoding
and decoding, respectively.
If you are interested in using the Subversion libraries in
conjunction with something other than a C program—say a
Python or Perl script—Subversion has some support for this
via the Simplified Wrapper and Interface Generator (SWIG). The
SWIG bindings for Subversion are located in
subversion/bindings/swig and whilst still
maturing, they are in a usable state. These bindings allow you
to call Subversion API functions indirectly, using wrappers that
translate the datatypes native to your scripting language into
the datatypes needed by Subversion's C libraries.
There is an obvious benefit to accessing the Subversion APIs via a language binding—simplicity. Generally speaking, languages such as Python and Perl are much more flexible and easy to use than C or C++. The sort of high-level datatypes and context-driven type checking provided by these languages are often better at handling information that comes from users. As you know, humans are proficient at botching up input to a program, and scripting languages tend to handle that misinformation more gracefully. Of course, often that flexibility comes at the cost of performance. That is why using a tightly-optimized, C-based interface and library suite, combined with a powerful, flexible binding language, is so appealing.
Let's look at a sample program that uses Subversion's Python SWIG bindings to recursively crawl the youngest repository revision, and print the various paths reached during the crawl.
Eksempel 8.2. Using the Repository Layer with Python
#!/usr/bin/python
"""Crawl a repository, printing versioned object path names."""
import sys
import os.path
import svn.fs, svn.core, svn.repos
def crawl_filesystem_dir(root, directory, pool):
"""Recursively crawl DIRECTORY under ROOT in the filesystem, and return
a list of all the paths at or below DIRECTORY. Use POOL for all
allocations."""
# Print the name of this path.
print directory + "/"
# Get the directory entries for DIRECTORY.
entries = svn.fs.svn_fs_dir_entries(root, directory, pool)
# Use an iteration subpool.
subpool = svn.core.svn_pool_create(pool)
# Loop over the entries.
names = entries.keys()
for name in names:
# Clear the iteration subpool.
svn.core.svn_pool_clear(subpool)
# Calculate the entry's full path.
full_path = directory + '/' + name
# If the entry is a directory, recurse. The recursion will return
# a list with the entry and all its children, which we will add to
# our running list of paths.
if svn.fs.svn_fs_is_dir(root, full_path, subpool):
crawl_filesystem_dir(root, full_path, subpool)
else:
# Else it's a file, so print its path here.
print full_path
# Destroy the iteration subpool.
svn.core.svn_pool_destroy(subpool)
def crawl_youngest(pool, repos_path):
"""Open the repository at REPOS_PATH, and recursively crawl its
youngest revision."""
# Open the repository at REPOS_PATH, and get a reference to its
# versioning filesystem.
repos_obj = svn.repos.svn_repos_open(repos_path, pool)
fs_obj = svn.repos.svn_repos_fs(repos_obj)
# Query the current youngest revision.
youngest_rev = svn.fs.svn_fs_youngest_rev(fs_obj, pool)
# Open a root object representing the youngest (HEAD) revision.
root_obj = svn.fs.svn_fs_revision_root(fs_obj, youngest_rev, pool)
# Do the recursive crawl.
crawl_filesystem_dir(root_obj, "", pool)
if __name__ == "__main__":
# Check for sane usage.
if len(sys.argv) != 2:
sys.stderr.write("Usage: %s REPOS_PATH\n"
% (os.path.basename(sys.argv[0])))
sys.exit(1)
# Canonicalize (enough for Subversion, at least) the repository path.
repos_path = os.path.normpath(sys.argv[1])
if repos_path == '.':
repos_path = ''
# Call the app-wrapper, which takes care of APR initialization/shutdown
# and the creation and cleanup of our top-level memory pool.
svn.core.run_app(crawl_youngest, repos_path)
This same program in C would need to deal with custom datatypes (such as those provided by the APR library) for representing the hash of entries and the list of paths, but Python has hashes (called “dictionaries”) and lists as built-in datatypes, and provides a rich collection of functions for operating on those types. So SWIG (with the help of some customizations in Subversion's language bindings layer) takes care of mapping those custom datatypes into the native datatypes of the target language. This provides a more intuitive interface for users of that language.
The Subversion Python bindings can be used for working
copy operations, too. In the previous section of this
chapter, we mentioned the libsvn_client
interface, and how it exists for the sole purpose of
simplifying the process of writing a Subversion client. The
following is a brief example of how that library can be
accessed via the SWIG bindings to recreate a scaled-down
version of the svn status command.
Eksempel 8.3. A Python Status Crawler
#!/usr/bin/env python
"""Crawl a working copy directory, printing status information."""
import sys
import os.path
import getopt
import svn.core, svn.client, svn.wc
def generate_status_code(status):
"""Translate a status value into a single-character status code,
using the same logic as the Subversion command-line client."""
if status == svn.wc.svn_wc_status_none:
return ' '
if status == svn.wc.svn_wc_status_normal:
return ' '
if status == svn.wc.svn_wc_status_added:
return 'A'
if status == svn.wc.svn_wc_status_missing:
return '!'
if status == svn.wc.svn_wc_status_incomplete:
return '!'
if status == svn.wc.svn_wc_status_deleted:
return 'D'
if status == svn.wc.svn_wc_status_replaced:
return 'R'
if status == svn.wc.svn_wc_status_modified:
return 'M'
if status == svn.wc.svn_wc_status_merged:
return 'G'
if status == svn.wc.svn_wc_status_conflicted:
return 'C'
if status == svn.wc.svn_wc_status_obstructed:
return '~'
if status == svn.wc.svn_wc_status_ignored:
return 'I'
if status == svn.wc.svn_wc_status_external:
return 'X'
if status == svn.wc.svn_wc_status_unversioned:
return '?'
return '?'
def do_status(pool, wc_path, verbose):
# Calculate the length of the input working copy path.
wc_path_len = len(wc_path)
# Build a client context baton.
ctx = svn.client.svn_client_ctx_t()
def _status_callback(path, status, root_path_len=wc_path_len):
"""A callback function for svn_client_status."""
# Print the path, minus the bit that overlaps with the root of
# the status crawl
text_status = generate_status_code(status.text_status)
prop_status = generate_status_code(status.prop_status)
print '%s%s %s' % (text_status, prop_status, path[wc_path_len + 1:])
# Do the status crawl, using _status_callback() as our callback function.
svn.client.svn_client_status(wc_path, None, _status_callback,
1, verbose, 0, 0, ctx, pool)
def usage_and_exit(errorcode):
"""Print usage message, and exit with ERRORCODE."""
stream = errorcode and sys.stderr or sys.stdout
stream.write("""Usage: %s OPTIONS WC-PATH
Options:
--help, -h : Show this usage message
--verbose, -v : Show all statuses, even uninteresting ones
""" % (os.path.basename(sys.argv[0])))
sys.exit(errorcode)
if __name__ == '__main__':
# Parse command-line options.
try:
opts, args = getopt.getopt(sys.argv[1:], "hv", ["help", "verbose"])
except getopt.GetoptError:
usage_and_exit(1)
verbose = 0
for opt, arg in opts:
if opt in ("-h", "--help"):
usage_and_exit(0)
if opt in ("-v", "--verbose"):
verbose = 1
if len(args) != 1:
usage_and_exit(2)
# Canonicalize (enough for Subversion, at least) the working copy path.
wc_path = os.path.normpath(args[0])
if wc_path == '.':
wc_path = ''
# Call the app-wrapper, which takes care of APR initialization/shutdown
# and the creation and cleanup of our top-level memory pool.
svn.core.run_app(do_status, wc_path, verbose)
Subversion's language bindings unfortunately tend to lack the level of attention given to the core Subversion modules. However, there have been significant efforts towards creating functional bindings for Python, Perl, and Ruby. To some extent, the work done preparing the SWIG interface files for these languages is reusable in efforts to generate bindings for other languages supported by SWIG (which includes versions of C#, Guile, Java, MzScheme, OCaml, PHP, Tcl, and others). However, some extra programming is required to compensate for complex APIs that SWIG needs some help interfacing with. For more information on SWIG itself, see the project's website at http://www.swig.org/.
As we mentioned earlier, each directory of a Subversion
working copy contains a special subdirectory called
.svn which houses administrative data about
that working copy directory. Subversion uses the information in
.svn to keep track of things like:
Which repository location(s) are represented by the files and subdirectories in the working copy directory.
What revision of each of those files and directories are currently present in the working copy.
Any user-defined properties that might be attached to those files and directories.
Pristine (un-edited) copies of the working copy files.
While there are several other bits of data stored in the
.svn directory, we will examine only a
couple of the most important items.
Perhaps the single most important file in the
.svn directory is the
entries file. The entries file is an XML
document which contains the bulk of the administrative
information about a versioned resource in a working copy
directory. It is this one file which tracks the repository
URLs, pristine revision, file checksums, pristine text and
property timestamps, scheduling and conflict state
information, last-known commit information (author, revision,
timestamp), local copy history—practically everything
that a Subversion client is interested in knowing about a
versioned (or to-be-versioned) resource!
The following is an example of an actual entries file:
Eksempel 8.4. Contents of a Typical .svn/entries
File
<?xml version="1.0" encoding="utf-8"?> <wc-entries xmlns="svn:"> <entry committed-rev="1" name="" committed-date="2005-04-04T13:32:28.526873Z" url="http://svn.red-bean.com/repos/greek-tree/A/D" last-author="jrandom" kind="dir" uuid="4e820d15-a807-0410-81d5-aa59edf69161" revision="1"/> <entry name="lambda" copied="true" kind="file" copyfrom-rev="1" schedule="add" copyfrom-url="http://svn.red-bean.com/repos/greek-tree/A/B/lambda"/> <entry committed-rev="1" name="gamma" text-time="2005-12-11T16:32:46.000000Z" committed-date="2005-04-04T13:32:28.526873Z" checksum="ada10d942b1964d359e048dbacff3460" last-author="jrandom" kind="file" prop-time="2005-12-11T16:32:45.000000Z"/> <entry name="zeta" kind="file" schedule="add" revision="0"/> <entry name="G" kind="dir"/> <entry name="H" kind="dir" schedule="delete"/> </wc-entries>
As you can see, the entries file is essentially a list of
entries. Each entry tag represents one of
three things: the working copy directory itself (called the
“this directory” entry, and noted as having an
empty value for its name
attribute), a file in that working copy directory (noted by
having its kind attribute set to
"file"), or a subdirectory in that working
copy (kind here is set to
"dir"). The files and subdirectories whose
entries are stored in this file are either already under
version control, or (as in the case of the file named
zeta above) are scheduled to be added to
version control when the user next commits this working copy
directory's changes. Each entry has a unique name, and each
entry has a node kind.
Developers should be aware of some special rules that
Subversion uses when reading and writing its
entries files. While each entry has a
revision and URL associated with it, note that not every
entry tag in the sample file has explicit
revision or
url attributes attached to it.
Subversion allows entries to not explicitly store those two
attributes when their values are the same as (in the
revision case) or trivially
calculable from
[48]
(in the url case) the data stored
in the “this directory” entry. Note also that
for subdirectory entries, Subversion stores only the crucial
attributes—name, kind, url, revision, and schedule. In
an effort to reduce duplicated information, Subversion
dictates that the method for determining the full set of
information about a subdirectory is to traverse down into that
subdirectory, and read the “this directory” entry
from its own .svn/entries file. However,
a reference to the subdirectory is kept in its parent's
entries file, with enough information to
permit basic versioning operations in the event that the
subdirectory itself is actually missing from disk.
As mentioned before, the .svn
directory also holds the pristine “text-base”
versions of files. Those can be found in
.svn/text-base. The benefits of these
pristine copies are multiple—network-free checks for
local modifications and difference reporting, network-free
reversion of modified or missing files, smaller transmission
of changes to the server—but comes at the cost of having
each versioned file stored at least twice on disk. These
days, this seems to be a negligible penalty for most files.
However, the situation gets uglier as the size of your
versioned files grows. Some attention is being given to
making the presence of the “text-base” an option.
Ironically though, it is as your versioned files' sizes get
larger that the existence of the “text-base”
becomes more crucial—who wants to transmit a huge file
across a network just because they want to commit a tiny
change to it?
Similar in purpose to the “text-base” files
are the property files and their pristine
“prop-base” copies, located in
.svn/props and
.svn/prop-base respectively. Since
directories can have properties, too, there are also
.svn/dir-props and
.svn/dir-prop-base files. Each of these
property files (“working” and “base”
versions) uses a simple “hash-on-disk” file
format for storing the property names and values.
WebDAV (shorthand for “Web-based Distributed Authoring and Versioning”) is an extension of the standard HTTP protocol designed to make the web into a read/write medium, instead of the basically read-only medium that exists today. The theory is that directories and files can be shared—as both readable and writable objects—over the web. RFCs 2518 and 3253 describe the WebDAV/DeltaV extensions to HTTP, and are available (along with a lot of other useful information) at http://www.webdav.org/.
A number of operating system file browsers are already able to mount networked directories using WebDAV. On Win32, the Windows Explorer can browse what it calls Web Folders (which are just WebDAV-ready network locations) as if they were regular shared folders. Mac OS X also has this capability, as do the Nautilus and Konqueror browsers (under GNOME and KDE, respectively).
How does all of this apply to Subversion? The mod_dav_svn Apache module uses HTTP, extended by WebDAV and DeltaV, as one of its network protocols. Subversion uses mod_dav_svn to map between Subversion's versioning concepts and those of RFCs 2518 and 3253.
For a more thorough discussion of WebDAV, how it works, and how Subversion uses it, see Tillegg C, WebDAV and Autoversioning. Among other things, that appendix discusses the degree to which Subversion adheres to the generic WebDAV specification, and how that affects interoperability with generic WebDAV clients.
[45] We understand that this may come as a shock to sci-fi fans who have long been under the impression that Time was actually the fourth dimension, and we apologize for any emotional trauma induced by our assertion of a different theory.
[46] Subversion uses ANSI system calls and datatypes as much as possible.
[47] Neon and Berkeley DB are examples of such libraries.
[48] That is, the URL for the entry is the same as the concatenation of the parent directory's URL and the entry's name.
Innholdsfortegnelse
This chapter is intended to be a complete reference to using Subversion. This includes the command line client (svn) and all its subcommands, as well as the repository administration programs (svnadmin and svnlook) and their respective subcommands.
To use the command line client, you type svn, the subcommand you wish to use [49], and any switches or targets that you wish to operate on—there is no specific order that the subcommand and the switches must appear in. For example, all of the following are valid ways to use svn status:
$ svn -v status $ svn status -v $ svn status -v myfile
You can find many more examples of how to use most client commands in Kapittel 2, Grunnleggende bruk and commands for managing properties in “Egenskaper”.
While Subversion has different switches for its
subcommands, all switches are global—that is, each
switch is guaranteed to mean the same thing regardless of
the subcommand you use it with. For example,
--verbose (-v) always
means “verbose output”, regardless of the
subcommand you use it with.
--auto-propsEnables auto-props, overriding the
enable-auto-props directive in the
config file.
--config-dir
DIRInstructs Subversion to read configuration
information from the specified directory instead of the
default location (.subversion in
the user's home directory).
--diff-cmd
CMDSpecifies an external program to use to show
differences between files. When svn
diff is invoked, it uses Subversion's internal
diff engine, which provides unified diffs by default.
If you want to use an external diff program, use
--diff-cmd. You can pass switches to
the diff program with the --extensions
switch (more on that later in this section).
--diff3-cmd
CMDSpecifies an external program to use to merge files.
--dry-runGoes through all the motions of running a command, but makes no actual changes—either on disk or in the repository.
--editor-cmd
CMDSpecifies an external program to use to edit a log message
or a property value. See the editor-cmd
section in “Konfigurasjon”
for ways to specify a default editor.
--encoding ENCTells Subversion that your commit message is encoded in the charset provided. The default is your operating system's native locale, and you should specify the encoding if your commit message is in any other encoding.
--extensions (-x)
ARGSSpecifies an argument or arguments that Subversion
should pass to an external diff command when providing
differences between files. If you wish to pass multiple
arguments, you must enclose all of them in quotes (for
example, svn diff --diff-cmd /usr/bin/diff -x
"-b -E"). This switch can
only be used if you also pass the
--diff-cmd switch.
--file (-F)
FILENAME
Uses the contents of the file passed as an argument to this switch for the specified subcommand.
--forceForces a particular command or operation to run. There are some operations that Subversion will prevent you from doing in normal usage, but you can pass the force switch to tell Subversion “I know what I'm doing as well as the possible repercussions of doing it, so let me at 'em”. This switch is the programmatic equivalent of doing your own electrical work with the power on—if you don't know what you're doing, you're likely to get a nasty shock.
--force-logForces a suspicious parameter passed to the
--message (-m) or
--file (-F) options to
be accepted as valid. By default, Subversion will
produce an error if parameters to these options look
like they might instead be targets of the subcommand.
For example, if you pass a versioned file's path to the
--file (-F) option,
Subversion will assume you've made a mistake, that the
path was instead intended as the target of the
operation, and that you simply failed to provide some
other—unversioned—file as the source of your log
message. To assert your intent and override these types
of errors, pass the --force-log option
to subcommands that accept log messages.
--help (-h or
-?)
If used with one or more subcommands, shows the built-in help text for each subcommand. If used alone, it displays the general client help text.
--ignore-ancestryTells Subversion to ignore ancestry when calculating differences (rely on path contents alone).
--ignore-externalsTells Subversion to ignore external definitions and the external working copies managed by them.
--incrementalPrints output in a format suitable for concatenation.
--limit
NUMShow only the first NUM
log messages.
--message (-m)
MESSAGE
Indicates that you will specify a commit message on the command line, following this switch. For example:
$ svn commit -m "They don't make Sunday."
--new ARGUses ARG as the newer
target.
--no-auth-cachePrevents caching of authentication information (e.g. username and password) in the Subversion administrative directories.
--no-auto-propsDisables auto-props, overriding the
enable-auto-props directive in the
config file.
--no-diff-addedPrevents Subversion from printing differences for added files. The default behavior when you add a file is for svn diff to print the same differences that you would see if you had added the entire contents of an existing (empty) file.
--no-diff-deletedPrevents Subversion from printing differences for deleted files. The default behavior when you remove a file is for svn diff to print the same differences that you would see if you had left the file but removed all the content.
--no-ignoreShows files in the status listing that would
normally be omitted since they match a pattern in the
global-ignores configuration option
or the svn:ignore property. See “Konfigurasjon” and “Ignoring Unversioned Items” for more
information.
--no-unlockDon't automatically unlock files (the default commit behavior is to unlock all files listed as part of the commit). See “Locking” for more information.
--non-interactiveIn the case of an authentication failure, or insufficient credentials, prevents prompting for credentials (e.g. username or password). This is useful if you're running Subversion inside of an automated script and it's more appropriate to have Subversion fail than to prompt for more information.
--non-recursive (-N)Stops a subcommand from recursing into subdirectories. Most subcommands recurse by default, but some subcommands—usually those that have the potential to remove or undo your local modifications—do not.
--notice-ancestryPay attention to ancestry when calculating differences.
--old ARGUses ARG as the older
target.
--password
PASSIndicates that you are providing your password for authentication on the command line—otherwise, if it is needed, Subversion will prompt you for it.
--quiet (-q)Requests that the client print only essential information while performing an operation.
--recursive (-R)Makes a subcommand recurse into subdirectories. Most subcommands recurse by default.
--relocate FROM TO
[PATH...]Used with the svn switch subcommand, changes the location of the repository that your working copy references. This is useful if the location of your repository changes and you have an existing working copy that you'd like to continue to use. See svn switch for an example.
--revision (-r)
REV
Indicates that you're going to supply a revision (or range of revisions) for a particular operation. You can provide revision numbers, revision keywords or dates (in curly braces), as arguments to the revision switch. If you wish to provide a range of revisions, you can provide two revisions separated by a colon. For example:
$ svn log -r 1729
$ svn log -r 1729:HEAD
$ svn log -r 1729:1744
$ svn log -r {2001-12-04}:{2002-02-17}
$ svn log -r 1729:{2002-02-17}
See “Nøkkelord for revisjoner” for more information.
--revpropOperates on a revision property instead of a
Subversion property specific to a file or directory.
This switch requires that you also pass a revision
with the --revision
(-r) switch. See “Uversjonerte egenskaper” for more details on
unversioned properties.
--show-updates (-u)Causes the client to display information about which files in your working copy are out-of-date. This doesn't actually update any of your files—it just shows you which files will be updated if you run svn update.
--stop-on-copyCauses a Subversion subcommand which is traversing the history of a versioned resource to stop harvesting that historical information when a copy—that is, a location in history where that resource was copied from another location in the repository—is encountered.
--strictCauses Subversion to use strict semantics, a notion which is rather vague unless talking about specific subcommands.
--targets
FILENAMETells Subversion to get the list of files that you wish to operate on from the filename you provide instead of listing all the files on the command line.
--username
NAMEIndicates that you are providing your username for authentication on the command line—otherwise, if it is needed, Subversion will prompt you for it.
--verbose (-v)Requests that the client print out as much information as it can while running any subcommand. This may result in Subversion printing out additional fields, detailed information about every file, or additional information regarding its actions.
--versionPrints the client version info. This information
not only includes the version number of the client,
but also a listing of all repository access modules
that the client can use to access a Subversion
repository. With --quiet
(-q) it prints only the version number
in a compact form.
--xmlPrints output in XML format.
svn add — Add files, directories, or symbolic links.
Add files, directories, or symbolic links to your working copy and schedule them for addition to the repository. They will be uploaded and added to the repository on your next commit. If you add something and change your mind before committing, you can unschedule the addition using svn revert.
--targets FILENAME --non-recursive (-N) --quiet (-q) --config-dir DIR --auto-props --no-auto-props --force
To add a file to your working copy:
$ svn add foo.c A foo.c
When adding a directory, the default behavior of svn add is to recurse:
$ svn add testdir A testdir A testdir/a A testdir/b A testdir/c A testdir/d
You can add a directory without adding its contents:
$ svn add --non-recursive otherdir A otherdir
Normally, the command svn add *
will skip over any directories that are already under
version control. Sometimes, however, you may want to add
every unversioned object in your working copy, including
those hiding deeper down. Passing the
--force option makes svn
add recurse into versioned directories:
$ svn add * --force A foo.c A somedir/bar.c A otherdir/docs/baz.doc …
svn blame — Show author and revision information in-line for the specified files or URLs.
Show author and revision information in-line for the specified files or URLs. Each line of text is annotated at the beginning with the author (username) and the revision number for the last change to that line.
svn cat — Output the contents of the specified files or URLs.
Output the contents of the specified files or URLs. For listing the contents of directories, see svn list.
--revision (-r) REV --username USER --password PASS --no-auth-cache --non-interactive --config-dir DIR
If you want to view readme.txt in your repository without checking it out:
$ svn cat http://svn.red-bean.com/repos/test/readme.txt This is a README file. You should read this.
![]() | Tips |
|---|---|
If your working copy is out of date (or you have
local modifications) and you want to see the
|
$ cat foo.c This file is in my local working copy and has changes that I've made. $ svn cat foo.c Latest revision fresh from the repository!
svn checkout — Check out a working copy from a repository.
Check out a working copy from a repository. If
PATH is omitted, the
basename of the URL will be used as the destination.
If multiple URLs are given each will be checked out into a
subdirectory of PATH, with the
name of the subdirectory being the basename of the
URL.
--revision (-r) REV --quiet (-q) --non-recursive (-N) --username USER --password PASS --no-auth-cache --non-interactive --ignore-externals --config-dir DIR
Check out a working copy into a directory called
mine:
$ svn checkout file:///tmp/repos/test mine A mine/a A mine/b Checked out revision 2. $ ls mine
Check out 2 different directories into two separate working copies:
$ svn checkout file:///tmp/repos/test file:///tmp/repos/quiz A test/a A test/b Checked out revision 2. A quiz/l A quiz/m Checked out revision 2. $ ls quiz test
Check out 2 different directories into two separate
working copies, but place both into a directory called
working-copies:
$ svn checkout file:///tmp/repos/test file:///tmp/repos/quiz working-copies A working-copies/test/a A working-copies/test/b Checked out revision 2. A working-copies/quiz/l A working-copies/quiz/m Checked out revision 2. $ ls working-copies
If you interrupt a checkout (or something else interrupts your checkout like loss of connectivity, etc.), you can restart it either by issuing the identical checkout command again, or by updating the incomplete working copy:
$ svn checkout file:///tmp/repos/test test A test/a A test/b ^C svn: The operation was interrupted svn: caught SIGINT $ svn checkout file:///tmp/repos/test test A test/c A test/d ^C svn: The operation was interrupted svn: caught SIGINT $ cd test $ svn update A test/e A test/f Updated to revision 3.
svn cleanup — Recursively clean up the working copy.
Recursively clean up the working copy, removing working copy locks and resuming unfinished operations. If you ever get a “working copy locked” error, run this command to remove stale locks and get your working copy into a usable state again.
If, for some reason, an svn update
fails due to a problem running an external diff program
(e.g. user input or network failure), pass the
--diff3-cmd to allow cleanup to complete
any merging with your external diff program. You can also
specify any configuration directory with the
--config-dir switch, but you should need
these switches extremely infrequently.
svn commit — Send changes from your working copy to the repository.
Send changes from your working copy to the
repository. If you do not supply a log message with your
commit by using either the --file or
--message switch,
svn will launch your editor for you
to compose a commit message. See the
editor-cmd section in “Konfigurasjon”.
svn commit will send found lock
tokens and release locks on all
PATHS committed (recursively)
unless --no-unlock is passed.
![]() | Tips |
|---|---|
If you begin a commit and Subversion launches your editor to compose the commit message, you can still abort without committing your changes. If you want to cancel your commit, just quit your editor without saving your commit message and Subversion will prompt you to either abort the commit, continue with no message, or edit the message again. |
--message (-m) TEXT --file (-F) FILE --quiet (-q) --no-unlock --non-recursive (-N) --targets FILENAME --force-log --username USER --password PASS --no-auth-cache --non-interactive --encoding ENC --config-dir DIR
Commit a simple modification to a file with the
commit message on the command line and an implicit
target of your current directory
(“.”):
$ svn commit -m "added howto section." Sending a Transmitting file data . Committed revision 3.
Commit a modification to the file
foo.c (explicitly specified on the
command line) with the commit message in a file named
msg:
$ svn commit -F msg foo.c Sending foo.c Transmitting file data . Committed revision 5.
If you want to use a file that's under version
control for your commit message with
--file, you need to pass the
--force-log switch:
$ svn commit --file file_under_vc.txt foo.c svn: The log message file is under version control svn: Log message file is a versioned file; use '--force-log' to override $ svn commit --force-log --file file_under_vc.txt foo.c Sending foo.c Transmitting file data . Committed revision 6.
To commit a file scheduled for deletion:
$ svn commit -m "removed file 'c'." Deleting c Committed revision 7.
svn copy — Copy a file or directory in a working copy or in the repository.
Copy a file in a working copy or in the repository.
SRC and
DST can each be either a
working copy (WC) path or URL:
Copy and schedule an item for addition (with history).
Immediately commit a copy of WC to URL.
Check out URL into WC, and schedule it for addition.
Complete server-side copy. This is usually used to branch and tag.
![]() | Notat |
|---|---|
You can only copy files within a single repository. Subversion does not support cross-repository copying. |
If source or destination is in the repository, or if needed to look up the source revision number.
--message (-m) TEXT --file (-F) FILE --revision (-r) REV --quiet (-q) --username USER --password PASS --no-auth-cache --non-interactive --force-log --editor-cmd EDITOR --encoding ENC --config-dir DIR
Copy an item within your working copy (just schedules the copy—nothing goes into the repository until you commit):
$ svn copy foo.txt bar.txt A bar.txt $ svn status A + bar.txt
Copy an item in your working copy to a URL in the repository (an immediate commit, so you must supply a commit message):
$ svn copy near.txt file:///tmp/repos/test/far-away.txt -m "Remote copy." Committed revision 8.
Copy an item from the repository to your working copy (just schedules the copy—nothing goes into the repository until you commit):
![]() | Tips |
|---|---|
This is the recommended way to resurrect a dead file in your repository! |
$ svn copy file:///tmp/repos/test/far-away near-here A near-here
And finally, copying between two URLs:
$ svn copy file:///tmp/repos/test/far-away file:///tmp/repos/test/over-there -m "remote copy." Committed revision 9.
![]() | Tips |
|---|---|
This is the easiest way to “tag” a
revision in your repository—just svn
copy that revision (usually
|
$ svn copy file:///tmp/repos/test/trunk file:///tmp/repos/test/tags/0.6.32-prerelease -m "tag tree" Committed revision 12.
And don't worry if you forgot to tag—you can always specify an older revision and tag anytime:
$ svn copy -r 11 file:///tmp/repos/test/trunk file:///tmp/repos/test/tags/0.6.32-prerelease -m "Forgot to tag at rev 11" Committed revision 13.
svn delete — Delete an item from a working copy or the repository.
Items specified by PATH are scheduled
for deletion upon the next commit. Files (and
directories that have not been committed) are
immediately removed from the working copy. The command
will not remove any unversioned or modified items; use
the --force switch to override this
behavior.
Items specified by URL are deleted from the repository via an immediate commit. Multiple URLs are committed atomically.
--force --force-log --message (-m) TEXT --file (-F) FILE --quiet (-q) --targets FILENAME --username USER --password PASS --no-auth-cache --non-interactive --editor-cmd EDITOR --encoding ENC --config-dir DIR
Using svn to delete a file from your working copy merely schedules it to be deleted. When you commit, the file is deleted in the repository.
$ svn delete myfile D myfile $ svn commit -m "Deleted file 'myfile'." Deleting myfile Transmitting file data . Committed revision 14.
Deleting a URL, however, is immediate, so you have to supply a log message:
$ svn delete -m "Deleting file 'yourfile'" file:///tmp/repos/test/yourfile Committed revision 15.
Here's an example of how to force deletion of a file that has local mods:
$ svn delete over-there svn: Attempting restricted operation for modified resource svn: Use --force to override this restriction svn: 'over-there' has local modifications $ svn delete --force over-there D over-there
svn diff — Display the differences between two paths.
diff [-r N[:M]] [TARGET[@REV]...]
diff [-r N[:M]] --old OLD-TGT[@OLDREV] [--new NEW-TGT[@NEWREV]] [PATH...]
diff OLD-URL[@OLDREV] NEW-URL[@NEWREV]
Display the differences between two paths. The three different ways you can use svn diff are:
svn diff [-r N[:M]] [--old OLD-TGT] [--new
NEW-TGT] [PATH...] displays the differences
between OLD-TGT and
NEW-TGT. If
PATHs are given, they are
treated as relative to OLD-TGT
and NEW-TGT and the output is
restricted to differences in only those paths.
OLD-TGT and
NEW-TGT may be working copy
paths or
URL[@REV].
OLD-TGT defaults to the current
working directory and NEW-TGT
defaults to OLD-TGT.
N defaults to
BASE or, if
OLD-TGT is a URL, to
HEAD. M
defaults to the current working version or, if
NEW-TGT is a URL, to
HEAD. svn diff -r N
sets the revision of OLD-TGT to
N, svn diff -r
N:M also sets the revision of
NEW-TGT to
M.
svn diff -r N:M URL is shorthand for svn diff -r N:M --old=URL --new=URL.
svn diff [-r N[:M]] URL1[@N] URL2[@M] is shorthand for svn diff [-r N[:M]] --old=URL1 --new=URL2.
If TARGET is a URL, then
revs N and M can be given either via the
--revision or by using
“@” notation as described earlier.
If TARGET is a working copy
path, then the --revision switch
means:
--revision N:MThe server compares
TARGET@N
and
TARGET@M.
--revision NThe client compares
TARGET@N
against working copy.
--revision)The client compares base and working copies of
TARGET.
If the alternate syntax is used, the server compares
URL1 and
URL2 at revisions
N and
M respectively. If either
N or
M are omitted, a value of
HEAD is assumed.
By default, svn diff ignores the
ancestry of files and merely compares the contents of the
two files being compared. If you use
--notice-ancestry, the ancestry of the
paths in question will be taken into consideration when
comparing revisions (that is, if you run svn
diff on two files with identical contents but
different ancestry you will see the entire contents of the
file as having been removed and added again).
For obtaining differences against anything but
BASE revision in your working copy
--revision (-r) REV --old OLD-TARGET --new NEW-TARGET --extensions (-x) "ARGS" --non-recursive (-N) --diff-cmd CMD --notice-ancestry --username USER --password PASS --no-auth-cache --non-interactive --no-diff-deleted --config-dir DIR
Compare BASE and your working copy
(one of the most popular uses of svn
diff):
$ svn diff COMMITTERS Index: COMMITTERS =================================================================== --- COMMITTERS (revision 4404) +++ COMMITTERS (working copy)
See how your working copy's modifications compare against an older revision:
$ svn diff -r 3900 COMMITTERS Index: COMMITTERS =================================================================== --- COMMITTERS (revision 3900) +++ COMMITTERS (working copy)
Compare revision 3000 to revision 3500 using “@” syntax:
$ svn diff http://svn.collab.net/repos/svn/trunk/COMMITTERS@3000 http://svn.collab.net/repos/svn/trunk/COMMITTERS@3500 Index: COMMITTERS =================================================================== --- COMMITTERS (revision 3000) +++ COMMITTERS (revision 3500) …
Compare revision 3000 to revision 3500 using range notation (you only pass the one URL in this case):
$ svn diff -r 3000:3500 http://svn.collab.net/repos/svn/trunk/COMMITTERS Index: COMMITTERS =================================================================== --- COMMITTERS (revision 3000) +++ COMMITTERS (revision 3500)
Compare revision 3000 to revision 3500 of all files in
trunk using range notation:
$ svn diff -r 3000:3500 http://svn.collab.net/repos/svn/trunk
Compare revision 3000 to revision 3500 of only three
files in trunk using range
notation:
$ svn diff -r 3000:3500 --old http://svn.collab.net/repos/svn/trunk COMMITTERS README HACKING
If you have a working copy, you can obtain the differences without typing in the long URLs:
$ svn diff -r 3000:3500 COMMITTERS Index: COMMITTERS =================================================================== --- COMMITTERS (revision 3000) +++ COMMITTERS (revision 3500)
Use --diff-cmd
CMD -x to
pass arguments directly to the external diff
program
$ svn diff --diff-cmd /usr/bin/diff -x "-i -b" COMMITTERS Index: COMMITTERS =================================================================== 0a1,2 > This is a test >
svn export — Export a clean directory tree.
The first form exports a clean directory tree from the
repository specified by URL, at revision
REV if it is given, otherwise
at HEAD, into
PATH. If
PATH is omitted, the last
component of the URL is used
for the local directory name.
The second form exports a clean directory tree from
the working copy specified by
PATH1 into
PATH2. All local changes will
be preserved, but files not under version control will not
be copied.
--revision (-r) REV --quiet (-q) --force --username USER --password PASS --no-auth-cache --non-interactive --non-recursive (-N) --config-dir DIR --native-eol EOL --ignore-externals
Export from your working copy (doesn't print every file and directory):
$ svn export a-wc my-export Export complete.
Export directly from the repository (prints every file and directory):
$ svn export file:///tmp/repos my-export A my-export/test A my-export/quiz … Exported revision 15.
When rolling operating-system-specific release
packages, it can be useful to export a tree which uses a
specific EOL character for line endings. The
--native-eol option will do this, but it
only affects files that have svn:eol-style =
native properties attached to them. For
example, to export a tree with all CRLF line endings
(possibly for a Windows .zip file distribution):
$ svn export file://tmp/repos my-export --native-eol CRLF A my-export/test A my-export/quiz … Exported revision 15.
svn import — Commit an unversioned file or tree into the repository.
Recursively commit a copy of
PATH to
URL. If
PATH is omitted
“.” is assumed. Parent
directories are created in the repository as
necessary.
--message (-m) TEXT --file (-F) FILE --quiet (-q) --non-recursive (-N) --username USER --password PASS --no-auth-cache --non-interactive --force-log --editor-cmd EDITOR --encoding ENC --config-dir DIR --auto-props --no-auto-props --ignore-externals
This imports the local directory myproj into the
root of your repository:
$ svn import -m "New import" myproj http://svn.red-bean.com/repos/test Adding myproj/sample.txt … Transmitting file data ......... Committed revision 16.
This imports the local directory myproj
into trunk/misc in your repository. The
directory trunk/misc need not exist before
you import into it—svn import will
recursively create directories for you:
$ svn import -m "New import" myproj \
http://svn.red-bean.com/repos/test/trunk/misc/myproj
Adding myproj/sample.txt
…
Transmitting file data .........
Committed revision 19.
After importing data, note that the original tree is not under version control. To start working, you still need to svn checkout a fresh working copy of the tree.
svn info — Display information about a local or remote item.
Print information about the working copy paths or URLs specified. The information shown for both may include:
Path
Name
URL
Repository Root
Repository UUID
Revision
Node Kind
Last Changed Author
Last Changed Revision
Last Changed Date
Lock Token
Lock Owner
Lock Created (date)
Lock Expires (date)
Additional kinds of information available only for working copy paths are:
Schedule
Copied From URL
Copied From Rev
Text Last Updated
Properties Last Updated
Checksum
Conflict Previous Base File
Conflict Previous Working File
Conflict Current Base File
Conflict Properties File
--revision (-r) REV --recursive (-R) --targets FILENAME --incremental --xml --username USER --password PASS --no-auth-cache --non-interactive --config-dir DIR
svn info will show you all the useful information that it has for items in your working copy. It will show information for files:
$ svn info foo.c Path: foo.c Name: foo.c URL: http://svn.red-bean.com/repos/test/foo.c Repository Root: http://svn.red-bean.com/repos/test Repository UUID: 5e7d134a-54fb-0310-bd04-b611643e5c25 Revision: 4417 Node Kind: file Schedule: normal Last Changed Author: sally Last Changed Rev: 20 Last Changed Date: 2003-01-13 16:43:13 -0600 (Mon, 13 Jan 2003) Text Last Updated: 2003-01-16 21:18:16 -0600 (Thu, 16 Jan 2003) Properties Last Updated: 2003-01-13 21:50:19 -0600 (Mon, 13 Jan 2003) Checksum: d6aeb60b0662ccceb6bce4bac344cb66
It will also show information for directories:
$ svn info vendors Path: vendors URL: http://svn.red-bean.com/repos/test/vendors Repository Root: http://svn.red-bean.com/repos/test Repository UUID: 5e7d134a-54fb-0310-bd04-b611643e5c25 Revision: 19 Node Kind: directory Schedule: normal Last Changed Author: harry Last Changed Rev: 19 Last Changed Date: 2003-01-16 23:21:19 -0600 (Thu, 16 Jan 2003) Properties Last Updated: 2003-01-16 23:39:02 -0600 (Thu, 16 Jan 2003)
svn info also acts on URLs (also note that the file readme.doc in this example is locked, so lock information is also provided):
$ svn info http://svn.red-bean.com/repos/test/readme.doc Path: readme.doc Name: readme.doc URL: http://svn.red-bean.com/repos/test/readme.doc Repository Root: http://svn.red-bean.com/repos/test Repository UUID: 5e7d134a-54fb-0310-bd04-b611643e5c25 Revision: 1 Node Kind: file Schedule: normal Last Changed Author: sally Last Changed Rev: 42 Last Changed Date: 2003-01-14 23:21:19 -0600 (Tue, 14 Jan 2003) Lock Token: opaquelocktoken:14011d4b-54fb-0310-8541-dbd16bd471b2 Lock Owner: harry Lock Created: 2003-01-15 17:35:12 -0600 (Wed, 15 Jan 2003) Lock Comment (1 line): My test lock comment
svn list — List directory entries in the repository.
List each TARGET file and
the contents of each TARGET
directory as they exist in the repository. If
TARGET is a working copy path,
the corresponding repository URL will be used.
The default TARGET is
“.”, meaning the
repository URL of the current working copy
directory.
With --verbose, the following fields show
the status of the item:
Revision number of the last commit
Author of the last commit
Size (in bytes)
Date and time of the last commit
With --xml, output is in XML format (with
a header and an enclosing document element unless
--incremental is also specified). All of the
information is present; the --verbose option
is not accepted.
--revision (-r) REV --verbose (-v) --recursive (-R) --incremental --xml --username USER --password PASS --no-auth-cache --non-interactive --config-dir DIR
svn list is most useful if you want to see what files a repository has without downloading a working copy:
$ svn list http://svn.red-bean.com/repos/test/support README.txt INSTALL examples/ …
You can pass the --verbose switch for
additional information, rather like the UNIX command
ls -l:
$ svn list --verbose file:///tmp/repos
16 sally 28361 Jan 16 23:18 README.txt
27 sally 0 Jan 18 15:27 INSTALL
24 harry Jan 18 11:27 examples/
For further details, see “svn list”.
svn lock — Lock working copy paths or URLs in the repository, so that no other user can commit changes to them.
Lock each TARGET. If any
TARGET is already locked by
another user, print a warning and continue locking the
rest of the TARGETs. Use
--force to steal a lock from another user
or working copy.
--targets FILENAME --message (-m) TEXT --file (-F) FILE --force-log --encoding ENC --username USER --password PASS --no-auth-cache --non-interactive --config-dir DIR --force
Lock two files in your working copy:
$ svn lock tree.jpg house.jpg 'tree.jpg' locked by user 'harry'. 'house.jpg' locked by user 'harry'.
Lock a file in your working copy that is currently locked by another user:
$ svn lock tree.jpg
svn: warning: Path '/tree.jpg is already locked by user 'harry in \
filesystem '/svn/repos/db'
$ svn lock --force foo
'tree.jpg' locked by user 'sally'.
Lock a file without a working copy:
$ svn lock http://svn.red-bean.com/repos/test/tree.jpg 'tree.jpg' locked by user 'sally'.
For further details, see “Locking”.
svn log — Display commit log messages.
The default target is the path of your current
directory. If no arguments are supplied, svn
log shows the log messages for all files and
directories inside of (and including) the current working
directory of your working copy. You can refine the
results by specifying a path, one or more revisions, or
any combination of the two. The default revision range
for a local path is BASE:1.
If you specify a URL alone, then it prints log
messages for everything that the URL contains. If you
add paths past the URL, only messages for those paths
under that URL will be printed. The default revision range
for a URL is HEAD:1.
With --verbose, svn log
will also print all affected paths with each log message.
With --quiet, svn log
will not print the log message body itself (this is
compatible with --verbose).
Each log message is printed just once, even if more
than one of the affected paths for that revision were
explicitly requested. Logs follow copy history by
default. Use --stop-on-copy to disable
this behavior, which can be useful for determining branch
points.
--revision (-r) REV --quiet (-q) --verbose (-v) --targets FILENAME --stop-on-copy --incremental --limit NUM --xml --username USER --password PASS --no-auth-cache --non-interactive --config-dir DIR
You can see the log messages for all the paths that changed in your working copy by running svn log from the top:
$ svn log ------------------------------------------------------------------------ r20 | harry | 2003-01-17 22:56:19 -0600 (Fri, 17 Jan 2003) | 1 line Tweak. ------------------------------------------------------------------------ r17 | sally | 2003-01-16 23:21:19 -0600 (Thu, 16 Jan 2003) | 2 lines …
Examine all log messages for a particular file in your working copy:
$ svn log foo.c ------------------------------------------------------------------------ r32 | sally | 2003-01-13 00:43:13 -0600 (Mon, 13 Jan 2003) | 1 line Added defines. ------------------------------------------------------------------------ r28 | sally | 2003-01-07 21:48:33 -0600 (Tue, 07 Jan 2003) | 3 lines …
If you don't have a working copy handy, you can log a URL:
$ svn log http://svn.red-bean.com/repos/test/foo.c ------------------------------------------------------------------------ r32 | sally | 2003-01-13 00:43:13 -0600 (Mon, 13 Jan 2003) | 1 line Added defines. ------------------------------------------------------------------------ r28 | sally | 2003-01-07 21:48:33 -0600 (Tue, 07 Jan 2003) | 3 lines …
If you want several distinct paths underneath the
same URL, you can use the URL [PATH...]
syntax.
$ svn log http://svn.red-bean.com/repos/test/ foo.c bar.c ------------------------------------------------------------------------ r32 | sally | 2003-01-13 00:43:13 -0600 (Mon, 13 Jan 2003) | 1 line Added defines. ------------------------------------------------------------------------ r31 | harry | 2003-01-10 12:25:08 -0600 (Fri, 10 Jan 2003) | 1 line Added new file bar.c ------------------------------------------------------------------------ r28 | sally | 2003-01-07 21:48:33 -0600 (Tue, 07 Jan 2003) | 3 lines …
When you're concatenating the results of multiple
calls to the log command, you may want to use the
--incremental switch. svn
log normally prints out a dashed line at the
beginning of a log message, after each subsequent log
message, and following the final log message. If you
ran svn log on a range of two
revisions, you would get this:
$ svn log -r 14:15 ------------------------------------------------------------------------ r14 | … ------------------------------------------------------------------------ r15 | … ------------------------------------------------------------------------
However, if you wanted to gather 2 non-sequential log messages into a file, you might do something like this:
$ svn log -r 14 > mylog $ svn log -r 19 >> mylog $ svn log -r 27 >> mylog $ cat mylog ------------------------------------------------------------------------ r14 | … ------------------------------------------------------------------------ ------------------------------------------------------------------------ r19 | … ------------------------------------------------------------------------ ------------------------------------------------------------------------ r27 | … ------------------------------------------------------------------------
You can avoid the clutter of the double dashed lines in your output by using the incremental switch:
$ svn log --incremental -r 14 > mylog $ svn log --incremental -r 19 >> mylog $ svn log --incremental -r 27 >> mylog $ cat mylog ------------------------------------------------------------------------ r14 | … ------------------------------------------------------------------------ r19 | … ------------------------------------------------------------------------ r27 | …
The --incremental switch provides
similar output control when using the
--xml switch.
![]() | Tips |
|---|---|
If you run svn log on a specific path and provide a specific revision and get no output at all $ svn log -r 20 http://svn.red-bean.com/untouched.txt ------------------------------------------------------------------------ That just means that the path was not modified in that revision. If you log from the top of the repository, or know the file that changed in that revision, you can specify it explicitly: $ svn log -r 20 touched.txt ------------------------------------------------------------------------ r20 | sally | 2003-01-17 22:56:19 -0600 (Fri, 17 Jan 2003) | 1 line Made a change. ------------------------------------------------------------------------ |
svn merge — Apply the differences between two sources to a working copy path.
svn merge sourceURL1[@N] sourceURL2[@M] [WCPATH]
svn merge sourceWCPATH1@N sourceWCPATH2@M [WCPATH]
svn merge -r N:M SOURCE[@REV] [WCPATH]
In the first and second forms, the source paths (URLs
in the first form, working copy paths in the second) are
specified at revisions N and
M. These are the two sources
to be compared. The revisions default to
HEAD if omitted.
In the third form, SOURCE
can be a URL or working copy item, in which case the
corresponding URL is used. This URL, at revisions
N and
M, defines the two sources to
be compared.
WCPATH is the working copy
path that will receive the changes. If
WCPATH is omitted, a default
value of “.” is assumed,
unless the sources have identical basenames that match a
file within “.”: in which
case, the differences will be applied to that file.
Unlike svn diff, the merge command takes the ancestry of a file into consideration when performing a merge operation. This is very important when you're merging changes from one branch into another and you've renamed a file on one branch but not the other.
--revision (-r) REV --non-recursive (-N) --quiet (-q) --force --dry-run --diff3-cmd CMD --ignore-ancestry --username USER --password PASS --no-auth-cache --non-interactive --config-dir DIR
Merge a branch back into the trunk (assuming that you have a working copy of the trunk, and that the branch was created in revision 250):
$ svn merge -r 250:HEAD http://svn.red-bean.com/repos/branches/my-branch U myproj/tiny.txt U myproj/thhgttg.txt U myproj/win.txt U myproj/flo.txt
If you branched at revision 23, and you want to merge changes on trunk into your branch, you could do this from inside the working copy of your branch:
$ svn merge -r 23:30 file:///tmp/repos/trunk/vendors U myproj/thhgttg.txt …
To merge changes to a single file:
$ cd myproj $ svn merge -r 30:31 thhgttg.txt U thhgttg.txt
svn mkdir — Create a new directory under version control.
Create a directory with a name given by the final
component of the PATH or URL.
A directory specified by a working copy
PATH is scheduled for addition
in the working copy. A directory specified by a URL is
created in the repository via an immediate commit.
Multiple directory URLs are committed atomically. In both
cases all the intermediate directories must already
exist.
svn move — Move a file or directory.
This command moves a file or directory in your working copy or in the repository.
![]() | Tips |
|---|---|
This command is equivalent to an svn copy followed by svn delete. |
![]() | Notat |
|---|---|
Subversion does not support moving between working copies and URLs. In addition, you can only move files within a single repository—Subversion does not support cross-repository moving. |
Move and schedule a file or directory for addition (with history).
Complete server-side rename.
svn propdel — Remove a property from an item.
This removes properties from files, directories, or revisions. The first form removes versioned properties in your working copy, while the second removes unversioned remote properties on a repository revision.
svn propedit — Edit the property of one or more items under version control.
Edit one or more properties using your favorite editor. The first form edits versioned properties in your working copy, while the second edits unversioned remote properties on a repository revision.
--revision (-r) REV --revprop --username USER --password PASS --no-auth-cache --non-interactive --encoding ENC --editor-cmd EDITOR --config-dir DIR
svn propedit makes it easy to modify properties that have multiple values:
$ svn propedit svn:keywords foo.c
<svn will launch your favorite editor here, with a buffer open
containing the current contents of the svn:keywords property. You
can add multiple values to a property easily here by entering one
value per line.>
Set new value for property 'svn:keywords' on 'foo.c'
svn propget — Print the value of a property.
Print the value of a property on files, directories, or revisions. The first form prints the versioned property of an item or items in your working copy, while the second prints unversioned remote property on a repository revision. See “Egenskaper” for more information on properties.
svn proplist — List all properties.
List all properties on files, directories, or revisions. The first form lists versioned properties in your working copy, while the second lists unversioned remote properties on a repository revision.
--verbose (-v) --recursive (-R) --revision (-r) REV --quiet (-q) --revprop --username USER --password PASS --no-auth-cache --non-interactive --config-dir DIR
You can use proplist to see the properties on an item in your working copy:
$ svn proplist foo.c Properties on 'foo.c': svn:mime-type svn:keywords owner
But with the --verbose flag, svn
proplist is extremely handy as it also shows you the
values for the properties:
$ svn proplist --verbose foo.c Properties on 'foo.c': svn:mime-type : text/plain svn:keywords : Author Date Rev owner : sally
svn propset — Set PROPNAME to PROPVAL on files, directories, or revisions.
svn propset PROPNAME [PROPVAL | -F VALFILE] PATH...
svn propset PROPNAME --revprop -r REV [PROPVAL | -F VALFILE] [URL]
Set PROPNAME to
PROPVAL on files, directories,
or revisions. The first example creates a versioned, local
property change in the working copy, and the second
creates an unversioned, remote property change on a
repository revision.
![]() | Tips |
|---|---|
Subversion has a number of “special” properties that affect its behavior. See “Subversion properties” for more on these properties. |
--file (-F) FILE --quiet (-q) --revision (-r) REV --targets FILENAME --recursive (-R) --revprop --username USER --password PASS --no-auth-cache --non-interactive --encoding ENC --force --config-dir DIR
Set the mimetype on a file:
$ svn propset svn:mime-type image/jpeg foo.jpg property 'svn:mime-type' set on 'foo.jpg'
On a UNIX system, if you want a file to have the executable permission set:
$ svn propset svn:executable ON somescript property 'svn:executable' set on 'somescript'
Perhaps you have an internal policy to set certain properties for the benefit of your coworkers:
$ svn propset owner sally foo.c property 'owner' set on 'foo.c'
If you made a mistake in a log message for a
particular revision and want to change it, use
--revprop and set svn:log
to the new log message:
$ svn propset --revprop -r 25 svn:log "Journaled about trip to New York." property 'svn:log' set on repository revision '25'
Or, if you don't have a working copy, you can provide a URL.
$ svn propset --revprop -r 26 svn:log "Document nap." http://svn.red-bean.com/repos property 'svn:log' set on repository revision '25'
Lastly, you can tell propset to take its input from a file. You could even use this to set the contents of a property to something binary:
$ svn propset owner-pic -F sally.jpg moo.c property 'owner-pic' set on 'moo.c'
![]() | Notat |
|---|---|
By default, you cannot modify revision properties
in a Subversion repository. Your repository
administrator must explicitly enable revision property
modifications by creating a hook named
|
svn resolved — Remove “conflicted” state on working copy files or directories.
Remove “conflicted” state on working copy
files or directories. This routine does not semantically
resolve conflict markers; it merely removes
conflict-related artifact files and allows
PATH to be committed again;
that is, it tells Subversion that the conflicts have been
“resolved”. See “Løse konflikter (Flette inn andres forandringer)” for an in-depth look at
resolving conflicts.
If you get a conflict on an update, your working copy will sprout three new files:
$ svn update C foo.c Updated to revision 31. $ ls foo.c foo.c.mine foo.c.r30 foo.c.r31
Once you've resolved the conflict and
foo.c is ready to be committed, run
svn resolved to let your working copy
know you've taken care of everything.
![]() | Advarsel |
|---|---|
You can just remove the conflict files and commit, but svn resolved fixes up some bookkeeping data in the working copy administrative area in addition to removing the conflict files, so we recommend that you use this command. |
svn revert — Undo all local edits.
Reverts any local changes to a file or directory and resolves any conflicted states. svn revert will not only revert the contents of an item in your working copy, but also any property changes. Finally, you can use it to undo any scheduling operations that you may have done (e.g. files scheduled for addition or deletion can be “unscheduled”).
Discard changes to a file:
$ svn revert foo.c Reverted foo.c
If you want to revert a whole directory of files,
use the --recursive flag:
$ svn revert --recursive . Reverted newdir/afile Reverted foo.c Reverted bar.txt
Lastly, you can undo any scheduling operations:
$ svn add mistake.txt whoops A mistake.txt A whoops A whoops/oopsie.c $ svn revert mistake.txt whoops Reverted mistake.txt Reverted whoops $ svn status ? mistake.txt ? whoops
![]() | Notat |
|---|---|
If you provide no targets to svn revert, it will do nothing—to protect you from accidentally losing changes in your working copy, svn revert requires you to provide at least one target. |
svn status — Print the status of working copy files and directories.
Print the status of working copy files and
directories. With no arguments, it prints only locally
modified items (no repository access). With
--show-updates, add working revision
and server out-of-date information. With
--verbose, print full revision
information on every item.
The first six columns in the output are each one character wide, and each column gives you information about different aspects of each working copy item.
The first column indicates that an item was added, deleted, or otherwise changed.
No modifications.
Item is scheduled for Addition.
Item is scheduled for Deletion.
Item has been modified.
Item has been replaced in your working copy. This means the file was scheduled for deletion, and then a new file with the same name was scheduled for addition in its place.
The contents (as opposed to the properties) of the item conflict with updates received from the repository.
Item is related to an externals definition.
Item is being ignored (e.g. with the
svn:ignore property).
Item is not under version control.
Item is missing (e.g. you moved or deleted it without using svn). This also indicates that a directory is incomplete (a checkout or update was interrupted).
Item is versioned as one kind of object (file, directory, link), but has been replaced by different kind of object.
The second column tells the status of a file's or directory's properties.
No modifications.
Properties for this item have been modified.
Properties for this item are in conflict with property updates received from the repository.
The third column is populated only if the working copy directory is locked. (See “svn cleanup”.)
Item is not locked.
Item is locked.
The fourth column is populated only if the item is scheduled for addition-with-history.
No history scheduled with commit.
History scheduled with commit.
The fifth column is populated only if the item is switched relative to its parent (see “Bytte om en arbeidskopi”).
Item is a child of its parent directory.
Item is switched.
The sixth column is populated with lock information.
When --show-updates is used,
the file is not locked. If
--show-updates is
not used, this merely means that
the file is not locked in this working copy.
File is locked in this working copy.
File is locked either by another user or in
another working copy. This only appears when
--show-updates is used.
File was locked in this working copy, but the
lock has been “stolen”and is invalid.
The file is currently locked in the repository. This
only appears when --show-updates is
used.
File was locked in this working copy, but the
lock has been “broken”and is invalid.
The file is no longer locked This only appears when
--show-updates is used.
The out-of-date information appears in the seventh
column (only if you pass the
--show-updates switch).
The item in your working copy is up-to-date.
A newer revision of the item exists on the server.
The remaining fields are variable width and
delimited by spaces. The working revision is the next
field if the --show-updates or
--verbose switches are passed.
If the --verbose switch is passed,
the last committed revision and last committed author
are displayed next.
The working copy path is always the final field, so it can include spaces.
--show-updates (-u) --verbose (-v) --non-recursive (-N) --quiet (-q) --no-ignore --username USER --password PASS --no-auth-cache --non-interactive --config-dir DIR --ignore-externals
This is the easiest way to find out what changes you have made to your working copy:
$ svn status wc M wc/bar.c A + wc/qax.c
If you want to find out what files in your working
copy are out-of-date, pass the
--show-updates switch (this will
not make any changes to your
working copy). Here you can see that
wc/foo.c has changed in the
repository since we last updated our working
copy:
$ svn status --show-updates wc
M 965 wc/bar.c
* 965 wc/foo.c
A + 965 wc/qax.c
Status against revision: 981
![]() | Notat |
|---|---|
|
And finally, the most information you can get out of the status subcommand:
$ svn status --show-updates --verbose wc
M 965 938 sally wc/bar.c
* 965 922 harry wc/foo.c
A + 965 687 harry wc/qax.c
965 687 harry wc/zig.c
Head revision: 981
For many more examples of svn status, see “svn status”.
svn switch — Update working copy to a different URL.
This subcommand updates your working copy to mirror a new URL—usually a URL which shares a common ancestor with your working copy, although not necessarily. This is the Subversion way to move a working copy to a new branch. See “Bytte om en arbeidskopi” for an in-depth look at switching.
--revision (-r) REV --non-recursive (-N) --quiet (-q) --diff3-cmd CMD --relocate FROM TO --username USER --password PASS --no-auth-cache --non-interactive --config-dir DIR
If you're currently inside the directory
vendors which was branched to
vendors-with-fix and you'd like to
switch your working copy to that branch:
$ svn switch http://svn.red-bean.com/repos/branches/vendors-with-fix . U myproj/foo.txt U myproj/bar.txt U myproj/baz.c U myproj/qux.c Updated to revision 31.
And to switch back, just provide the URL to the location in the repository from which you originally checked out your working copy:
$ svn switch http://svn.red-bean.com/repos/trunk/vendors . U myproj/foo.txt U myproj/bar.txt U myproj/baz.c U myproj/qux.c Updated to revision 31.
![]() | Tips |
|---|---|
You can just switch part of your working copy to a branch if you don't want to switch your entire working copy. |
Sometimes an administrator might change the
“base location” of your repository—in
other words, the contents of the repository doesn't
change, but the main URL used to reach the root of the
repository does. For example, the hostname may change,
the URL scheme, or any part of the URL which leads to the
repository itself. Rather than checkout a new working
copy, you can have the svn switch
command “rewrite” the beginnings of all the
URLs in your working copy. Use the
--relocate option to do the substitution.
No file contents are changed, nor is the repository
contacted. It's similar to running a Perl script over
your working copy .svn/ directories
which runs s/OldRoot/NewRoot/.
$ svn checkout file:///tmp/repos test A test/a A test/b … $ mv repos newlocation $ cd test/ $ svn update svn: Unable to open an ra_local session to URL svn: Unable to open repository 'file:///tmp/repos' $ svn switch --relocate file:///tmp/repos file:///tmp/newlocation . $ svn update At revision 3.
![]() | Advarsel |
|---|---|
Be careful when using the
|
svn unlock — Unlock working copy paths or URLs.
Unlock each TARGET. If any
TARGET is either locked by
another user or no valid lock token exists in the working
copy, print a warning and continue unlocking the rest of
the TARGETs. Use
--force to break a lock belonging to
another user or working copy.
--targets FILENAME --username USER --password PASS --no-auth-cache --non-interactive --config-dir DIR --force
Unlock two files in your working copy:
$ svn unlock tree.jpg house.jpg 'tree.jpg' unlocked. 'house.jpg' unlocked.
Unlock a file in your working copy that is currently locked by another user:
$ svn unlock tree.jpg svn: 'tree.jpg' is not locked in this working copy $ svn unlock --force tree.jpg 'tree.jpg' unlocked.
Unlock a file without a working copy:
$ svn unlock http://svn.red-bean.com/repos/test/tree.jpg 'tree.jpg unlocked.
For further details, see “Locking”.
svn update — Update your working copy.
svn update brings changes from the
repository into your working copy. If no revision given,
it brings your working copy up-to-date with the
HEAD revision. Otherwise, it
synchronizes the working copy to the revision given by the
--revision switch. As part of the
synchronization, svn update also
removes any stale locks (see “svn cleanup”) found in the
working copy.
For each updated item a line will start with a character reporting the action taken. These characters have the following meaning:
Added
Deleted
Updated
Conflict
Merged
A character in the first column signifies an update to the actual file, while updates to the file's properties are shown in the second column.
--revision (-r) REV --non-recursive (-N) --quiet (-q) --diff3-cmd CMD --username USER --password PASS --no-auth-cache --non-interactive --config-dir DIR --ignore-externals
Pick up repository changes that have happened since your last update:
$ svn update A newdir/toggle.c A newdir/disclose.c A newdir/launch.c D newdir/README Updated to revision 32.
You can also update your working copy to an older revision (Subversion doesn't have the concept of “sticky” files like CVS does; see Tillegg B, Subversion for CVS-brukere):
$ svn update -r30 A newdir/README D newdir/toggle.c D newdir/disclose.c D newdir/launch.c U foo.c Updated to revision 30.
![]() | Tips |
|---|---|
If you want to examine an older revision of a single file, you may want to use svn cat. |
svnadmin is the administrative tool for monitoring and repairing your Subversion repository. For detailed information, see “svnadmin”.
Since svnadmin works via direct repository access (and thus can only be used on the machine that holds the repository), it refers to the repository with a path, not a URL.
--bdb-log-keep(Berkeley DB specific) Disable automatic log removal of database log files.
--bdb-txn-nosync(Berkeley DB specific) Disables fsync when committing database transactions.
--bypass-hooksBypass the repository hook system.
--clean-logsRemoves unused Berkeley DB logs.
--force-uuidBy default, when loading data into repository that
already contains revisions, svnadmin
will ignore the UUID from the dump
stream. This switch will cause the repository's
UUID to be set to the
UUID from the stream.
--ignore-uuidBy default, when loading an empty repository,
svnadmin will use the
UUID from the dump stream. This
switch will cause that UUID to be ignored.
--incrementalDump a revision only as a diff against the previous revision, instead of the usual fulltext.
--parent-dir
DIRWhen loading a dump file, root paths at
DIR instead of
/.
--revision (-r)
ARGSpecify a particular revision to operate on.
--quietDo not show normal progress—show only errors.
--use-post-commit-hookWhen loading a dump file, run the repository's post-commit hook after finalizing each newly loaded revision.
--use-pre-commit-hookWhen loading a dump file, run the repository's pre-commit hook before finalizing each newly loaded revision. If the hook fails, abort the commit and terminate the load process.
svnadmin create — Create a new, empty repository.
Create a new, empty repository at the path provided.
If the provided directory does not exist, it will be
created for you.[50] As of
Subversion 1.2, svnadmin creates new
repositories with the fsfs filesystem
backend by default.
Creating a new repository is just this easy:
$ svnadmin create /usr/local/svn/repos
In Subversion 1.0, a Berkeley DB repository is always
created. In Subversion 1.1, a Berkeley DB repository is
the default repository type, but an FSFS repository can be
created using the --fs-type
option:
$ svnadmin create /usr/local/svn/repos --fs-type fsfs
svnadmin deltify — Deltify changed paths in a revision range.
svnadmin deltify only exists in current versions of Subversion due to historical reasons. This command is deprecated and no longer needed.
It dates from a time when Subversion offered administrators greater control over compression strategies in the repository. This turned out to be a lot of complexity for very little gain, and this “feature” was deprecated.
svnadmin dump — Dump the contents of filesystem to stdout.
Dump the contents of filesystem to stdout in a
“dumpfile” portable format, sending feedback
to stderr. Dump revisions
LOWER rev through
UPPER rev. If no revisions are
given, dump all revision trees. If only
LOWER is given, dump that one
revision tree. See “Flytte et depot”
for a practical use.
By default, the Subversion dumpfile stream contains a single revision (the first revision in the requested revision range) in which every file and directory in the repository in that revision is presented as if that whole tree was added at once, followed by other revisions (the remainder of the revisions in the requested range) which contain only the files and directories which were modified in those revisions. For a modified file, the complete fulltext representation of its contents, as well as all of its properties, are presented in the dumpfile; for a directory, all of its properties are presented.
There are a pair of useful options which modify the
dumpfile generator's behavior. The first is the
--incremental option, which simply causes
that first revision in the dumpfile stream to contain only
the files and directories modified in that revision,
instead of being presented as the addition of a new tree,
and in exactly the same way that every other revision in
the dumpfile is presented. This is useful for generating
a dumpfile that is to be loaded into another repository
which already has the files and directories that exist in
the original repository.
The second useful option is --deltas.
This switch causes svnadmin dump to,
instead of emitting fulltext representations of file
contents and property lists, emit only deltas of those
items against their previous versions. This reduces (in
some cases, drastically) the size of the dumpfile that
svnadmin dump creates. There are, however,
disadvantages to using this option—deltified
dumpfiles are more CPU intensive to create, cannot be
operated on by svndumpfilter, and tend
not to compress as well as their non-deltified counterparts
when using third-party tools like gzip
and bzip2.
Dump your whole repository:
$ svnadmin dump /usr/local/svn/repos SVN-fs-dump-format-version: 1 Revision-number: 0 * Dumped revision 0. Prop-content-length: 56 Content-length: 56 …
Incrementally dump a single transaction from your repository:
$ svnadmin dump /usr/local/svn/repos -r 21 --incremental * Dumped revision 21. SVN-fs-dump-format-version: 1 Revision-number: 21 Prop-content-length: 101 Content-length: 101 …
svnadmin help — Help!
svnadmin hotcopy — Make a hot copy of a repository.
This subcommand makes a full “hot” backup
of your repository, including all hooks, configuration
files, and, of course, database files. If you pass the
--clean-logs switch,
svnadmin will perform a hotcopy of your
repository, and then remove unused Berkeley DB logs from
the original repository. You can run this command at any
time and make a safe copy of the repository, regardless of
whether other processes are using the repository.
svnadmin list-dblogs — Ask
Berkeley DB which log files exist for a given Subversion
repository (applies only to repositories using the
bdb backend).
Berkeley DB creates logs of all changes to the
repository, which allow it to recover in the face of
catastrophe. Unless you enable
DB_LOG_AUTOREMOVE, the log files
accumulate, although most are no longer used and can be
deleted to reclaim disk space. See “Bruken av diskplass” for more
information.
svnadmin list-unused-dblogs — Ask Berkeley DB which log files can be safely
deleted (applies only to repositories using the
bdb backend).
Berkeley DB creates logs of all changes to the
repository, which allow it to recover in the face of
catastrophe. Unless you enable
DB_LOG_AUTOREMOVE, the log files
accumulate, although most are no longer used and can be
deleted to reclaim disk space. See “Bruken av diskplass” for more
information.
svnadmin load — Read a “dumpfile”-formatted stream from stdin.
Read a “dumpfile”-formatted stream from stdin, committing new revisions into the repository's filesystem. Send progress feedback to stdout.
--quiet (-q) --ignore-uuid --force-uuid --use-pre-commit-hook --use-post-commit-hook --parent-dir
This shows the beginning of loading a repository from a backup file (made, of course, with svnadmin dump):
$ svnadmin load /usr/local/svn/restored < repos-backup
<<< Started new txn, based on original revision 1
* adding path : test ... done.
* adding path : test/a ... done.
…
Or if you want to load into a subdirectory:
$ svnadmin load --parent-dir new/subdir/for/project /usr/local/svn/restored < repos-backup
<<< Started new txn, based on original revision 1
* adding path : test ... done.
* adding path : test/a ... done.
…
svnadmin lslocks — Print descriptions of all locks.
This lists the one locked file in the repository at
/svn/repos
$ svnadmin lslocks /svn/repos Path: /tree.jpg UUID Token: opaquelocktoken:ab00ddf0-6afb-0310-9cd0-dda813329753 Owner: harry Created: 2005-07-08 17:27:36 -0500 (Fri, 08 Jul 2005) Expires: Comment (1 line): Rework the uppermost branches on the bald cypress in the foreground.
svnadmin lstxns — Print the names of all uncommitted transactions.
Print the names of all uncommitted transactions. See “Depotvedlikehold” for information on how uncommitted transactions are created and what you should do with them.
svnadmin recover — Bring a repository database back into a
consistent state (applies only to repositories using the
bdb backend). In addition, if
repos/conf/passwd does not exist, it
will create a default password file .
Run this command if you get an error indicating that your repository needs to be recovered.
Recover a hung repository:
$ svnadmin recover /usr/local/svn/repos/ Repository lock acquired. Please wait; recovering the repository may take some time... Recovery completed. The latest repos revision is 34.
Recovering the database requires an exclusive lock on the repository. (This is a “database lock”; see Three meanings of “lock”.) If another process is accessing the repository, then svnadmin recover will error:
$ svnadmin recover /usr/local/svn/repos svn: Failed to get exclusive repository access; perhaps another process such as httpd, svnserve or svn has it open? $
The --wait option, however, will
cause svnadmin recover to wait
indefinitely for other processes to disconnect:
$ svnadmin recover /usr/local/svn/repos --wait Waiting on repository lock; perhaps another process has it open? ### time goes by… Repository lock acquired. Please wait; recovering the repository may take some time... Recovery completed. The latest repos revision is 34.
svnadmin rmtxns — Delete transactions from a repository.
Delete outstanding transactions from a repository. This is covered in detail in “Depotvedlikehold”.
Remove named transactions:
$ svnadmin rmtxns /usr/local/svn/repos/ 1w 1x
Fortunately, the output of lstxns works great as the input for rmtxns:
$ svnadmin rmtxns /usr/local/svn/repos/ `svnadmin lstxns /usr/local/svn/repos/`
Which will remove all uncommitted transactions from your repository.
svnadmin setlog — Set the log-message on a revision.
Set the log-message on revision REVISION to the contents of FILE.
This is similar to using svn propset
--revprop to set the svn:log property
on a revision, except that you can also use the option
--bypass-hooks to avoid running any pre- or
post-commit hooks, which is useful if the modification of
revision properties has not been enabled in the pre-revprop-change
hook.
![]() | Advarsel |
|---|---|
Revision properties are not under version control, so this command will permanently overwrite the previous log message. |
svnlook is a command-line utility for examining different aspects of a Subversion repository. It does not make any changes to the repository—it's just used for “peeking”. svnlook is typically used by the repository hooks, but a repository administrator might find it useful for diagnostic purposes.
Since svnlook works via direct repository access (and thus can only be used on the machine that holds the repository), it refers to the repository with a path, not a URL.
If no revision or transaction is specified, svnlook defaults to the youngest (most recent) revision of the repository.
Switches in svnlook are global, just like in svn and svnadmin; however, most switches only apply to one subcommand since the functionality of svnlook is (intentionally) limited in scope.
--no-diff-deletedPrevents svnlook from printing differences for deleted files. The default behavior when a file is deleted in a transaction/revision is to print the same differences that you would see if you had left the file but removed all the content.
--revision
(-r)Specify a particular revision number that you wish to examine.
--revpropOperates on a revision property instead of a
Subversion property specific to a file or directory.
This switch requires that you also pass a revision
with the --revision
(-r) switch. See “Uversjonerte egenskaper” for more details on
unversioned properties.
--transaction
(-t)Specify a particular transaction ID that you wish to examine.
--show-idsShow the filesystem node revision IDs for each path in the filesystem tree.
svnlook cat — Print the contents of a file.
This shows the contents of a file in transaction
ax8, located at
/trunk/README:
$ svnlook cat -t ax8 /usr/local/svn/repos /trunk/README
Subversion, a version control system.
=====================================
$LastChangedDate: 2003-07-17 10:45:25 -0500 (Thu, 17 Jul 2003) $
Contents:
I. A FEW POINTERS
II. DOCUMENTATION
III. PARTICIPATING IN THE SUBVERSION COMMUNITY
…
svnlook changed — Print the paths that were changed.
Print the paths that were changed in a particular revision or transaction, as well as “svn update-style” status letters in the first two columns:
A 'Item added to repository.
D 'Item deleted from repository.
U 'File contents changed.
_U'Properties of item changed.
UU'File contents and properties changed.
Files and directories can be distinguished, as directory
paths are displayed with a trailing '/'
character.
This shows a list of all the changed files in revision 39 of a test repository:
$ svnlook changed -r 39 /usr/local/svn/repos A trunk/vendors/deli/ A trunk/vendors/deli/chips.txt A trunk/vendors/deli/sandwich.txt A trunk/vendors/deli/pickle.txt U trunk/vendors/baker/bagel.txt _U trunk/vendors/baker/croissant.txt UU trunk/vendors/baker/pretzel.txt D trunk/vendors/baker/baguette.txt
svnlook diff — Print differences of changed files and properties.
This shows a newly added (empty) file, a deleted file, and a copied file:
$ svnlook diff -r 40 /usr/local/svn/repos/ Copied: egg.txt (from rev 39, trunk/vendors/deli/pickle.txt) Added: trunk/vendors/deli/soda.txt ============================================================================== Modified: trunk/vendors/deli/sandwich.txt ============================================================================== --- trunk/vendors/deli/sandwich.txt (original) +++ trunk/vendors/deli/sandwich.txt 2003-02-22 17:45:04.000000000 -0600 @@ -0,0 +1 @@ +Don't forget the mayo! Modified: trunk/vendors/deli/logo.jpg ============================================================================== (Binary files differ) Deleted: trunk/vendors/deli/chips.txt ============================================================================== Deleted: trunk/vendors/deli/pickle.txt ==============================================================================
If a file has a non-textual
svn:mime-type property, then the
differences are not explicitly shown.
svnlook dirs-changed — Print the directories that were themselves changed.
svnlook help — Help!
svnlook history — Print information about the history of a path in the repository (or the root directory if no path is supplied).
Print information about the history of a path in the repository (or the root directory if no path is supplied).
This shows the history output for the path
/tags/1.0 as of revision 20 in our
sample repository.
$ svnlook history -r 20 /usr/local/svn/repos /tags/1.0 --show-ids
REVISION PATH <ID>
-------- ---------
19 /tags/1.0 <1.2.12>
17 /branches/1.0-rc2 <1.1.10>
16 /branches/1.0-rc2 <1.1.x>
14 /trunk <1.0.q>
13 /trunk <1.0.o>
11 /trunk <1.0.k>
9 /trunk <1.0.g>
8 /trunk <1.0.e>
7 /trunk <1.0.b>
6 /trunk <1.0.9>
5 /trunk <1.0.7>
4 /trunk <1.0.6>
2 /trunk <1.0.3>
1 /trunk <1.0.2>
svnlook lock — If a lock exists on a path in the repository, describe it.
Print all information available for the lock at
PATH_IN_REPOS. If
PATH_IN_REPOS is not locked,
print nothing.
This describes the lock on the file
tree.jpg.
$ svnlook lock /svn/repos tree.jpg UUID Token: opaquelocktoken:ab00ddf0-6afb-0310-9cd0-dda813329753 Owner: harry Created: 2005-07-08 17:27:36 -0500 (Fri, 08 Jul 2005) Expires: Comment (1 line): Rework the uppermost branches on the bald cypress in the foreground.
svnlook proplist — Print the names and values of versioned file and directory properties.
List the properties of a path in the repository. With
--verbose, show the property values too.
This shows the names of properties set on the file
/trunk/README in the
HEAD revision:
$ svnlook proplist /usr/local/svn/repos /trunk/README original-author svn:mime-type
This is the same command as in the previous example, but this time showing the property values as well:
$ svnlook --verbose proplist /usr/local/svn/repos /trunk/README original-author : fitz svn:mime-type : text/plain
svnlook tree — Print the tree.
svnserve allows access to Subversion
repositories using the svn network protocol.
You can run svnserve either as a standalone server process, or
you can have another process, such as inetd,
xinetd or sshd, launch it
for you.
Once the client has selected a repository by transmitting
its URL, svnserve reads a file named
conf/svnserve.conf in the repository
directory to determine repository-specific settings such as what
authentication database to use and what authorization policies
to apply. See “svnserve, en tilpasset server” for details of
the svnserve.conf file.
Unlike the previous commands we've described. svnserve has no subcommands—svnserve is controlled exclusively by switches.
--daemon (-d)Causes svnserve to run in daemon mode. svnserve backgrounds itself and accepts and serves TCP/IP connections on the svn port (3690, by default).
--listen-port=PORTCauses svnserve to listen on
PORT when run in daemon
mode.
--listen-host=HOSTCauses svnserve to listen on the
interface specified by HOST,
which may be either a hostname or an IP address.
--foregroundWhen used together with -d, this
switch causes svnserve to stay in the
foreground. This switch is mainly useful for
debugging.
--inetd (-i)Causes svnserve to use the stdin/stdout file descriptors, as is appropriate for a daemon running out of inetd.
--help (-h)Displays a usage summary and exits.
--versionDisplays version information, a list of repository back-end modules available, and exits.
--root=ROOT
(-r=ROOT)Sets the virtual root for repositories served by svnserve. The pathname in URLs provided by the client will be interpreted relative to this root, and will not be allowed to escape this root.
--tunnel (-t)Causes svnserve to run in tunnel mode, which is just like the inetd mode of operation (serve one connection over stdin/stdout) except that the connection is considered to be pre-authenticated with the username of the current uid. This flag is selected by the client when running over a tunnel agent such as ssh.
--tunnel-user NAMEUsed in conjunction with --tunnel
switch; tells svnserve to assume that
NAME is the authenticated
user, rather than the UID of the svnserve
process. Useful for users wishing to share a single
system account over SSH, but maintaining separate commit
identities.
--threads (-T)When running in daemon mode, causes svnserve to spawn a thread instead of a process for each connection. The svnserve process still backgrounds itself at startup time.
--listen-once (-X)Causes svnserve to accept one connection on the svn port, serve it, and exit. This option is mainly useful for debugging.
svnversion — Summarize the local revision(s) of a working copy.
svnversion is a program for summarizing the revision mixture of a working copy. The resultant revision number, or revision range, is written to standard output.
TRAIL_URL, if present, is the
trailing portion of the URL used to determine if
WC_PATH itself is switched
(detection of switches within
WC_PATH does not rely on
TRAIL_URL).
When WC_PATH is not defined the current directory will be used as the working copy path. TRAIL_URL cannot be defined if WC_PATH is not explicitly given.
Like svnserve, svnversion has no subcommands, it only has switches.
--no-newline (-n)Omit the usual trailing newline from the output.
--committed (-c)Use the last-changed revisions rather than the current (i.e., highest locally available) revisions.
--help (-h)Print a help summary.
--versionPrint the version of svnversion and exit with no error.
If the working copy is all at the same revision (for example, immediately after an update), then that revision is printed out:
$ svnversion 4168
You can add TRAIL_URL to show that the working copy is not switched from what you expect. Note that the WC_PATH was required in this command:
$ svnversion . /repos/svn/trunk 4168
For a mixed-revision working copy, the range of revisions present is printed:
$ svnversion 4123:4168
If the working copy contains modifications, a trailing "M" is added:
$ svnversion 4168M
If the working copy is switched, a trailing "S" is added:
$ svnversion 4168S
Thus, here is a mixed-revision, switched working copy containing some local modifications:
$ svnversion 4212:4168MS
If invoked on a directory that is not a working copy, svnversion assumes it is an exported working copy and prints "exported":
$ svnversion exported
mod_dav_svn Configuration
Directives — Apache configuration
directives for serving Subversion repositories through Apache
HTTP Server.
This section briefly describes each of the Subversion Apache configuration directives. For an in-depth description of configuring Apache with Subversion, see “HTTP-serveren Apache (httpd)”.)
DAV svnThis directive must be included in any
Directory or
Location block for a Subversion
repository. It tells httpd to use the Subversion
backend for mod_dav to handle all requests.
SVNAutoversioning OnThis directive allows write requests from WebDAV
clients to result in automatic commits. A generic log
message is auto-generated and attached to each
revision. If you enable Autoversioning, you'll likely
want to set ModMimeUsePathInfo On
so that mod_mime can set
svn:mime-type to the correct
mime-type automatically (as best as
mod_mime is able to, of course).
For more information, see Tillegg C, WebDAV and Autoversioning
SVNPathThis directive specifies the location in the
filesystem for a Subversion repository's files. In a
configuration block for a Subversion repository,
either this directive or
SVNParentPath must be present, but
not both.
SVNSpecialURISpecifies the URI component (namespace) for
special Subversion resources. The default is
“!svn”, and most
administrators will never use this directive. Only
set this if there is a pressing need to have a file
named !svn in your repository. If
you change this on a server already in use, it will
break all of the outstanding working copies and your
users will hunt you down with pitchforks and flaming
torches.
SVNReposNameSpecifies the name of a Subversion repository for
use in HTTP GET requests. This
value will be prepended to the title of all directory
listings (which are served when you navigate to a
Subversion repository with a web browser). This
directive is optional.
SVNIndexXSLTSpecifies the URI of an XSL transformation for directory indexes. This directive is optional.
SVNParentPathSpecifies the location in the filesystem of a
parent directory whose child directories are
Subversion repositories. In a configuration block for
a Subversion repository, either this directive or
SVNPath must be present, but not
both.
SVNPathAuthzControl path-based authorization by enabling or disabling subrequests. See “Slå av stibaserte kontroller” for details.
Subversion-defined properties — properties defined by Subversion to control behavior.
Subversion allows users to invent arbitrarily-named versioned properties on files and directories, as well as unversioned properties on revisions. The only restriction is on properties prefixed with “svn:”. Properties in that namespace are reserved for Subversion's own use. While these properties may be set by users to control Subversion's behavior, users may not invent new “svn:” properties.
svn:executableIf present on a file, the client will make the file executable in Unix-hosted working copies. See “File Executability”.
svn:mime-typeIf present on a file, the value indicates the file's mime-type. This allows the client to decide whether line-based contextual merging is safe to perform during updates, and can also affect how the file behaves when fetched via web browser. See “File Content Type”.
svn:ignoreIf present on a directory, the value is a list of unversioned file patterns to be ignored by svn status and other subcommands. See “Ignoring Unversioned Items”
svn:keywordsIf present on a file, the value tells the client how to expand particular keywords within the file. See “Keyword Substitution”.
svn:eol-styleIf present on a file, the value tells the client how to manipulate the file's line-endings in the working copy. See “End-of-Line Character Sequences”.
svn:externalsIf present on a directory, the value is a multi-line list of other paths and URLs the client should check out. See “Externals Definitions”.
svn:specialIf present on a file, indicates that the file is not an ordinary file, but a symbolic link or other special object.
svn:needs-lockIf present on a file, tells the client to make the file read-only in the working copy, as a reminder that the file should be locked before editing begins. See “Lock Communication”.
svn:authorIf present, contains the authenticated username of the person who created the revision. (If not present, then the revision was committed anonymously.)
svn:dateContains the UTC time the revision was created, in ISO format. The value comes from the server machine's clock.
svn:logContains the log message describing the revision.
svn:autoversionedIf present, the revision was created via the autoversioning feature. See “Autoversioning”.
Innholdsfortegnelse
Noen personer har problemer med å absorbere en ny teknologi ved å lese dokumentasjon lagt ut etter et “ovenfra og ned”-prinsipp som i denne boka. Dette tillegget er en veldig kort introduksjon til Subversion, og er ment å gi personer som lærer “nedenfra og opp” en sjanse. Hvis du foretrekker å lære gjennom eksperimentering, vil den følgende demonstrasjonen få deg i gang. Under gjennomgangen vil vi gi deg lenker til de relevante kapitlene i denne boka.
Hvis du er ny innen hele konseptet med versjonskontroll eller til “kopier-rediger-flett”-modellen brukt av både CVS og Subversion, bør du lese Kapittel 1, Grunnleggende konsepter før du går videre.
Subversion er bygget på et portabilitetslag kalt APR – Apache Portable Runtime. APR-biblioteket inneholder alle grensesnitt som Subversion trenger for å fungere på forskjellige operativsystemer: Diskaksess, nettverkstilgang, styring av hukommelsen og så videre. Selv om Subversion er i stand til å bruke Apache som nettverksserver, fører ikke Subversions APR-avhengighet til at Apache er en nødvendig komponent. APR er et selvstendig bibliotek som kan brukes av mange programmer. Det det derimot betyr, er at Subversion skal kunne kjøre på alle operativsystemer som Apache httpd-serveren kjører på: Windows, Linux, alle varianter av BSD, Mac OS X, Netware og andre.
Den letteste måten å få tak i Subversion er å hente en binær pakke bygget for ditt operativsystem. Subversions hjemmeside (http://subversion.tigris.org) har ofte disse pakkene tilgjengelig for nedlasting, lagt ut av frivillige. Denne plassen inneholder vanligvis grafiske installasjonspakker for brukere av operativsystemer fra Microsoft. Hvis du kjører et Unix-lignende operativsystem, kan du bruke systemets innebygde distribusjonssystem (RPM-filer, DEB-filer, “ports”-treet, osv.) for å hente Subversion.
Du kan også bygge Subversion direkte fra kildekode.
Siste versjon av programmet kan hentes fra Subversions hjemmeside.
Etter at du har pakket det ut, følg instruksjonene i fila
INSTALL for å kompilere den.
Merk at en offentliggjort kildekodepakke inneholder alt du trenger
for å bygge en kommandolinjeklient i stand til å kommunisere med
et fjerntliggende depot (mer spesifikt, bibliotekene apr, apr-util
og neon).
Men valgfrie deler av Subversion har mange andre avhengigheter,
som Berkeley DB og muligens Apache httpd.
Hvis du vil foreta en komplett kompilering, vær sikker på at du
har alle pakkene dokumentert i
INSTALL-fila.
Hvis du er av den typen som liker å bruke rykende fersk programvare, kan du også hente kildekoden for Subversion fra Subversion-depotet hvor den er lagret. For å gjøre dette, trenger du en Subversion-klient. Med den kan du hente ut en arbeidskopi av Subversion-depotet fra http://svn.collab.net/repos/svn/trunk/:[51]
$ svn checkout http://svn.collab.net/repos/svn/trunk subversion A subversion/HACKING A subversion/INSTALL A subversion/README A subversion/autogen.sh A subversion/build.conf …
Kommandoen ovenfor vil hente ut den rykende ferske og nyeste
versjonen av kildekoden for Subversion inn i en underkatalog kalt
subversion.
Du kan selvfølgelig forandre det siste parameteret til det du syns
passer.
Men, uansett hva du kaller den nye arbeidskopien, etter at denne
operasjonen er fullført, vil du ha kildekoden til Subversion.
Du vil også trenge å hente en del programbiblioteker (apr,
apr-util og så videre) – se INSTALL-fila i
toppkatalogen i arbeidskopien for detaljene.
“Vennligst rett opp seteryggen, fest setebeltet og rett opp bordene. Flight attendants, prepare for take-off …”
Det som kommer nå er en høytflygende innføring som vil ta deg gjennom litt grunnleggende konfigurasjon og bruk av Subversion. Når du har fullført innføringen, vil du ha en grunnleggende forståelse av Subversions typiske bruksmåter.
![]() | Notat |
|---|---|
Eksemplene som brukes i dette tillegget forutsetter at du har svn, kommandolinjeklienten, og svnadmin, det administrative verktøyet, klar til kjøring. Det forutsetter også at du bruker Subversion 1.2 eller senere (kjør svn --version for å sjekke). |
Subversion lagrer alle versjonerte data i et sentralt depot. For å begynne, lag et nytt depot:
$ svnadmin create /sti/til/depot $ ls /sti/til/depot conf/ dav/ db/ format hooks/ locks/ README.txt
Denne kommandoen lager en ny katalog
/sti/til/depot som inneholder et
Subversiondepot.
Denne nye katalogen inneholder (sammen med andre ting) en samling
databasefiler.
Du vil ikke se dine versjonerte filer hvis du tar en kikk
innenfor.
For mer informasjon om opprettelse og vedlikehold av depot, se
Kapittel 5, Depotadministrasjon.
Subversion har ikke noen oppfatning av et “prosjekt”. Depotet er kun et virtuelt versjonert filsystem, et stort tre som kan inneholde hva du vil. Noen administratorer foretrekker å lagre bare ett prosjekt i et depot, andre foretrekker å lagre flere prosjekter i et depot ved å plassere dem i egne kataloger. Fordeler og ulemper med hvert system diskuteres i “Velge en depot-layout”. Uansett, depotet holder bare rede på filer og kataloger, så det er opp til mennesker å se på spesielle kataloger som “prosjekter”. Så selv om du ser referanser til prosjekter i denne boka, husk på at vi bare snakker om en katalog (eller samling av kataloger) i depotet.
I dette eksempelet går vi ut i fra at du allerede har en form
for prosjekt (en samling av filer og kataloger) som du vil
importere inn i det nyopprettede Subversiondepotet ditt.
Start med å organisere dem i en enkel katalog kalt
mittprosjekt eller noe annet, hvis du vil.
På grunn av ting som bli avklart senere (se Kapittel 4, Forgrening og fletting), bør katalogstrukturen til prosjektet
inneholde tre kataloger på toppnivå som kalles
branches, tags og
trunk.
trunk-katalogen inneholder alle dine data,
mens katalogene branches og
tags er tomme:
/tmp/mittprosjekt/branches/
/tmp/mittprosjekt/tags/
/tmp/mittprosjekt/trunk/
foo.c
bar.c
Makefile
…
Katalogene branches,
tags og trunk er
egentlig ikke nødvendig for at Subversion skal fungere.
Det er bare en utbredt konvensjonell måte å gjøre ting på som du
også sannsynligvis vil komme til å bruke.
Når du har klargjort treet med data, importer det inn i depotet med kommandoen svn import (se “svn import”):
$ svn import /tmp/mittprosjekt file:///sti/til/depot/mittprosjekt -m "Innledende import" Legger til /tmp/mittprosjekt/branches Legger til /tmp/mittprosjekt/tags Legger til /tmp/mittprosjekt/trunk Legger til /tmp/mittprosjekt/trunk/foo.c Legger til /tmp/mittprosjekt/trunk/bar.c Legger til /tmp/mittprosjekt/trunk/Makefile … La inn revisjon 1. $
Nå inneholder depotet dette treet med data.
Som nevnt tidligere, vil du ikke se filene dine ved å se direkte
inn i depotet; de er lagret i en database.
Men depotets virtuelle filsystem inneholder nå en toppkatalog kalt
mittprosjekt, som igjen inneholder dine
data.
Legg merke til at den originale
/tmp/mittprosjekt-katalogen er uforandret,
Subversion kjenner ikke til den.
(Faktisk kan du til og med slette denne katalogen hvis du ønsker
det.)
For å starte med å manipulere dataene i depotet, må du lage en ny
“arbeidskopi” av dataene, et slags personlig
arbeidsområde.
Be Subversion om å “hente ut” en arbeidskopi fra
katalogen mittprosjekt/trunk i
depotet:
$ svn checkout file:///sti/til/depot/mittprosjekt/trunk mittprosjekt A mittprosjekt/foo.c A mittprosjekt/bar.c A mittprosjekt/Makefile … Sjekket ut revisjon 1.
Nå har du en personlig kopi av en del av depotet i en ny
katalog kalt mittprosjekt.
Du kan redigere filene i arbeidskopien og deretter legge disse
forandringene inn i depotet.
Gå inn i arbeidskopien og rediger innholdet av en fil.
Kjør kommandoen svn diff for å se en unified diff (forskjellsfil) over forandringene dine.
Kjør svn commit for å legge inn den nye versjonen av fila di til depotet.
Kjør svn update for å oppdatere arbeidskopien din i forhold til depotet.
For en full gjennomgang av tingene som du kan gjøre med arbeidskopien din, les Kapittel 2, Grunnleggende bruk.
Ved dette punktet har du valget å gjøre depotet ditt tilgjengelig over et nettverk. Se Kapittel 6, Serverkonfigurasjon for å lære om de forskjellige serverprosessene tilgjengelig og hvordan du setter dem opp.
### TODO: Let's make this into a full tutorial, rather than simply referring off to other sections. ###
[51] Legg merke til at URLen som hentes ut i eksempelet ovenfor
ikke ender med svn, men med en underkatalog
fra den kalt trunk.
Se diskusjonen vår om Subversions forgrenings- og merkemodell
for begrunnelsen for dette.
Innholdsfortegnelse
Dette tillegget er en guide for CVS-brukere som nettopp har begynt å bruke Subversion. Det er hovedsaklig en liste over forskjeller mellom de to systemene som om den er “sett fra en høyde av 3.000 meter”. For hver seksjon refererer vi tilbake til relevante kapitler når det er mulig.
Selv om målet til Subversion er å overta dagens og fremtidens brukermasse, var det nødvendig med nye funksjoner og forandringer i oppbygningen for å ordne enkelte “ødelagte” virkemåter i CVS. Dette betyr at du som CVS-bruker kanskje må bryte vaner – av den typen du har glemt var merkelige til å begynne med.
I CVS er revisjonsnumrene konstruert for hver enkelt fil. Dette er fordi CVS lagrer dataene sine i RCS-filer; hver fil har en tilsvarende RCS-fil i depotet, og depotet er lagt ut på bortimot samme måte som prosjekttreet ditt.
I Subversion ser depotet ut som et enkeltstående filsystem. Hver innlegging resulterer i et helt nytt filsystemtre; depotet er i grunnen en rekke av trær. Hvert av disse trærne er merket med hvert sitt revisjonsnummer. Når noen snakker om “revisjon 54”, snakker de om et spesifikt tre (og indirekte, sånn som filsystemet så ut etter den 54. innleggingen).
Teknisk sett gir det ingen ingen mening å snakke om
“revisjon 5 av foo.c”.
Istedenfor vil man si “foo.c som den
fremstår i revisjon 5”.
Vær også forsiktig når du gjør deg antakelser om utviklingen av en
fil.
I CVS er revisjon 5 og 6 av foo.c alltid
forskjellig.
I Subversion er det mest sannsynlig at foo.c
ikke forandret seg mellom revisjon 5 og
6.
For flere detaljer om dette emnet, se “Revisjoner”.
I tillegg til å arkivere innholdet av filene, holder Subversion også orden på trestrukturer. Dette er en av hovedgrunnene til at Subversion ble skrevet for å erstatte CVS.
Her er hva dette har å si for deg, som en tidligere CVS-bruker:
Kommandoene svn add og svn delete virker nå også på kataloger, akkurat som de gjør på filer. Det samme gjelder svn copy og svn move. Disse kommandoene forårsaker imidlertid ingen øyeblikkelige forandringer i depotet. Istedenfor blir de elementene det gjelder “lagt i kø” for tillegging eller sletting. Det vil ikke bli gjort noen forandringer i depotet før du kjører svn commit.
Kataloger er ikke “dumme” lagringsplasser for
filer mer, de har revisjonsnumre i likhet med filer.
(Eller riktigere beskrevet, det er korrekt å snakke om
“katalogen foo/ i revisjon
5”.
La oss snakke mer om det siste punktet. Versjonskontroll av kataloger er et vanskelig problem. Fordi vi ønsker å tillate kopier som inneholder blandede revisjoner, er det lagt inn begrensninger i hvor langt vi kan gå når det gjelder å misbruke denne modellen.
Fra et teoretisk synspunkt definerer vi “revisjon 5 av
katalogen foo” til å bety en spesifikk
samling av katalogposter og egenskaper.
Tenk deg så at vi begynner å legge til og fjerne filer fra
foo, og deretter legger det inn.
Det ville være løgn å si at vi fortsatt har revisjon 5 av
foo.
Imidlertid, hvis vi øker revisjonsnummeret for
foo etter innleggingen, ville det også være
en løgn;
det kan være andre forandringer i foo som vi
foreløpig ikke har mottatt, fordi vi ikke har oppdatert
enda.
Subversion tar seg av dette problemet ved å i all stillhet
undersøke innlagte tillegginger og slettinger i
.svn, det sjekkes at alt er i orden i henhold
til depotet, og det nye revisjonsnummeret blir korrekt satt for
katalogen.
Derfor, det er kun etter en oppdatering det er helt
sikkert å si at du har en “perfekt” revisjon av en
katalog.
Mesteparten av tiden vil arbeidskopien din inneholde
“uperfekte” katalogrevisjoner.
På samme måte vil et problem oppstå hvis du forsøker å legge inn forandringer i egenskapene for en katalog. Normalt ville innleggingen øke det lokale revisjonsnummeret for arbeidskatalogen. Men også her ville det være en løgn, fordi det kan være tillegg og slettinger som katalogen fortsatt ikke har, fordi ingen oppdatering er gjort. Derfor får du ikke lov til å legge inn egenskapsforandringer på en katalog hvis den ikke er oppdatert.
For videre diskusjon om begrensningene på versjonskontroll for kataloger, se “Arbeidskopier med blandede revisjonsnumre”.
I de senere år har diskplass blitt hårreisende billig og tilgjengelig, i motsetning til båndbredde. Derfor er arbeidskopiene til Subversion blitt optimalisert for den mer dyrebare ressursen.
Den administrative katalogen .svn tjener
samme formål som CVS-katalogen, unntatt at
den også lagrer skrivebeskyttede, “rene” kopier av
filene dine.
Dette gjør at du kan gjøre mange ting uten nettforbindelse:
Viser deg alle lokale forandringer du har gjort (se “svn status”)
Viser deg forandringene dine i detalj (se “svn diff”)
Tilbakestiller dine lokale forandringer (se “svn revert”)
I tillegg tillater de originale filene Subversionklienten å sende oppdateringen som en differansefil, noe CVS ikke kan gjøre.
Den siste delkommandoen i listen er ny; den vil ikke bare fjerne lokale forandringer, men den vil også fjerne operasjoner som tillegg og slettinger fra køen. Dette er den foretrukne måten å tilbakestille ei fil. Kommandoene rm file; svn update vil fortsatt virke, men det utydeliggjør meningen med oppdatering. Og med det samme vi er inne på temaet:
I Subversion har vi prøvd å fjerne en del av forvirringen angående kommandoene cvs status og cvs update.
Kommandoen cvs status har to formål:
For det første å vise brukeren alle lokale forandringer i
arbeidskopien, og for det andre å vise brukeren hvilke filer som
er utdatert.
Uheldigvis, på grunn av CVSs uoversiktlige utlisting, er det mange
CVS-brukere som ikke bruker denne kommandoen i det hele tatt.
Istedenfor har de lagt seg til vanen å kjøre cvs
update eller cvs update -n for å få
en rask oversikt over forandringene.
Hvis brukere glemmer å bruke -n-valget, vil dette
føre til at det flettes inn forandringer fra depotet som de
kanskje ikke er klare til å håndtere.
Med Subversion har vi forsøkt å fjerne dette rotet ved å gjøre informasjonen fra svn status lettlest både for menneske og maskin. I tillegg begrenser informasjonen fra svn update seg til kun å inneholde filer som blir oppdatert, ikke lokale endringer.
svn status lister alle filer som inneholder lokale forandringer. Standard oppførsel er å ikke kontakte depotet og nettverkskontakt er derfor ikke nødvendig. Denne delkommandoen godtar en god del valg, dette er de mest vanlige:
-uKontakt depotet for å finne ut, og deretter vise informasjon om utdaterte elementer.
-vVis alle elementer som er under versjonskontroll.
-NKjør kommandoen ikke-rekursivt (ikke gå inn i underkataloger).
status-kommandoen har to visningsformater. Med det vanlige “korte” formatet ser lokale forandringer ut som dette:
$ svn status M foo.c M bar/baz.c
Hvis du spesifisererer valget
--show-updates (-u), brukes et
lengre format:
$ svn status -u
M 1047 foo.c
* 1045 faces.html
* bloo.png
M 1050 bar/baz.c
Status against revision: 1066
I dette tilfellet kommer to nye kolonner til syne.
Den andre kolonnen inneholder en asterisk hvis fila eller
katalogen er utdatert.
Den tredje kolonnen viser arbeidskopiens revisjonsnummer for
elementet.
I eksempelet ovenfor indikerer asterisken at
faces.html vil bli patchet hvis vi
oppdaterer, og at bloo.png er ei fil som
nylig er lagt til i depotet.
(Når revisjonsnummeret ved siden av
bloo.png mangler, betyr det at at fila ikke
eksisterer enda i arbeidskopien.)
Til sist, her er en rask oversikt over de vanligste statuskodene som du vil se:
A Ressursen er klargjort for tillegging (“Addition”) D Ressursen er klargjort for sletting (“Deletion”) M Ressursen inneholder lokale forandringer (“Modifications”) C Ressursen inneholder konflikter (forandringer er enda ikke blitt flettet sammen med depotet og arbeidskopien) (“Conflicts”) X Ressursen er ekstern i denne arbeidskopien (kan komme fra et annet depot (“eXternal”). Se “Externals Definitions” ? Ressursen er ikke under versjonskontroll ! Ressursen mangler eller er ikke komplett (fjernet av et annet verktøy enn Subversion)
For en mer detaljert diskusjon om svn status, se “svn status”.
svn update oppdaterer arbeidskopien din og skriver kun informasjon om filer som blir oppdatert.
Subversion har kombinert CVSs P- og
U-kode inn i den ene
U-koden.
Når en fletting eller konflikt oppstår, skriver Subversion rett
og slett bare G eller C,
istedenfor en hel setning om det.
For en mer detaljert diskusjon om svn update, se “Oppdater arbeidskopien din”.
Subversion skiller ikke mellom områder i filsystemet og områder for “forgreninger”, forgreninger og merker er vanlige kataloger i filsystemet. Dette er muligens det største enkeltstående mentale hinderet en CVS-bruker må forsere. Les alt om det i Kapittel 4, Forgrening og fletting.
![]() | Advarsel |
|---|---|
Siden Subversion behandler forgreninger og merker som
ordinære kataloger, husk alltid på å hente ut katalogen kalt
|
En ny funksjon i Subversion lar deg legge til vilkårlige metadata (eller “egenskaper”) til filer og kataloger. Egenskaper er vilkårlige navn/verdi-par koblet til filer og kataloger i arbeidskopien din.
For å sette eller lese et egenskapsnavn, bruk delkommandoene svn propset og svn propget. For å liste ut alle egenskaper ved et objekt, bruk svn proplist.
For mer informasjon, se “Egenskaper”.
CVS markerer konflikter med innlagte
“konfliktmerker”, og skriver en C
under oppdatering.
Historisk sett har dette laget problemer, fordi CVS ikke gjør nok.
Mange brukere glemmer (eller ser ikke) C-en
etter den fyker forbi på terminalen deres.
Ofte glemmer de at konfliktmerkene er der i det hele tatt, og de
legger deretter inn filer som inneholder konfliktmerker.
Subversion løser dette problemet ved å gjøre konflikter mer synlige. Den husker at ei fil har en konflikt, og vil ikke tillate deg å legge inn forandringene dine før du kjører svn resolved. Se “Løse konflikter (Flette inn andres forandringer)” for flere detaljer.
Generelt sett behandler Subversion binære filer mer elegant enn CVS. Fordi CVS bruker RCS, kan den bare lagre hele kopier av binære filer som forandres. Subversion, derimot, behandler forskjeller mellom filer ved hjelp av en binærdata-basert algoritme, uansett om de inneholder tekst eller binære data. Dette betyr at alle filer er lagret differensielt (pakket) i depotet.
CVS-brukere må merke binære filer med flagget
-kb, for å forhindre data å bli rotet til (på
grunn av nøkkelordutvidelser og oversettelse av linjeslutt).
Dette glemmer de noen ganger.
Subversion tar den mer paranoide ruten – til å begynne med utfører den ingen form for nøkkelordutvidelser hvis du ikke ber den spesielt om å gjøre det (Se “Keyword Substitution” og “End-of-Line Character Sequences” for flere detaljer). Standard oppførsel for Subversion er å behandle alle fildata som rene strenger av bytes, og filer blir alltid lagret i depotet i en uoversatt tilstand.
For det andre har Subversion et internt begrep om ei fil er “tekst” eller “binære” data, men dette begrepet er bare bevart i arbeidskopien. Under en svn update vil Subversion utføre kontekstbaserte flettinger på tekstfiler som inneholder lokale endringer, men vil ikke forsøke dette for binære filer.
For å avgjøre hvorvidt en kontekstbasert fletting er mulig,
leser Subversion svn:mime-type-egenskapen.
Hvis fila ikke har noen svn:mime-type-egenskap,
eller den har en mime-type som indikerer tekst (for eksempel
text/*), går Subversion ut i fra at det er
tekst.
Ellers går Subversion ut i fra at fila er binær.
Subversion hjelper også brukere ved å kjøre en algoritme som
sjekker om ei fil er binær for kommandoene svn
import og svn add.
Disse kommandoene gjetter godt og setter (muligens) en binær
svn:mime-type-egenskap på fila som blir lagt
til.
(Hvis Subversion gjetter feil, kan brukeren alltids fjerne eller
redigere egenskapen for hånd.)
I motsetning til CVS er en arbeidskopi i Subversion klar over at den har hentet ut en modul. Dette betyr at hvis noen forandrer definisjonen av en modul (det vil si legger til eller fjerner komponenter), vil et kall til svn update oppdatere arbeidskopien på en skikkelig måte.
Subversion definerer moduler som en liste av kataloger innenfor en katalogegenskap: Se “Externals Definitions”.
Med CVSs pserver er du nødt til å “logge inn” på serveren før du kan utføre lese- eller skriveoperasjoner – du må til og med logge inn for anonyme operasjoner. Med et Subversiondepot som bruker Apache httpd eller svnserve på serveren, oppgir du ingen autentiseringsopplysninger, serveren vil spørre deg etter opplysningene (enten disse er brukernavn og passord, et klientsertifikat, eller til og med begge). Så hvis depotet er lesbart for hele verden, trenger du ikke å autentisere i det hele tatt for leseoperasjoner.
I likhet med CVS vil Subversion lagre dine
autentiseringsopplysninger på disken (i katalogen
~/.subversion/auth/) unntatt hvis du ber
programmet om å ikke gjøre det.
Til dette bruker du valget
--no-auth-cache.
Unntaket fra denne oppførselen, derimot, er tilfellet med å
aksessere en svnserve-server gjennom en
SSH-tunnel ved å bruke URL-skjemaet svn+ssh://.
I det tilfellet forlanger ssh autentisering
bare for å starte tunnelen.
Kanskje den viktigste måten å gjøre CVS-brukere kjent med Subversion er å la dem fortsette arbeidet på prosjektene deres ved bruk av det nye systemet. Mens dette kan bli gjennomført til en viss grad ved å bruke et Subversiondepot som inneholder en flat import av et eksportert CVS-depot, vil den mer gjennomførte løsningen ikke bare inneholde den siste versjonen av dataene, men også hele historien, fra et system til et annet. Dette er et ekstremt vanskelig problem å løse som involverer å fastslå et sett med forandringer uten at atomiske egenskaper er tilgjengelige, og å oversette mellom systemenes forskjellige forgreningsmåter, i tillegg til andre komplikasjoner. Til tross for dette er det en håndfull verktøy som påstår i hvertfall delvis å kunne konvertere eksisterende CVS-depoter til Subversion.
Et slikt verktøy er cvs2svn (http://cvs2svn.tigris.org/), et Pythonskript originalt laget av medlemmer fra Subversions utviklermiljø. Et annet er Lev Serebryakovs RefineCVS (http://lev.serebryakov.spb.ru/refinecvs/). Disse verktøyene er komplette i varierende grad, og kan komme til å gjøre helt forskjellige vurderinger om hvordan historien til CVS-depotet skal behandles. Uansett hvilket verktøy du bestemmer deg for å bruke, vær nøye med å utføre så mye verifisering som du kan på konverteringsresultatet – når alt kommer til alt har du jobbet hardt for å lage denne historien!
For en oppdatert samling av lenker til kjente konverteringsverktøy, besøk lenkesiden på hjemmesiden til Subversion (http://subversion.tigris.org/project_links.html).
WebDAV is an extension to HTTP, and is growing more and more popular as a standard for file-sharing. Today's operating systems are becoming extremely Web-aware, and many now have built-in support for mounting “shares” exported by WebDAV servers.
If you use Apache/mod_dav_svn as your Subversion network server, then to some extent, you are also running a WebDAV server. This appendix gives some background on the nature of this protocol, how Subversion uses it, and how well Subversion interoperates with other software that is WebDAV-aware.
This section provides a very brief, very general overview to the ideas behind WebDAV. It should lay the foundation for understanding WebDAV compatibility issues between clients and servers.
RFC 2518 defines a set of concepts and accompanying extension methods to HTTP 1.1 that make the web into a more universal read/write medium. The basic idea is that a WebDAV-compliant web server can act like a generic file server; clients can mount shared folders that behave much like NFS or SMB filesystems.
The tragedy, though, is that the RFC 2518 WebDAV specification does not provide any sort of model for version control, despite the “V” in DAV. Basic WebDAV clients and servers assume only one version of each file or directory exists, and can be repeatedly overwritten.
Here are the concepts and terms introduced in basic WebDAV:
WebDAV lingo refers to any server-side object (that can be described with a URI) as a resource.
Beyond the standard HTTP PUT
method (which creates or overwrites a web resource),
WebDAV defines new COPY and
MOVE methods for duplicating or
rearranging resources.
A collection is the WebDAV
term for a grouping of resources. In most cases, it
is analogous to a directory. Whereas file resources
can be written or created with a
PUT method, collection resources
are created with the new MKCOL
method.
This is the same idea present in
Subversion—metadata attached to files and
collections. A client can list or retrieve properties
attached to a resource with the new
PROPFIND method, and can change
them with the PROPPATCH method.
Some properties are wholly created and controlled by
users (e.g. a property called “color”),
and others are wholly created and controlled by the
WebDAV server (e.g. a property that contains the last
modification time of a file). The former kind are
called dead properties, and the
latter kind are called live
properties.
A WebDAV server may decide to offer a locking
feature to clients—this part of the
specification is optional, although most WebDAV
servers do offer the feature. If present, then
clients can use the new LOCK and
UNLOCK methods to mediate access to
a resource. In most cases these methods are used to
create exclusive write locks (as discussed in ““Lås-rediger-lås opp”-løsningen”), although shared write
locks are also possible in some server
implementations.
A more recent specification (RFC 3744) defines a system for defining access control lists (ACLs) on WebDAV resources. Some clients and servers have begun to implement this feature.
Because RFC 2518 left out versioning concepts, another committee was left with the responsibility of writing RFC 3253, which adds versioning to WebDAV, a.k.a. “DeltaV”. WebDAV/DeltaV clients and servers are often called just “DeltaV” programs, since DeltaV implies the existence of basic WebDAV.
DeltaV introduces a whole slew of new acronyms, but don't be intimidated. The ideas are fairly straightforward:
Like CVS and other version-control systems,
DeltaV assumes that each resource has a potentially
infinite number of states. A client begins by placing
a resource under version control using the new
VERSION-CONTROL method.
Some DeltaV servers support the ability to create
a virtual workspace on the server, where all of your
work is performed. Clients use the
MKWORKSPACE method to create a
private area, then indicate they want to change
specific resources by “checking them out”
into the workspace, editing them, and “checking
them in” again. In HTTP terms, the sequence of
methods would be CHECKOUT,
PUT,
CHECKIN.
Some DeltaV servers also support the idea that the
client may have a private working copy on local disk.
When the client wants to commit changes to the server,
it begins by creating a temporary server transaction
(called an activity) with the
MKACTIVITY method. The client then
performs a CHECKOUT on each
resource it wishes to change and sends
PUT requests. Finally, the client
performs a CHECKIN resource, or
sends a MERGE request to check in
all resources at once.
DeltaV allows you define flexible collections of resources called “configurations”, which don't necessarily correspond to particular directories. A configuration can be made to point to specific versions of files, and then a “baseline” snapshot can be made, much like a tag.
DeltaV defines a new method,
REPORT, which allows the client and
server to perform customized data exchanges. While
DeltaV defines a number of standardized history reports
that a client can request, the server is also free
to define custom reports. The client sends a
REPORT request with a
properly-labeled XML body full of custom data; assuming
the server understands the specific report-type, it
responds with an equally custom XML body. This
technique is very similar to XML-RPC.
The original WebDAV standard has been widely successful. Every modern computer operating system has a general WebDAV client built-in (details to follow), and a number of popular standalone applications are also able to speak WebDAV — Microsoft Office, Dreamweaver, and Photoshop to name a few. On the server end, the Apache webserver has been able to provide WebDAV services since 1998 and is considered the de-facto open-source standard. There are several other commercial WebDAV servers available, including Microsoft's own IIS.
DeltaV, unfortunately, has not been so successful. It's very difficult to find any DeltaV clients or servers. The few that do exist are relatively unknown commercial products, and thus it's very difficult to test interoperability. It's not entirely clear as to why DeltaV has remained stagnant. Some argue that the specification is just too complex, others argue that while WebDAV's features have mass appeal (even the least technical users appreciate network file-sharing), version control features aren't interesting or necessary for most users. Finally, some have argued that DeltaV remains unpopular because there's still no open-source server product which implements it.
When Subversion was still in its design phase, it seemed like a great idea to use Apache httpd as the main network server. It already had a module to provide WebDAV services. DeltaV was a relatively new specification. The hope was that the Subversion server module (mod_dav_svn) would eventually evolve into an open-source DeltaV reference implementation. Unfortunately, DeltaV has a very specific versioning model that doesn't quite line up with Subversion's model. Some concepts were mappable, others were not.
The upshot is that
The Subversion client is not a fully-implemented DeltaV client.
The client needs certain things from the server that
DeltaV cannot provide, and thus is largely dependent on a
number of Subversion-specific REPORT
requests that only mod_dav_svn understands.
mod_dav_svn is not a fully-implemented DeltaV server.
Many portions of the DeltaV specification were irrelevant to Subversion, and thus left unimplemented.
There is still some debate in the developer community as to whether or not it's worthwhile to remedy either of these situations. It's fairly unrealistic to change Subversion's design to match DeltaV, so there's probably no way the client can ever learn to get everything it needs from a general DeltaV server. On the other hand, mod_dav_svn could be further developed to implement all of DeltaV, but it's hard to find motivation to do so—there are almost no DeltaV clients to interoperate with.
While the Subversion client is not a full DeltaV client, nor the Subversion server a full DeltaV server, there's still a glimmer of WebDAV interoperability to be happy about: it's called autoversioning.
Autoversioning is an optional feature defined in the DeltaV
standard. A typical DeltaV server will reject an ignorant
WebDAV client attempting to do a PUT to a
file that's under version control. To change a
version-controlled file, the server expects a series proper
versioning requests: something like
MKACTIVITY, CHECKOUT,
PUT, CHECKIN. But if the
DeltaV server supports autoversioning, then write-requests from
basic WebDAV clients are accepted. The server behaves as if the
client had issued the proper series of versioning requests,
performing a commit under the hood. In other words, it allows a
DeltaV server to interoperate with ordinary WebDAV
clients that don't understand versioning.
Because so many operating systems already have integrated WebDAV clients, the use case for this feature borders on fantastical: imagine an office of ordinary users running Microsoft Windows or Mac OS. Each user “mounts” the Subversion repository, which appears to be an ordinary network folder. They use the shared folder as they always do: open files, edit them, save them. Meanwhile, the server is automatically versioning everything. Any administrator (or knowledgeable user) can still use a Subversion client to search history and retrieve older versions of data.
This scenario isn't fiction: it's real and it works, as of
Subversion 1.2 and later. To activate autoversioning in
mod_dav_svn, use the SVNAutoversioning
directive within the httpd.conf Location
block, like so:
<Location /repos> DAV svn SVNPath /path/to/repository SVNAutoversioning on </Location>
When SVNAutoversioning is active, write requests from WebDAV clients result in automatic commits. A generic log message is auto-generated and attached to each revision.
Before activating this feature, however, understand what
you're getting into. WebDAV clients tend to do
many write requests, resulting in a huge
number of automatically committed revisions. For example, when
saving data, many clients will do a PUT of a
0-byte file (as a way of reserving a name) followed by another
PUT with the real filedata. The single
file-write results in two separate commits. Also consider that
many applications auto-save every few minutes, resulting in even
more commits.
If you have a post-commit hook program that sends email, you
may want to disable email generation either altogether, or on
certain sections of the repository; it depends on whether you
think the influx of emails will still prove to be valuable
notifications or not. Also, a smart post-commit hook program
can distinguish between a transaction created via autoversioning
and one created through a normal svn commit.
The trick is to look for a revision property
named svn:autoversioned. If present, the
commit was made by a generic WebDAV client.
Another feature that may be a useful complement
for SVNAutoversioning comes from
Apache's mod_mime module. If a generic
WebDAV client adds a new file to the repository, there's no
opportunity for the user to set the
the svn:mime-type property. This might cause
the file to appear as “generic” icon when viewed
within a WebDAV shared folder, not having an association with
any application. One remedy is to have a sysadmin (or other
Subversion-knowledgable person) check out a working copy and
manually set the svn:mime-type property on
necessary files. But there's potentially no end to such cleanup
tasks. Instead, you can use
the ModMimeUsePathInfo directive in
your Subversion <Location>
block:
<Location /repos> DAV svn SVNPath /path/to/repository SVNAutoversioning on ModMimeUsePathInfo on </Location>
This directive allows mod_mime to attempt
automatic deduction of the mime-type on new files that enter the
repository via autoversioning. The module looks at the file's
named extension and possibly the contents as well; if the file
matches some common patterns, then the the
file's svn:mime-type property will be set
automatically.
All WebDAV clients fall into one of three categories—standalone applications, file-explorer extensions, or filesystem implementations. These categories broadly define the types of WebDAV functionality available to users. Tabell C.1, “Common WebDAV Clients” gives our categorization and a quick description of some common pieces of WebDAV-enabled software. More details about these software offerings, as well as their general category, can be found in the sections that follow.
Tabell C.1. Common WebDAV Clients
| Software | Category | Description |
|---|---|---|
| Adobe Photoshop | Standalone WebDAV applications | Image editing software, allowing direct opening from, and writing to, WebDAV URLs |
| Cadaver | Standalone WebDAV applications | Command-line WebDAV client supporting file transfer, tree, and locking operations |
| DAV Explorer | Standalone WebDAV applications | GUI tool for exploring WebDAV shares |
| davfs2 | WebDAV filesystem implementation | Linux file system driver that allows you to mount a WebDAV share |
| GNOME Nautilus | File-explorer WebDAV extensions | GUI file explorer able to perform tree operations on a WebDAV share |
| KDE Konqueror | File-explorer WebDAV extensions | GUI file explorer able to perform tree operations on a WebDAV share |
| Mac OS X | WebDAV filesystem implementation | Operating system with built-in support for mounting WebDAV shares locally |
| Macromedia Dreamweaver | Standalone WebDAV applications | Web production software able to directly read from and write to WebDAV URLs |
| Microsoft Office | Standalone WebDAV applications | Office productivity suite with several components able to directly read from and write to WebDAV URLs |
| Microsoft Web Folders | File-explorer WebDAV extensions | GUI file explorer program able to perform tree operations on a WebDAV share |
| Novell NetDrive | WebDAV filesystem implementation | Drive-mapping program for assigning Windows drive letters to a mounted remote WebDAV share |
| SRT WebDrive | WebDAV filesystem implementation | File transfer software which, among other things, allows the assignment of Windows drive letters to a mounted remote WebDAV share |
A WebDAV application is a program which contains built-in functionality for speaking WebDAV protocols with a WebDAV server. We'll cover some of the most popular programs with this kind of WebDAV support.
On Windows, there are several well-known applications that contain integrated WebDAV client functionality, such as Microsoft's Office, [53] Adobe's Photoshop, and Macromedia's Dreamweaver programs. They're able to directly open and save to URLs, and tend to make heavy use of WebDAV locks when editing a file.
Note that while many of these programs also exist for the Mac OS X, they do not appear to support WebDAV directly on that platform. In fact, on Mac OS X, the dialog box doesn't allow one to type a path or URL at all. It's likely that the WebDAV features were deliberately left out of Macintosh versions of these programs, since OS X already provides such excellent low-level filesystem support for WebDAV.
Cadaver is a bare-bones Unix commandline program for browsing and changing WebDAV shares. Like the Subversion client, it uses the neon HTTP library—not surprisingly, both neon and cadaver are written by the same author. Cadaver is free software (GPL license) and is available at http://www.webdav.org/cadaver/.
Using cadaver is similar to using a commandline FTP program, and thus it's extremely useful for basic WebDAV debugging. It can be used to upload or download files in a pinch, and also to examine properties, copy, move, lock or unlock files:
$ cadaver http://host/repos
dav:/repos/> ls
Listing collection `/repos/': succeeded.
Coll: > foobar 0 May 10 16:19
> playwright.el 2864 May 4 16:18
> proofbypoem.txt 1461 May 5 15:09
> westcoast.jpg 66737 May 5 15:09
dav:/repos/> put README
Uploading README to `/repos/README':
Progress: [=============================>] 100.0% of 357 bytes succeeded.
dav:/repos/> get proofbypoem.txt
Downloading `/repos/proofbypoem.txt' to proofbypoem.txt:
Progress: [=============================>] 100.0% of 1461 bytes succeeded.
DAV Explorer is another standalone WebDAV client, written in Java. It's under a free Apache-like license and is available at http://www.ics.uci.edu/~webdav/. DAV Explorer does everything cadaver does, but has the advantages of being portable and being a more user-friendly GUI application. It's also one of the first clients to support the new WebDAV Access Control Protocol (RFC 3744).
Of course, DAV Explorer's ACL support is useless in this
case, since mod_dav_svn doesn't support it. The fact that
both Cadaver and DAV Explorer support some limited DeltaV
commands isn't particularly useful either, since they don't
allow MKACTIVITY requests. But it's not
relevant anyway; we're assuming all of these clients are
operating against an autoversioning repository.
Some popular file explorer GUI programs support WebDAV extensions which allow a user to browse a DAV share as if it was just another directory on the local computer, and allowing basic tree editing operations on the items in that share. For example, Windows Explorer is able to browse a WebDAV server as a “network place”. Users can drag files to and from the desktop, or can rename, copy, or delete files in the usual way. But because it's only a feature of the file-explorer, the DAV share isn't visible to ordinary applications. All DAV interaction must happen through the explorer interface.
Microsoft was one of the original backers of the WebDAV specification, and first started shipping a client in Windows 98, known as “Web Folders”. This client was also shipped in Windows NT4 and 2000.
The original Web Folders client was an extension to Explorer, the main GUI program used to browse filesystems. It works well enough. In Windows 98, the feature might need to be explicitly installed if Web Folders aren't already visible inside “My Computer”. In Windows 2000, simply add a new “network place”, enter the URL, and the WebDAV share will pop up for browsing.
With the release of Windows XP, Microsoft started shipping
a new implementation of Web Folders, known as the “WebDAV
mini-redirector”. The new implementation is a
filesystem-level client, allowing WebDAV shares to be mounted
as drive letters. Unfortunately, this implementation is
incredibly buggy. The client usually tries to convert http
URLs (http://host/repos) into UNC share
notation (\\host\repos); it also often
tries to use Windows Domain authentication to respond to
basic-auth HTTP challenges, sending usernames as
HOST\username. These interoperability
problems are severe and documented in numerous places around
the web, to the frustration of many users. Even Greg Stein,
the original author of Apache's WebDAV module, recommends
against trying to use XP Web Folders against an Apache
server.
It turns out that the original “Explorer-only” Web Folders implementation isn't dead in XP, it's just buried. It's still possible to find it by using this technique:
Go to 'Network Places'.
Add a new network place.
When prompted, enter the URL of the repository, but
include a port number in the URL.
For example, http://host/repos would be
entered as http://host:80/repos instead.
Respond to any authentication prompts.
There are a number of other rumored workarounds to the problems, but none of them seem to work on all versions and patchlevels of Windows XP. In our tests, only the previous algorithm seems to work consistently on every system. The general consensus of the WebDAV community is that you should avoid the new Web Folders implementation and use the old one instead, and that if you need a real filesystem-level client for Windows XP, then use a third-party program like WebDrive or NetDrive.
A final tip: if you're attempting to use XP Web Folders, make sure you have the absolute latest version from Microsoft. For example, Microsoft released a bug-fixed version in January 2005, available at http://support.microsoft.com/?kbid=892211. In particular, this release is known to fix a bug whereby browsing a DAV share shows an unexpected infinite recursion.
Nautilus is the official file manager/browser for the GNOME desktop (http://www.gnome.org), and Konqueror is the manager/browser for the KDE desktop (http://www.kde.org). Both of these applications have an explorer-level WebDAV client built-in, and operate just fine against an autoversioning repository.
In GNOME's Nautilus, from the , select and enter the URL. The repository should then be displayed like any other filesystem.
In KDE's Konqueror, you need to use the
webdav:// scheme when entering the URL in
the location bar. If you enter an http://
URL, Konqueror will behave like an ordinary web browser.
You'll likely see the generic HTML directory listing produced
by mod_dav_svn. By entering
webdav://host/repos instead of
http://host/repos, Konqueror becomes a
WebDAV client and displays the repository as a
filesystem.
The WebDAV filesystem implementation is arguably the best sort of WebDAV client. It's implemented as a low-level filesystem module, typically within the operating system's kernel. This means that the DAV share is mounted like any other network filesystem, similar to mounting an NFS share on Unix, or attaching an SMB share as drive-letter in Windows. As a result, this sort of client provides completely transparent read/write WebDAV access to all programs. Applications aren't even aware that WebDAV requests are happening.
Both WebDrive and NetDrive are excellent commercial products which allow a WebDAV share to be attached as drive letters in Windows. We've had nothing but success with these products. At the time of writing, WebDrive can be purchased from South River Technologies (http://www.southrivertech.com). NetDrive ships with Netware, is free of charge, and can be found by searching the web for “netdrive.exe”. Though it is freely available online, users are required to have a Netware license. (If any of that sounds odd to you, you're not alone. See this page on Novell's website: http://www.novell.com/coolsolutions/qna/999.html)
Apple's OS X operating system has an integrated
filesystem-level WebDAV client. From the Finder, select the
item from the
. Enter a WebDAV URL, and it
appears as a disk on the desktop, just like any other
mounted volume. You can also mount a WebDAV share from the
Darwin terminal by using the webdav
filesystem type with the mount command:
$ mount -t webdav http://svn.example.com/repos/project /some/mountpoint $
Note that if your mod_dav_svn is older than version 1.2, OS X will refuse to mount the share as read-write; it will appear as read-only. This is because OS X insists on locking support for read-write shares, and the ability to lock files first appeared in Subversion 1.2.
One more word of warning: OS X's WebDAV client can
sometimes be overly sensitive to HTTP redirects. If OS X is
unable to mount the repository at all, you may need to enable
the BrowserMatch directive in the Apache server's
httpd.conf:
BrowserMatch "^WebDAVFS/1.[012]" redirect-carefully
Linux davfs2 is a filesystem module for the Linux kernel, whose development is located at http://dav.sourceforge.net/. Once installed, a WebDAV network share can be mounted with the usual Linux mount command:
$ mount.davfs http://host/repos /mnt/dav
[53] WebDAV support was removed from Microsoft Access for some reason, but exists in the rest of the Office suite.
Subversion's modular design (covered in “Layered Library Design”) and the availability of language bindings (as described in “Using Languages Other than C and C++”) make it a likely candidate for use as an extension or backend to other pieces of software. For a listing of many third-party tools that are using Subversion functionality under-the-hood, check out the Links page on the Subversion website (http://subversion.tigris.org/project_links.html).
Copyright (c) 2002-2006
Ben Collins-Sussman, Brian W. Fitzpatrick, C. Michael Pilato.
This work is licensed under the Creative Commons Attribution License.
To view a copy of this license, visit
http://creativecommons.org/licenses/by/2.0/ or send a letter to
Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305,
USA.
A summary of the license is given below, followed by the full legal
text.
--------------------------------------------------------------------
You are free:
* to copy, distribute, display, and perform the work
* to make derivative works
* to make commercial use of the work
Under the following conditions:
Attribution. You must give the original author credit.
* For any reuse or distribution, you must make clear to others the
license terms of this work.
* Any of these conditions can be waived if you get permission from
the author.
Your fair use and other rights are in no way affected by the above.
The above is a summary of the full license below.
====================================================================
Creative Commons Legal Code
Attribution 2.0
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR
DAMAGES RESULTING FROM ITS USE.
License
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS
CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS
PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE
WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS
PROHIBITED.
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND
AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS
YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF
SUCH TERMS AND CONDITIONS.
1. Definitions
a. "Collective Work" means a work, such as a periodical issue,
anthology or encyclopedia, in which the Work in its entirety in
unmodified form, along with a number of other contributions,
constituting separate and independent works in themselves, are
assembled into a collective whole. A work that constitutes a
Collective Work will not be considered a Derivative Work (as
defined below) for the purposes of this License.
b. "Derivative Work" means a work based upon the Work or upon the
Work and other pre-existing works, such as a translation,
musical arrangement, dramatization, fictionalization, motion
picture version, sound recording, art reproduction, abridgment,
condensation, or any other form in which the Work may be recast,
transformed, or adapted, except that a work that constitutes a
Collective Work will not be considered a Derivative Work for the
purpose of this License. For the avoidance of doubt, where the
Work is a musical composition or sound recording, the
synchronization of the Work in timed-relation with a moving
image ("synching") will be considered a Derivative Work for the
purpose of this License.
c. "Licensor" means the individual or entity that offers the Work
under the terms of this License.
d. "Original Author" means the individual or entity who created the Work.
e. "Work" means the copyrightable work of authorship offered under
the terms of this License.
f. "You" means an individual or entity exercising rights under this
License who has not previously violated the terms of this
License with respect to the Work, or who has received express
permission from the Licensor to exercise rights under this
License despite a previous violation.
2. Fair Use Rights. Nothing in this license is intended to reduce,
limit, or restrict any rights arising from fair use, first sale or
other limitations on the exclusive rights of the copyright owner
under copyright law or other applicable laws.
3. License Grant. Subject to the terms and conditions of this License,
Licensor hereby grants You a worldwide, royalty-free,
non-exclusive, perpetual (for the duration of the applicable
copyright) license to exercise the rights in the Work as stated
below:
a. to reproduce the Work, to incorporate the Work into one or more
Collective Works, and to reproduce the Work as incorporated in
the Collective Works;
b. to create and reproduce Derivative Works;
c. to distribute copies or phonorecords of, display publicly,
perform publicly, and perform publicly by means of a digital
audio transmission the Work including as incorporated in
Collective Works;
d. to distribute copies or phonorecords of, display publicly,
perform publicly, and perform publicly by means of a digital
audio transmission Derivative Works.
e.
For the avoidance of doubt, where the work is a musical composition:
i. Performance Royalties Under Blanket Licenses. Licensor
waives the exclusive right to collect, whether
individually or via a performance rights society
(e.g. ASCAP, BMI, SESAC), royalties for the public
performance or public digital performance (e.g. webcast)
of the Work.
ii. Mechanical Rights and Statutory Royalties. Licensor waives
the exclusive right to collect, whether individually or
via a music rights agency or designated agent (e.g. Harry
Fox Agency), royalties for any phonorecord You create from
the Work ("cover version") and distribute, subject to the
compulsory license created by 17 USC Section 115 of the US
Copyright Act (or the equivalent in other jurisdictions).
f. Webcasting Rights and Statutory Royalties. For the avoidance of
doubt, where the Work is a sound recording, Licensor waives the
exclusive right to collect, whether individually or via a
performance-rights society (e.g. SoundExchange), royalties for
the public digital performance (e.g. webcast) of the Work,
subject to the compulsory license created by 17 USC Section 114
of the US Copyright Act (or the equivalent in other
jurisdictions).
The above rights may be exercised in all media and formats whether now
known or hereafter devised. The above rights include the right to make
such modifications as are technically necessary to exercise the rights
in other media and formats. All rights not expressly granted by
Licensor are hereby reserved.
4. Restrictions.The license granted in Section 3 above is expressly
made subject to and limited by the following restrictions:
a. You may distribute, publicly display, publicly perform, or
publicly digitally perform the Work only under the terms of this
License, and You must include a copy of, or the Uniform Resource
Identifier for, this License with every copy or phonorecord of
the Work You distribute, publicly display, publicly perform, or
publicly digitally perform. You may not offer or impose any
terms on the Work that alter or restrict the terms of this
License or the recipients' exercise of the rights granted
hereunder. You may not sublicense the Work. You must keep intact
all notices that refer to this License and to the disclaimer of
warranties. You may not distribute, publicly display, publicly
perform, or publicly digitally perform the Work with any
technological measures that control access or use of the Work in
a manner inconsistent with the terms of this License
Agreement. The above applies to the Work as incorporated in a
Collective Work, but this does not require the Collective Work
apart from the Work itself to be made subject to the terms of
this License. If You create a Collective Work, upon notice from
any Licensor You must, to the extent practicable, remove from
the Collective Work any reference to such Licensor or the
Original Author, as requested. If You create a Derivative Work,
upon notice from any Licensor You must, to the extent
practicable, remove from the Derivative Work any reference to
such Licensor or the Original Author, as requested.
b. If you distribute, publicly display, publicly perform, or
publicly digitally perform the Work or any Derivative Works or
Collective Works, You must keep intact all copyright notices for
the Work and give the Original Author credit reasonable to the
medium or means You are utilizing by conveying the name (or
pseudonym if applicable) of the Original Author if supplied; the
title of the Work if supplied; to the extent reasonably
practicable, the Uniform Resource Identifier, if any, that
Licensor specifies to be associated with the Work, unless such
URI does not refer to the copyright notice or licensing
information for the Work; and in the case of a Derivative Work,
a credit identifying the use of the Work in the Derivative Work
(e.g., "French translation of the Work by Original Author," or
"Screenplay based on original Work by Original Author"). Such
credit may be implemented in any reasonable manner; provided,
however, that in the case of a Derivative Work or Collective
Work, at a minimum such credit will appear where any other
comparable authorship credit appears and in a manner at least as
prominent as such other comparable authorship credit.
5. Representations, Warranties and Disclaimer
UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING,
LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR
WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED,
STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF
TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE,
NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY,
OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT
DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED
WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY
APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY
LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE
OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE
WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
7. Termination
a. This License and the rights granted hereunder will terminate
automatically upon any breach by You of the terms of this
License. Individuals or entities who have received Derivative
Works or Collective Works from You under this License, however,
will not have their licenses terminated provided such
individuals or entities remain in full compliance with those
licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any
termination of this License.
b. Subject to the above terms and conditions, the license granted
here is perpetual (for the duration of the applicable copyright
in the Work). Notwithstanding the above, Licensor reserves the
right to release the Work under different license terms or to
stop distributing the Work at any time; provided, however that
any such election will not serve to withdraw this License (or
any other license that has been, or is required to be, granted
under the terms of this License), and this License will continue
in full force and effect unless terminated as stated above.
8. Miscellaneous
a. Each time You distribute or publicly digitally perform the Work
or a Collective Work, the Licensor offers to the recipient a
license to the Work on the same terms and conditions as the
license granted to You under this License.
b. Each time You distribute or publicly digitally perform a
Derivative Work, Licensor offers to the recipient a license to
the original Work on the same terms and conditions as the
license granted to You under this License.
c. If any provision of this License is invalid or unenforceable
under applicable law, it shall not affect the validity or
enforceability of the remainder of the terms of this License,
and without further action by the parties to this agreement,
such provision shall be reformed to the minimum extent necessary
to make such provision valid and enforceable.
d. No term or provision of this License shall be deemed waived and
no breach consented to unless such waiver or consent shall be in
writing and signed by the party to be charged with such waiver
or consent.
e. This License constitutes the entire agreement between the
parties with respect to the Work licensed here. There are no
understandings, agreements or representations with respect to
the Work not specified here. Licensor shall not be bound by any
additional provisions that may appear in any communication from
You. This License may not be modified without the mutual written
agreement of the Licensor and You.
Creative Commons is not a party to this License, and makes no warranty
whatsoever in connection with the Work. Creative Commons will not be
liable to You or any party on any legal theory for any damages
whatsoever, including without limitation any general, special,
incidental or consequential damages arising in connection to this
license. Notwithstanding the foregoing two (2) sentences, if Creative
Commons has expressly identified itself as the Licensor hereunder, it
shall have all rights and obligations of Licensor.
Except for the limited purpose of indicating to the public that the
Work is licensed under the CCPL, neither party will use the trademark
"Creative Commons" or any related trademark or logo of Creative
Commons without the prior written consent of Creative Commons. Any
permitted use will be in compliance with Creative Commons'
then-current trademark usage guidelines, as may be published on its
website or otherwise made available upon request from time to time.
Creative Commons may be contacted at http://creativecommons.org/.
====================================================================