Vagrant + Windows static file caching

Oplossing voor het vreemdste probleem van vandaag; Ik heb een Vagrant box draaien in Virtualbox welke via een vm.share_folder een virtuele share maakt tussen bestanden op de pc en de virtuele server. Dit werkte voor dynamische bestanden prima maar bij o.a. CSS & JS files ging het fout.

Als ik het bestand opriep via de browser kreeg ik een oude versie (ongeacht of je er bijvoorbeeld .css?1 van maakte of iets). Gooide ik het bestand weg dan werkte het wel. Alles nagelopen rondom browser en server-side caching maar daar zat het niet.

De dader: Sendfile()

Na wat onderzoek op het grote web kwam ik erachter dat dit komt door de manier waarop statische files worden opgehaald middels de sendfile() call welke in Virtualbox echter niet goed werkt. Hierdoor werd het bestand als het ware éénmalig echt opgehaald en vanaf dat punt kreeg je een versie uit de ‘cache’ terug. De verwarring is groot omdat dit bestand zich niet als gecached gedraagt; de headers zijn goed, er zijn geen opvallende cache-tags te vinden of iets.

De oplossing

Als je op Windows zit is de meest handige oplossing om sendfile uit te schakelen. Dit doe je met de volgende config line voor je Apache;
EnableSendfile off

Voor Mac gebruikers zou ik eerder gaan kijken naar andere manier om de virtual share te maken namelijk NFS: http://docs-v1.vagrantup.com/v1/docs/nfs.html

Dit probleem speelt hier niet en de performance is aanzienlijk beter.

Zend Framework 2: Form validation error messages translated

Om mij nog niet geheel duidelijke redenen gebruikt ZF2 voor de vertalingen van validatie errors niet de default locale. Dit is erg spijtig maar is relatief eenvoudig op te lossen. Even de stappen bij elkaar om het helder te houden.

Translator configureren: autoload/global.php

'service_manager' => array(
    'aliases' => array(
        'translator' => 'MvcTranslator',
    ),
),
'translator' => array(
    'locale' => 'nl_NL',
    'translation_file_patterns' => array(
        array(
            'type' => 'phpArray',
            'base_dir' => __DIR__ . '/../../resources/languages',
            'pattern' => '/%s/Zend_Validate.php',
        ),
    ),
),

Hierbij zorgt regel 7 ( ‘locale’ => ‘nl_NL’) ervoor dat de default locale van de gehele applicatie op nl_NL komt te staan. Uiteraard kan dit ook via bijvoorbeeld een call in de bootstrap gedaan worden op basis van taalinstellingen browser, url of wat voor leuks dan ook.

Forceren validation error translation: module.php

Dan de verassing; de vertalingen van de validatie errrors zijn niet vertaald. Om dit te forceren moet je in de bootstrap van de module het volgende toevoegen;

public function onBootstrap($e)
{
    $translator = $e->getApplication()->getServiceManager()->get('translator');
    AbstractValidator::setDefaultTranslator($translator);
}

Met een beetje geluk zijn nu de validatie errors van de forms netjes vertaald naar de Nederlandse versie.

Zend Framework 2 controller based layout

In Zend Framework 2 kan het soms wenselijk zijn een afwijkende layout te configureren voor een controller. Bijvoorbeeld om een admin & front controller te dienen met een afwijkende layout. Er zijn hiervoor een aantal voorbeelden te vinden maar was zelf niet helemaal tevreden hierover dus kwam uiteindelijk met het volgende om een verschil te maken tussen de PageAdminController.php & PageFrontController.php

module.config.php


return array(
    'view_manager' => array(
        'template_map' => array(
            'layout/layout' => __DIR__ . '/../view/layout/default.phtml',
            'layout/admin' => __DIR__ . '/../view/layout/admin.phtml',
            'layout/front' => __DIR__ . '/../view/layout/front.phtml',
        ),
    ),
);

module.php


public function onBootstrap($e)
{
    $eventManager = $e->getApplication()->getEventManager();
    $eventManager->getSharedManager()->attach(
        'Zend\Mvc\Controller\AbstractActionController',
        'dispatch',
        function ($e) {
            $controller = $e->getTarget();
            $ccString = preg_split('/(?=[A-Z])/', get_class($controller));
            $layoutType = strtolower($ccString[count($ccString) - 2]);
            $config = $e->getApplication()->getServiceManager()->get('config');
            if (isset($config['view_manager']['template_map']['layout/' . $layoutType])) {
                $controller->layout('layout/' . $layoutType);
            }
        }
    );
}

Wat hij nu doet is in de module.php op basis van de controller-naam controleren of er een layout gedefinieerd is. Zo niet dan doet hij niets en gebruikt hij de default (layout/layout). Bestaat hij wel dan gebruikt hij bijvoorbeeld de layout/admin of layout/front.

Google maps API geocoding met Zend_Http_Client

Voor een leukheidje in een CMS wilde ik de geo-coordinaten van een adres ophalen. Ik had al wel iets liggen maar dat was wat oudere code en wilde de output als JSON hebben. Hier de meest recht-toe-recht-aan oplossing om verder te ontwikkelen naar wens:

// Address to lookup. Don't overlook the + instead of spaces
$address = 'Stationsplein+45,3013+AK,ROTTERDAM';

$client = new Zend_Http_Client();
$client->setUri('https://maps.googleapis.com/maps/geo');
$client->setConfig(array('maxredirects' => 0, 'timeout' => 30));
$client->setParameterGet('output', 'json');
$client->setParameterGet('q', $address);
$response = $client->request('GET');

$body = $response->getBody();
$response = Zend_Json::decode($body, Zend_Json::TYPE_OBJECT);

if($response->Status->code == 200) {
    // Jeej, success
    Zend_Debug::dump($response);
} else {
    // Trouble!
    Zend_Debug::dump($response);
}

Zoals ik al zei, geen übercode die klaar is voor gebruik maar een leuke basis voor implementatie in een Google maps service of class.

PHP xmlWriter resultaten naar log schrijven

Een bestaande applicatie die een XML export doet met XMLWriter moest voorzien worden van een mogelijkheid om de exacte XML output weg te schrijven in een log. Het script maakte in eerste instantie gebruik van directe output naar de browser:

$xml->openURI('php://output');

Om het totale resultaat van de XML output in een logfile te schrijven was dit niet ideaal. Het zou op zich wel kunnen maar omzetten naar gebruik van het geheugen voor opslag van de XML was iets handiger (zeker omdat het om relatief weinig data per run ging).

Hieronder de code voor een basis XML die zowel naar de browser gaat als naar een logfile:

// Set correct header
header('Content-Type: application/xml, charset=utf-8');

// Initiate XMLWriter
$xml = new XMLWriter();

// Create new xmlwriter using memory for string output
$xml->openMemory();

// Create document tag
$xml->startDocument('1.0', 'UTF-8');

// Create start element tag
$xml->startElement('test');

//  Write full element tag
$xml->writeElement('value', 'testwaarde');

// End current element
$xml->endElement();

// End current document
$xml->endDocument();

// Define logfile name
$filename = '/logs/' . date('Ymd_hm') . '.xml';

// Open file
$fp = fopen($filename, "w");

// Write memory output to file. The false boolean is to
// prevent XMLWriter from flushing the current buffer
fwrite($fp, $xml->outputMemory(false));

// Close the file
fclose($fp);

// Return the current buffer
echo $xml->outputMemory();

Dit is een redelijk kort samengevat voorbeeld en het kan altijd beter, netter en leuker maar het idee is duidelijk.

PHP memory limit stress test

In het vervolg op mijn eerdere bericht over een CPU stress test met PHP werd ook de vraag neergelegd om iets te maken wat de max uit het geheugen zou halen met PHP. Wederom volgde een korte brainstorm. Ik wilde voorkomen dat mijn memory test afhankelijk was van externe partijen (bijv. inlezen enorme datareeks of iets) en minimaal de processor zou belasten (om te voorkomen dat hij al tegen een CPU usage limiet aan zou lopen voor hij echt het geheugen vol kon stoppen). Het moest dus iets zijn wat iets simpels deed maar wel een monster ervan maakte voor het geheugen. Mijn oplossing is een scriptje wat éénmalig een string van 26 tekens maakt en die dan 5000 keer 5 keer achter elkaar plakt.

Even voor de lol de stringlengtes die PHP dus in het geheugen probeert te bewaren per for-loop (waarvan er 5000 zijn):
1x = 130 tekens
2x = 650 tekens
5x = 81250 tekens
10x = 253906250 tekens
15x = 793457031250 tekens

Etc. etc. Nog voor je bij een paarhonderd loops bent aangekomen vindt excel al dat de uitkomt “#GETAL!” is.

function generateData($loops)
{
	$chars = "ABCDEFGHJKLMNPQRSTUVWXYZ123456789";
	$i = 0;
	$string = null;
	
	while ($i <= 25) {
		$num = rand() % 33;
		$tmp = substr($chars, $num, 1);
		$string = $string . $tmp;
		$i++;
	}
	
	for ($i = 1; $i <= $loops; $i++) {
		$string = $string.$string.$string.$string.$string;
	}

	return $string;
}

$value = generateData(5000);
die('Wow, your memory is endless!');

Of download hem hier als kant-en-klaar PHP scriptje (tar file)

PHP CPU stress test

Recent vroeg iemand mij of ik even een scriptje in elkaar kon zetten wat een CPU tot de max kon drijven via PHP. Natuurlijk wil ik dat. Heel even voelt het dan net of je iets mag slopen. Na een korte brainstorm realiseerde ik me dat het helemaal niet zo’n ingewikkelde uitdaging ging worden als ik had gehoopt. Ik moest een proces hebben wat veel rekenkracht vroeg en ik moest het gewoon zo vaak mogelijk los laten op de processor als mogelijk in een zo kort mogelijk tijd. Het eerst wat in me opkwam was een loop met daarin een PI calculatie. Beetje zoeken op internet gaf me een nette PI calculatie code, daar nog wat omheen bakken en dan heb je iets als:

function bcpi($precision){
	bcscale($precision+6);
	$a = bcsqrt(2);
	$b = 0;
	$p = bcadd(2, $a);
	$i = 0;
	$count = ceil(log($precision+6)/log(2))-1;
	while($i < $count){
		$sqrt_a = bcsqrt($a);
		$a1 = $a;
		$a = bcdiv(bcadd($sqrt_a,bcdiv(1,$sqrt_a)),2);
		$b_up = bcmul($sqrt_a,bcadd(1,$b));
		$b_down = bcadd($a1,$b);
		$b = bcdiv($b_up, $b_down);
		$p_up = bcmul(bcmul($p,$b),bcadd(1,$a));
		$p_down = bcadd(1, $b);
		$p = bcdiv($p_up, $p_down);
		++$i;
	}
 
return bcadd($p,0,$precision);
}

for ($i = 1; $i <= 100; $i++) {
	bcpi(10000+$i);
}
die('Unbelievable, your CPU is a monster!');

Of download hem hier als kant-en-klaar PHP bestandje (rar file)

APC cache en Zend Server CE

Als je op je Zend Server CE kijkt in de extensions lijst zoals die default ingesteld staan zou je vermoeden dan APC erop draait.

Dit blijkt echter niet geheel het geval als je de php.ini bekijkt. De versie die erop staat lijkt een soort port te zijn naar de cache engine van Zend Server zelf. Niet alle commando’s die normaal in APC beschikbaar zijn werken etc.

APC installeren
Paul Kiddie heeft op zijn weblog al redelijk goed uitgezocht hij hij dit kon doen ten behoeve van een file upload progress bar.

  • Ga naar http://downloads.php.net/pierre/
  • Zoek de juiste versie van APC caching die bij je systeem past. In mijn geval was dit php_apc-3.1.5-5.3-nts-vc9-x86.zip (APC versie 3.1.5 voor PHP 5.3, Non-Threading Safe VC9 versie)
  • Plaats php_apc.dll in je zendServer map \lib\phpext\
  • Pas je php.ini (zendServer map \etc\) aan en voeg onderin bij de extensions extension=php_apc.dll toe.
  • Restart je PHP engine en klaar

Als het goed is bevat je phpinfo nu het APC configuratie deel:

Kanttekening

Je PHP log bevat nu een warning.

[20-Nov-2010 15:31:48] PHP Warning:  Module 'apc' already loaded in Unknown on line 0

Dit heeft te maken met de “APC” zoals Zend Server die zelf laadt. Je nu toegevoegde extension botst daar licht mee. Heb wel gekeken naar de opties maar heb nog geen oplossing. De APC request die Zend Server al doet voor je eigen extensies komt mee uit een kant-en-klare extension-dll van Zend Server. Als je hem via de Zend Server configuratietool disabled gooit hij ook gelijk je zelf toegevoegde APC extensie uit de php.ini. Zet je de eigen extension regel er dan weer in dan zet hij ook gelijk die van Zend Server weer aan op één of andere manier.

Update 23 november @ 22:05

We hadden het er vandaag op kantoor nog eens over en Pieter (thnx!) kwam met een briljant idee. Hij kon zich namelijk herinneren ergens in de configs van ZendServer ook nog een file tegengekomen te zijn waarin de oorzaak mogelijk stond.

Hierbij dus alsnog de oplossing voor deze error:

In ZendServer/etc/cfg staat het bestand datacache.ini. Hierin staat:

; When enabled, the Data Cache extension registers APC compatibility methods
zend_datacache.apc_compatibility=1

Als je die parameter op 0 zet ben je er. Op zich ook een erg logische regel om op 0 te zetten als je hem zo leest.

PHP & AJAX met Jquery tutorial

Recent hadden voor een project een creatieve oplossing gemaakt om bepaalde velden in het CMS standaard te “locken” en alleen mensen met een bepaalde user-role mochten de velden unlocken en bewerken. Denk hierbij aan velden als permanames. Omdat dit meer een stukje bescherming van gebruikers dan een echte security kwestie was (in dit geval) leek het ons wel leuk dit met een eenvoudige AJAX call te doen. Met Jquery zijn dit soort opties binnen het handbereik van iedere developer gekomen.

Erover nadenkend hoe lastig dit vroeger was en hoe leuk het nu was realiseerde ik me dat het misschien voor sommige mensen nog niet zo voor de hand liggend was. Daarom deze “super recht toe recht aan” tutorial / voorbeeldcode hoe je een simpele AJAX call naar een PHP script doet vanuit je HTML en het resultaat teruggooit naar de HTML.

De HTML code












Jquery AJAX call example

Klik op een woord hieronder om het resultaat van dat woord op te halen via AJAX en terug te geven als result.

  • Appels
  • Peren
  • Bananen
  • Kersen
  • Pinguins
<< empty >>

De PHP code

$fruits = array('Appels', 'Peren', 'Bananen', 'Kersen');

if(in_array($_POST['ajaxableVar'], $fruits)){
	echo 'Eet veel ' . $_POST['ajaxableVar'] . ' dat is gezond!';
	return;
}

echo $_POST['ajaxableVar'] . ' kun je niet eten!';
return;

Ditzelfde principe kun je ook neerzetten met JSON zodat je bijvoorbeeld een boolean terug kunt geven aan je Jquery code om bepaalde acties wel / niet uit te voeren. Eigenlijk zijn de mogelijkheden redelijk ruim.

* Let op! Het voorbeeld is ZEER basic en vereist wel enige configuratie en mutaties om hem veilig te maken voor je website maar als voorbeeld van het principe dekt het de lading prima.

Download hier de bestanden als .rar

De beste software en tools voor PHP webdevelopment

Met de jaren bouw je een verzameling op met software waar je als developer prettig mee werkt. Van tools om het programmeren eenvoudiger te maken tot software om grafische zaken te doen.

Hieronder staat mijn lijst met favorites en een korte omschrijving waar ze voor dienen / wat deze software waardig maakt om in deze lijst te komen;

  • Netbeans
    Als serieus PHP developer moet je een goede IDE hebben en Netbeans is dit meer dan waardig.
    www.netbeans.org
  • MySQL workbench
    Voor het maken van gelikte database ontwerpen en deze inzichtelijk maken aan projectmanagers / opdrachtgevers.
    wb.mysql.com
  • Photoshop
    Hoort eigenlijk niet thuis in een lijst voor PHP developers maar zeker wel als webdeveloper om zo nu en dan een plaatje te snijden of een knopje te maken.
    http://www.adobe.com/nl/products/photoshop/photoshop/
  • Notepad2
    Naast Netbeans is het altijd handig een lightweight tooltje te hebben om even snel htaccess bestanden of conf files te bewerken. Ik vervang altijd zelf de notepad van windows met notepad2 zodat ik altijd syntax highlighting en regelnummers tot mijn beschikking heb.
  • http://www.flos-freeware.ch/notepad2.html
  • Filezilla
    Een goede en stabiele FTP tool.
    http://filezilla-project.org
  • Tortoise SVN
    Soms kom je er met je IDE gewoon niet goed uit als het gaat om SVN en dan is Tortoise de beste windows oplossing. Mooi is hij niet maar wel effectief.
    http://tortoisesvn.tigris.org/
  • WAMP of Zend Server
    Niets werkt zo lekker als lokaal. Snel, veilig en resultaat voor je F5 hebt kunnen drukken.
    http://www.wampserver.com/en/
    of
    http://www.zend.com/en/products/server-ce/
  • De browsers om te testen
    Test op dit moment met Safari, Firefox, Chrome, IE7, IE8, IE9 en op een Virtual PC met windows XP en IE6. Voor noodgevallen vragen we een Mac visie op zaken. Daarnaast spelen we natuurlijk wel eens met Adobe labs maar bovenstaande dekt aardig de lading.

Dit zijn wel een beetje de belangrijkste.Niet alle software mag op kantoor in productie gebruikt worden maar als ik thuis voor mezelf aan het rommelen ben mag dit vaak wel dus dan komt mijn goede ervaring daaruit voort.

Nu ik dit lijstje typ realiseer ik me dat ik ook best veel handige firefox plugins gebruik. Zal daarover binnenkort een keer iets schrijven.

http://wb.mysql.com/

Eclipse naar Netbeans

Ooit gestart in DreamWeaver om daarna, omdat het cooler en handiger was, door te gaan naar Notepad2.  Tijdens de groei van PHP/HTML scripting naar Zend Framework development groeide echter de behoefte aan betere ondersteuning voor diverse zaken. Zo begonnen we met versie controle en wilden we ook meer overzicht over de verschillende bestanden en projecten. Onze behoefte een goede Integrated Development Enviroment (IDE) te gebruiken werd groter en groter.

Eclipse PDT
De afgelopen jaren werkten we met ons hele team in Eclipse. Een geweldig programma. Solide en prettig in gebruik. Oke, we zullen niet ontkennen dat we zo nu en dan flinke ruzie hadden met subclipse (voor de versiecontrole) maar meestal was dit onze eigen fout. Het had nou eenmaal een gebruiksaanwijzing als het ging om bestanden hernoemen etc. Verder niets dan lof. Iedere keer keken we vol spanning uit naar de nieuwe versie van Eclipse. Wat voor moois zou er toch weer in zitten, zou de interface sexier zijn geworden etc?

Eclipse naar Netbeans
Het leven was zo eenvoudig, iedereen was gelukkig met Eclipse en er was geen behoefte aan een nieuwe IDE. Tot één van onze collega’s Netbeans installeerden op zijn thuisomgeving om mee te werken. Al snel was hij enthousiast genoeg om het op kantoor te durven opnemen tegen de Eclipse-fans. Niet zonder succes. Inmiddels is er nog maar één iemand bij ons op kantoor die Eclipse gebruikt. De rest is over naar Netbeans.

Waarom Netbeans?
Netbeans heeft dezelfde roots als Eclipse dus de overstap voelt niet erg zwaar aan en vanaf dat moment is het al snel genieten van alle leuke dingen die Netbeans wel goed kan / doet (of in iedere geval doet lijken alsof het goed is) zoals;

  • Instant renaming van PHP namen, classes etc
  • Nagenoeg naadloze SVN integratie
  • Frisse stijl qua schermen en icoontjes
  • Prettige bestuurbaarheid van kleurschema’s
  • Slimme code completion en controle (in zowel PHP als o.a. JS, CSS, HTML)
  • Fijne kleurcodering voor gewijzigde code tov. actuele SVN etc

Samenwerken met Eclipse en Netbeans
Dit werkt prachtig samen. Bij projecten waar we met meerdere mensen aan werken merk je er niets van. Beide zit je gewoon te werken in je gewenste editor en alle data wordt via de SVN prima op lijn gehouden zonder problemen.

Het inladen van oude Eclipse projecten (altijd mijn grootste motivatie om niet over te stappen naar een andere editor) ging eigenlijk te eenvoudig. Gewoon “new project” -> “PHP application with existing sources” en dan even paar kleine configuratiezaken en klaar. Alles inclusief de SVN configuratie. Sterker nog; beide omgevingen werken eigenlijk best goed naast elkaar (als je echt gek wilt doen)

Netbeans grootste gemis?
Wij werken redelijk veel met externe tools om bijvoorbeeld Docblocks te genereren, PHPdocumentor aan te sturen en Doctrine models te genereren. Helaas is dit alles niet mogelijk in Netbeans. Vanuit Eclipse kunnen we deze externe tools aansturen met parameters die betrekking hebben op het actuele project zodat hij automatisch de juiste mappen en namen pakt. Zo lang we hiervoor geen oplossing hebben blijft dit een beetje spijtig. (werk nu met een .bat file die wat dingen doet maar is natuurlijk lapwerk)

Heb al wel zitten kijken naar de mogelijkheden om zelf een Plugin te maken voor Netbeans maar gezien de drukte zal dat er nog even niet van komen.

Versiebeheer met Subversion

Sinds de dag dat ik kennis maakte met versiebeheer was ik verkocht. Eerder hoorde ik hier en daar wel eens developers die het gebruikten maar omdat ik zelf niet wist hoe geweldig het was miste ik niets. Tegenwoordig gebruiken we in principe voor alles versiebeheer middels Subversion (SVN). Ongeacht het formaat van het project.

Wat is versiebeheer?
In basis is dit software waarmee wijzigingen in software of documenten kunnen worden bewaard. Alle wijzigingen worden als het waren gelogd in een soort geschiedenis. Wijzigingen krijgen een uniek nummer zodat snel te zien welke mutaties bij welke versie horen. Zeker in omgevingen waar je met meerdere gebruikers aan één project werkt is versiebeheer een uitkomst. Zo kun je eenvoudig de laatste mutaties van je collega’s binnenhalen als je met een project begint en kun je de door jou gemaakte mutaties snel verspreiden onder de rest van het team. Daarnaast biedt versiebeheer je de mogelijkheid om terug te kijken in de geschiedenis. Op welk moment is iets aangepast en door wie.

Subversion
Wij gebruiken op kantoor subversion voor ons versiebeheer. Subversion is eenvoudig te koppelen vanuit Eclipse of Netbeans en werkt redelijk eenvoudig. In het kort;

  1. We maken een nieuwe SVN repository (zeg maar een plaats waar de historie van bestanden bewaard wordt) aan op onze eigen SVN server
  2. We bepalen op de server welke gebruikers er zijn en welke rechten ze hebben op dit project
  3. Daarna gaan we naar onze IDE en koppelen het project aan de aangemaakte SVN
  4. Hierna kun je lokaal bepalen welke zaken je wel niet (settings van je IDE bijvoorbeeld) in de SVN repository wilt opslaan
  5. De laatste stap is de initiële import, hierbij importeer je als het ware het project in zijn huidige staat in de repository

Vanaf dit moment heb je een werkend project met SVN koppeling. Vanaf nu zal je IDE bij alle wijzigingen in bestanden en mappen met een icoontje of kleurtje aangeven dat deze gewijzigd is ten opzichte van de laatste SVN situatie. Je kunt dan je wijzigingen toevoegen aan de repository (commit), vernieuwen volgens de actuele repository (update) of terugdraaien naar de repository status (revert).

Samen werken
Bij iedere commit kun je opmerkingen meegeven. Zo zien je collega’s gelijk wat de reden was van de update mochten ze hem binnenhalen middels een update of later terugzien in de geschiedenis van het bestand. Als je toevallig tegelijk één bestand gewijzigd hebt dan heb je een conflict. Dit is vaak eenvoudig op te lossen door beide versies met elkaar samen te voegen. Je IDE is vaak zelf perfect in staat om te kijken of de wijzigingen elkaar overlappen of dat het twee verschillende delen van de code betreft.

Nog een voordeel van versiebeheer
Wij doen ook regelmatig projecten voor grotere organisaties waarbij het belangrijk is dat mutaties aan de code genoteerd worden. Zo kun je later eenvoudig terugzoeken op welk moment een bepaalde bug bijvoorbeeld is opgelost, door wie en welke bestanden daarmee gewijzigd zijn. Bij wijzigingen kan het handig zijn omdat je bijvoorbeeld een wijziging in een tabelstructuur die meerdere bestanden omvat in één keer terug kunt draaien alsof hij nooit heeft plaatstgevonden.

Branches en tags
Het is ook mogelijk verschillende versies van een project naast elkaar te hebben. Dit doe je met branches. Als je bijvoorbeeld een nieuwe functionaliteit gaat ontwikkelen die voorlopig nog los moet staan van het hoofdproject (wat ondertussen wel doorontwikkeld wordt) maar op termijn wel samengevoegd gaat worden dan maak je een branche aan. Dit is eigenlijk gewoon een virtuele kopie van de trunk (hoofdmap van het project) waarin afwijkingen ten opzichte van de core worden bijgehouden. Op een later moment kan dan beslist worden een branche te integreren in de trunk zodat dit dus de productieversie wordt. Als een branche voorlopig niet meer actief ontwikkeld wordt noemt men deze een tag. Er is namelijk verder geen verschil tussen een branche en een tag.