= Source Control Tools = [[TOC(heading=Inhoudsopgave)]] [[TOC(heading=Hoofdstukken, sectionindex, compact, depth=2, Documentatie/Ontwikkelhandleiding/*)]] OpenAC wordt ontwikkeld en onderhouden in een [http://subversion.apache.org/ Subversion] repository. Subversion is de standaard manier om met die repository om te gaan, maar het is ook mogelijk om met andere versiebeheer programma's aan OpenAC te werken. == Subversion == De SVN repository bevat twee directories: {{{development/}}} met de actuele ontwikkelversie, en {{{release/}}} met daarin stabiele releases van OpenAC. De versies onder release hebben namen {{{v1.nnn/}}} (uiteindelijk ook {{{v2.nnn/}}}). De AC's kunnen zelf wijzigingen in hun adapataties inleveren. Ze doen dit in de regel in de nieuwste release. Wanneer een AC een wijziging heeft ingeleverd, is dit te zien in de timeline van TRAC. Die houden we als ontwikkelaars dus nauwlettend in de gaten. Wekelijks worden wijzigingen door centra ingeleverd overgenomen in de development-tak. Als centra een oudere release in gebruik hebben, worden wijzigingen ook in de nieuwere releases overgenomen. Wanneer een centrum een wijzing indient en er is al een nieuwe release, krijgt men een waarschuwing dat de ingeleverde zaken niet automatisch beschikbaar zijn in de nieuwe release. === Command-Line === === TortoiseSVN === === OpenAC SVN === == Mercurial == [http://mercurial.selenic.com/ Mercurial] is een zogeheten ''gedistribueerd'' versiebeheersysteem. Dat betekent dat de gehele source en geschiedenis lokaal wordt opgeslagen en lokaal wordt bewerkt. Elke gebruiker heeft zijn of haar eigen kopie van de hele geschiedenis, en het is aan de gebruikers om vervolgens hun lokale wijzigingen met elkaar te delen. Het voordeel van zo'n gedistribueerd systeem is dat ontwikkeling -- commits, probeersels, branches en soms ook reverts -- losgekoppeld zijn van het publiceren of delen van die stappen. Experimenten kunnen worden uitgevoerd zonder een centrale repository te "vervuilen." Daarnaast heeft iedere gebruiker een volledige geschiedenis van het project en is het dus mogelijk om grotendeels "offline" te werken -- een voordeel op reis of in de trein. Mercurial kan heel goed met Subversion repositories overweg als je een plugin installeert. Hierdoor kan je een branch van de Subversion repository als Mercurial repository importeren en bewerken, en doet {{{hg push}}} hetzelfde als {{{svn commit}}} voor alle nieuwe changesets in je lokale repository. De combinatie van mq en hgsubversion maakt het makkelijk om stapsgewijs te ontwikkelen en die geschiedenis te bewaren ook in de centrale Subversion repository terwijl je ook makkelijk dingen kunt terugdraaien als het nodig is. Je kan ook eigen patches -- bijvoorbeeld extra debugging dingen -- gemakkelijk prive houden terwijl je je gewone werk naar de centrale server publiceert. Maak allereerst een directory om je extra Mercurial configuratie en extensies in te bewaren. Het is het handigst in je home directory, genaamd {{{.hgext}}}. De voorbeelden hieronder gaan allemaal er van uit dat je die directory hebt. {{{ mkdir ~/.hgext }}} === Installatie === Je hebt allereerst Mercurial zelf nodig, en de [http://mercurial.selenic.com/wiki/HgSubversion hgsubversion] extensie moet je apart installeren. Dat gaat het makkelijkst als je Mercurial al hebt. Ga naar je home directory, en clone dan de repo: {{{ hg clone https://bitbucket.org/durin42/hgsubversion }}} Daarna kan je -- als je de configuratie hieronder ongewijzigd wilt gebruiken -- de map {{{hgsubversion/hgsubversion}}} hernoemen naar {{{.hgsubversion}}} en daarna de clone weer weggooien. {{{ mv hgsubversion/hgsubversion ~/.hgext rm -rf hgsubversion }}} Maak daarna de configuratie-files aan zoals hieronder omschreven bij [#hg.configuratie Configuratie]. === Configuratie ===#hg.configuratie Er zijn twee extensies ''nodig'' om met Mercurial aan OpenAC te werken (''hgsubversion'' en ''rebase''), en twee ''aanbevolen'' (dat zijn ''graphlog'' en ''mq''). Daarnaast is het handig om Mercurial zo te configureren dat je een zinvolle username doorgeeft, de artefacten van Python ontwikkeling negeert, en logs produceert die een beetje overeenstemmen met Subversion zodat je makkelijk mee kunt praten over "revisie r1". Vanaf Mercurial v1.7 zijn ''rebase'', ''graphlog'' en ''mq'' allemaal onderdeel van de standaard Mercurial configuratie. De extensie [http://mercurial.selenic.com/wiki/HgSubversion hgsubversion] moet apart worden geinstalleerd. Subversion-achtige logs krijg je met een ''log template''. Maak een file {{{~/.hgext/style.svn}}} aan met de volgende inhoud; hiermee verwijs je naar een specifieke template file die in dezelfde directory staat. {{{ changeset = style.svn.template file = " {file}\n" }}} Maak ook een file {{{~/.hgext/style.svn.template}}} met de template zelf. {{{ changeset: r{svnrev} {rev}:{node} user: {author} date: {date|isodate} files: {files|stringify|tabindent} {desc|fill68|tabindent} }}} Let op spaties in dit template, inclusief de lege regel aan het eind. Hiermee wordt een mengeling van de Subversion en Mercurial logs afgedrukt. Bij elke changeset krijg je de Subversion revision te zien (als het bestaat) zoals r1. Daarnaast de Mercurial changeset aanduiding met nummer en hash. Alle gewijzigde files worden afgedrukt als ware het de uitvoer van {{{svn log -v}}}, en de commit message wordt volledig afgedrukt, uitgelijnd naar 68 kolommen. Python ontwikkeling zet een boel compiled Python objects in de repository, en ontwikkeling met Mercurial kan veel patch artefacten opleveren, met {{{.orig}}} files en backups. Maak een bestand {{{~/.hgext/ignore.python}}} met de volgende inhoud: {{{ syntax: glob *.pyc *.pyo *.py~ *.py.orig *.py.rej *.py.bak }}} Om een checkout te kunnen doen van OpenAC moet je de juiste extensies aanzetten in je {{{~/.hgrc}}}, door de volgende regels toe te voegen (als er al een section {{{[extensions]}}} is, de twee regels eronder toevoegen. {{{ [extensions] hgsubversion = ~/.hgext/hgsubversion rebase = }}} Maak vervolgens een [#Clone clone van de repository]. Dat levert een directory {{{v2.000/}}} op en daarbinnen een directory {{{v2.000/.hg}}} waar je de laatste beetjes configuratie kunt neerzetten. Voeg het volgende '''toe''' aan het bestand {{{v2.000/.hg/hgrc}}} die er al staat. Er staat al (minstens) een {{{[path]}}} om de pull- en push-bestemming in te stellen. {{{ [extensions] hgext.graphlog = mq = hgsubversion = ~/.hgext/hgsubversion rebase = [ui] username = Adriaan de Groot ignore.python = ~/.hgext/ignore.python style = ~/.hgext/style.svn }}} === Clone === Als Mercurial eenmaal correct is geinstalleerd en geconfigureerd, kan je met {{{hg help svn}}} controleren of ''hgsubversion'' wel goed werkt. Daarna kan je de OpenAC repository clonen. Merk op dat je maar '''een branch''' tegelijk kunt clonen. Dat komt omdat de layout van de Subversion repository van OpenAC afwijkt van wat hgsubversion normaal aankan. Een branch is prima, dus je kan die releases clonen die je nodig hebt -- voorlopig is dat alleen v2.0: {{{ hg clone svn+https://svn.openac.fenac.nl/release/v2.000 v2.000 }}} Dit kan '''lang duren''' terwijl Mercurial elke revisie van die branch (momenteel zo'n 1100) ophaalt en vertaalt naar een lokale Mercurial changeset. Als het proces wordt afgebroken, dan kan het later hervat worden door in de {{{v2.000}}} directory een {{{hg pull}}} te doen. === Workflow === Bij Mercurial zijn veel verschillende workflows mogelijk. Omdat changesets uiteindelijk in Subversion terecht moeten komen zijn '''branches en merges niet toegestaan''' op het moment dat je naar Subversion pusht. Uiteraard kan je lokale clones maken voor branchy development en dan relevante branches met cherry-picking weer in je Subversion clone laten verschijnen zonder branches of merges. Typische workflow ziet er zo uit (met ''mq''): - Werk de clone bij vanaf de Subversion repository. {{{ hg pull }}} - Besluit om aan feature ''X'' te gaan werken, of pak ticket ''N'' aan. Begin een serie patches om dat te doen. {{{ hg qnew -m "Begin feature X" feature-X }}} - Breng veranderingen aan, besluit dat dit een redelijke stap vooruit is. {{{ hg qref }}} - Ondertussen kan je nieuwe commits uit de centrale repository overhalen met {{{hg pull}}}. Die komen niet in dezelfde branch als de patches waar je nu mee bezig bent, dus die hebben geen effect tenzij je een rebase doet van je patches. Maar je kan wel zien wat er verder gebeurt en ook diffs bekijken of eventjes bijwerken om te kijken wat voor effect je veranderingen hebben. - Als je een nieuwe patch aan wilt maken, bijvoorbeeld omdat je een afzonderlijke stap in de ontwikkeling van je feature wilt zetten of omdat je tussendoor een bug wilt fixen, gebruik je {{{hg qnew}}} met een nieuwe patch-naam. - Na verloop van tijd denk je "dit kan naar de repository". Dan haal je eventjes al je patches weg, werk je helemaal bij vanaf subversion, zet je de patches terug (hier kunnen conflicten optreden, maar je hebt de individuele patches om mee te werken en kan met de hand mergen), en push je de patches naar de repo. {{{ hg qpop -a hg pull -u hg qpush -a hg qfin -a hg push }}} - Met de tools van ''mq'' kan je je patches zo ordenen dat je evt. ook zinvolle sub-branches of delen van je werk kunt pushen. Hierdoor kan je bijvoorbeeld bug-fixes die je halverwege het ontwikkelen doet, naar voren halen in je lokale geschiedenis en dan pushen zonder dat je feature werk beinvloed wordt. == Git == Git is een gedistribueerd versiebeheer systeem met een zeer uitgebreide toolset en een nogal cryptische ''core'' -- een kern waarmee je wel alles kunt. Git beschikt ook over een goeie SVN bridge, zodat je met git kunt werken en de gedistribueerde kenmerken van git kunt gebruiken en '''tegelijk''' ook gecontroleerd met Subversion om kunt gaan. Hierdoor wordt het mogelijk om samen te werken in git en dan af te ronden in Subversion. [[NoteBox(tip, Hier staat alleen hoe je OpenAC-specifieke handelingen voor git moet ondernemen. Een [http://git-scm.com/book/en/Git-Basics algemene handleiding voor git] is het boek Pro Git (gratis via de git site).)]] [[NoteBox(warn, Omdat git over ssh gaat, moet je wel naar de OpenAC server kunnen ssh-en. Dat is aan FENAC-ontwikkelaars voorbehouden en gekoppeld aan specifieke IP adressen.)]] === Installatie === Onder Linux is git een van de standaard ontwikkeltools die bij je distro zitten. Installatie wisselt per distro, maar de package zal waarschijnlijk ''git'' heten (in OpenSUSE, `zypper in git`). Onder Windows, haal de [http://git-scm.com/download/win nieuwste installer] op van [http://git-scm.com/ git-scm.com]. Ga de installer uitvoeren. Tijdens het installeren kan je kiezen welke componenten geinstallerd worden. De defaults zijn goed. Ik zet zelf het vinkje bij ''Use a !TrueType font'' omdat ik dat prettiger vind lezen in een console window. [[Image(git-win1.PNG,class=inline)]] Een volgende keuze die je moet maken is of je git en andere meegeleverde tools bij '''alle''' command-prompt windows wilt hebben, of alleen in speciale ''Git Bash'' windows. Dat hangt af van hoe veel je de command-prompt normaal gebruikt en war je gewoontes zijn. Ik kies voor de optie om git overal beschikbaar te maken, omdat ik graag de UNIX-style tools heb. Maar de default keuze, alleen ''Git Bash'', is ook prima. [[Image(git-win2.PNG,class=inline)]] Vervolgens moet je kiezen hoe git met line-endings omgaat. Kies hier voor ''checkout Windows, commit UNIX''. Dit komt overeen met de SVN instelling `eol-style:LF` zodat alleen LF in de repository komt, terwijl de files makkelijk(er) te editen zijn met iets als Wordpad. [[Image(git-win3.PNG, class=inline)]] [[Image(git-win4.PNG, class=inline-right)]]Hierna wordt git geinstalleerd op het systeem en krijg je een bureau-blad icoontje. Als je dit opstart, krijg je een Linux-achtige shell omgeving waarin je git uit kunt voeren. De commando's hieronder gaan er allemaal van uit dat je zo'n git bash window tot je beschikking hebt. [[Image(git-win5.PNG, class=inline)]] === Starten === - '''SSH''' Maak eerst een SSH-key aan waarmee je naar de FENAC server kunt SSH'en. Hiervoor is een gebruikers-login op de server zelf nodig. Je kan alleen vanaf Audcom bij die server. Configureer SSH vervolgens zo dat je een nette alias (zeg ''openac'') voor die verbinding. Dat kan door in je `~/.ssh/config` dit op te nemen: {{{ Host openac HostName svn.openac.fenac.nl User mijzelf IdentityFile ~/.ssh/id_openac }}} - '''Initiele Clone''' Dit maakt een clone in de directory `openac-git` en gaat vervolgens de (remote) development branch volgen. Bij de eerste clone komt er misschien een foutmelding dat er geen checkout gemaakt kan worden omdat HEAD geen remote-ref heeft. Die kan je negeren, want je wilt toch een andere branch volgen. {{{ git clone -o mirror ssh://openac/home/svn/openac-git cd openac-git/ git checkout -t mirror/git-svn git svn init --prefix=mirror/ https://svn.openac.fenac.nl/development git svn dcommit }}} - '''Configuratie''' Voordat je verder werkt met de repository, kan je het beste je gebruikersgegevens zoals die in de log worden vertoond, aanpassen (anders klaagt `git commit` erover). Hiermee stel je (voor '''deze''' repository alleen) je te-vertonen gebruikersnaam en email adres in. Traditioneel gebruiken we alleen een voornaam: {{{ git config user.name "Adriaan" git config user.email "a.degroot@fenac.nl" }}} - '''Update''' Dit werkt de checked out working-directory bij naar de huidige stand van SVN, met behoud van eigen commits sinds de laatste keer (zoals `svn up`). {{{ git checkout git-svn git pull --rebase }}} - '''Commit''' In git kan je altijd lokaal committen. Deze commits gaan niet (direct) naar de centrale server, en je kan dus experimenteren en/of een feature in meerdere commits opbouwen zonder dat dat zichtbaar is voor de buitenwereld. Hoe git commits te doen staat in de git handleidingen. - '''SVN Push''' Als je iets af hebt en dat om wilt zetten naar SVN changesets, doe je {{{ git svn dcommit }}} Hiermee worden je git commits een-voor-een naar SVN gestuurd als SVN commits. Je checkout wordt ook (net als bij update) bijgewerkt naar de meest recente SVN checkout. === Workflow === Op de manier zoals hierboven is omschreven kan je git gebruiken als SVN client. Enig voordeel ten opzichte van SVN zelf is dat je ook lokale commits kunt doen en iets lokaal af kunt maken zonder dat je tussentijdse commits naar SVN hoeft te doen. Aan het eind van de rit kan je met ''dcommit'' je changesets naar SVN pushen. Eventueel kan je ook met '''branches''' werken om changesets onafhankelijk van elkaar te ontwikkelen, of om verschillende problemen los van elkaar op te lossen. Het plaatje hieronder laat een (eenvoudige) grafische weergave zien van branches in git tijdens OpenAC ontwikkeling. [[Image(branches.png)]] De branch ''git-svn'' komt overeen met SVN zelf. Er zijn twee remote branches, een genaamd ''backups'' (voor een niet nader gespecificeerd feature) en een genaamd ''ticket5150'' (om [#5150 dat ticket] op te lossen). De ticket-branch is net geopend en loopt vanaf de nieuwste SVN revisie verder. De backups-branch is een stuk ouder. Onder normale omstandigheden zouden er meer branches zijn van wisselende ouderdom, en ook een mengsel van lokale en remote branches. - '''Lokale branch''' Om een ticket op te lossen in een aparte (lokale, heel goedkope) branch, maak je een branch, schakel je daar op over, werk je normaal en doe je gewoon git commits. Af-en-toe controleer je dat je hele geschiedenis van fixes nog werkt ten opzichte van wat er nu in SVN staat. Je kan tussendoor ook wisselen naar andere branches of naar de huidige staat van SVN als je aan iets anders moet werken. Tenslotte maak je de branch af met en verdwijnt die -- de commits worden allemaal omgezet in SVN commits. - '''Maak branch''' Kies een naam voor de lokale branch. Als het voor een ticket is, gebruik dan de naam ''ticketNNNN'' met het ticket nummer erin. Hiermee houd je de ticket-branches duidelijk zichtbaar ten opzichte van feature- en experimenteer-branches. Start de branch op ''git-svn'' zodat je vanaf een bekende SVN revisie begint: {{{ git checkout git-svn git checkout -b ticketNNNN }}} - '''Wissel branch''' Als je tussendoor van branch wilt wisselen -- bijvoorbeeld om verder te werken aan een ander ticket of om ''git-svn'' bij te werken -- dan gebruik je weer `git checkout`, bijvoorbeeld een van deze: {{{ git checkout git-svn git checkout ticketNNNN }}} - '''SVN bijwerken''' Zoals gewoonlijk kan je de branch ''git-svn'' bijwerken zoals hierboven beschreven. Maar daarmee heb je niet je eigen wijzigingen overgezet naar (git-)commits vanaf de meest recente SVN revisie. Daarvoor moet je eerst bijwerken vanuit SVN, en dan je eigen commits er bovenop zetten: {{{ git checkout git-svn git pull --rebase git checkout ticketNNNN git rebase git-svn }}} - '''Geschiedenis aanpassen''' In git doe je heel vaak kleine commits en er kunnen ook "tussentijdse" tussen zitten die op zichzelf niet interessant zijn. Je kunt een branch met commits interactief herschrijven door commits samen te voegen en log-messages te veranderen, voordat je ze naar SVN stuurt. Daarvoor gebruik je de `-i` vlag bij rebase: {{{ git checkout ticketNNNN git rebase -i git-svn }}} Dit start een tekst-editor op met instructies over hoe je de commits kunt her-ordenen of anders aanpassen. - '''Branch afmaken''' Ben je helemaal klaar met een branch en wil je de commits in die branch overzetten naar SVN zodat ze ook echt in OpenAC zitten, dan doe je eerst SVN bijwerken, daarna SVN push en tot slot gooi je de branch weg -- in feite gooi je alleen de naam van de branch weg, de commits blijven staan want ze zitten dan al in SVN. Bijwerken en push staan hierboven beschreven. Weggooien van de branch gaat tenslotte zo: {{{ git checkout git-svn git branch -d ticketNNNN }}} - '''Remote branch''' Als je wilt samenwerken aan een feature, maar niet wilt dat dit meteen zichtbaar is in SVN, of als je een bugfix hebt maar die wilt laten reviewer, dan kan je een lokale branch als '''remote''' branch in de git repository pushen. Dan wordt de branch zichtbaar voor anderen die de git repository gebruiken, maar wordt het niet naar SVN gepusht. Hierdoor kan er "onzichtbaar" aan iets gewerkt worden totdat het af is, en kan iets goed getest worden voordat het in SVN komt. - '''Branch publiceren''' - '''Branches volgen''' - '''Branch afmaken''' Als je een remote branch hebt (voor een bepaald ticket, zeg) en je weet dat die klaar is (iedereen heeft het gezien, changesets gepushed, is getest enzovoorst) dan kan je het afmaken door de branch naar SVN te pushen. Ondertussen kan je geschiedenis herschrijven. Daarna moet je wat opruimwerk doen. In [attachment:git-svn-finish.sh] staat een script ter illustratie (waarschijnlijk kan dat makkelijker). === Infrastructuur === (dit is de documentatie over hoe de git-svn infrastructuur op de server is geconfigureerd; dat gaat allemaal volgens de handleiding van tfnico.com)