Branch per Feature (Product Backlog Item) in TFS

Talvolta si ha la necessità di sviluppare le varie funzionalità di un progetto in maniera completamente separata ed avere poi la possibilità di fare il Merge di tali funzionalità in maniera indipendente nella trunk (Main)L’unica soluzione disponibile usando il Source Control Centralizzato di TFS è utilizzare una branch per ogni Feature. Questa soluzione si rende necessaria perché non è possibile effettuare il merge di changeset non contigui, per cui è necessario che ogni funzionalità venga sviluppata in una branch separata.

Questa soluzione spesso non viene adottata perché in questo modo gli sviluppatori lamentano nel proprio Hard Disk la presenza di una copia intera di tutti i sorgenti per ogni PBI o funzionalità da sviluppare. In questo scenario le branch crescono rapidamente di numero ed è poco pratico fare il Get-Latest la mattina e vedere nel proprio HD dieci copie nuove di tutti i sorgenti perché il giorno precedente è partito lo sviluppo di un nuovo sprint.

Prima di tutto è forse superfluo, ma è bene notare, che a livello di server non esiste nessuna duplicazione di sorgenti, la branch è una operazione molto leggera, e quindi avere tante branch non appesantisce il source control. A livello di macchina dello sviluppatore invece è necessario fare un uso più corretto e intelligente del concetto di workspace. Quello che si fa solitamente è usare un workspace per ogni Team Project e mappare solamente la branch su cui si sta lavorando, come potete vedere nella figura sottostante.

image

In questo caso l’utente Keller ha mappato la branch Main del progetto FabrikamFiber nella cartella c:\ws\brian\ff. Questo mapping gli permette di scaricare solamente gli aggiornamenti di quella branch durante un Get-Latest, occupare tra meno spazio sull’HD locale ed ignorare ogni modifica che viene fatta in branch differenti.

Ora supponiamo di dover iniziare a sviluppare il PBI con Id 1435, la prima operazione da effettuare è creare la nuova branch che verrà fatta in un percorso particolare $/NomeTeamProject/Pbi/ ad indicare appunto che in questa cartella si troveranno tutte le branch delle funzionalità attive.

image

Come si può vedere si sta effettuando una normale branch della Main in $/FabrikamFiber/Pbi/1435 e si è messo un commento che spiega in maniera completa il perché della sua creazione. Una volta creata, il Source Control Explorer permette di visualizzarla, ma chiaramente in grigio, perché è fuori dal percorso mappato nel workspace. In questo caso infatti l’unico percorso mappato nel proprio HD dall’utente Keller è $/FabrikamFiber/Main e quindi non è possibile accedere alla branch appena creata.

image

Se si vuole iniziare a lavorare su questa branch, è sufficiente aprire la definizione del workspace dal Source Control Explorer e procedere a cambiare il mapping affinche la stessa cartella locale punti alla nuova branch, come mostrato nella figura sottostante.

image

Quello che è stato fatto è rimappare la cartella locale c:\ws\brian\ff sulla nuova branch, in questo modo si utilizza una sola cartella locale per mappare di volta in volta la branch su cui si sta lavorando, riducendo lo spazio occupato nel proprio HD. Appena si effettua il cambiamento Visual Studio, accorgendosi che il mapping del workspace è cambiato, propone all’utente di effettuare subito un Get Latest per aggiornare la cartella locale con la nuova cartella remota del server.

image

Rispondendo yes viene effettuato un Get Latest, il quale però procede prima a cancellare tutti i vecchi file e poi riscaricare nuovamente da zero il nuovo percorso mappato. Questo si può vedere chiaramente dalla finestra di output (replacing c:\ws\brian\ff …. ) seguito da una serie di delete dei vecchi file ed un successivo get di tutti i file dal nuovo percorso.

SNAGHTML1dda55c

Questa operazione è abbastanza logica, avendo infatti rimappato interamente una cartella locale ad un differente percorso nel server il client decide di cancellare tutto il vecchio contenuto e scaricare il nuovo. Il problema è che, essendo il nuovo percorso una branch del vecchio, ci si attenderebbe un comportamento più intelligente, che è disponibile, ma solamente da riga di comando, tramite un tf get /remap

image 

Questo comando verifica se il cambiamento di mapping è stato fatto tra due branch correlate, ed in caso affermativo verifica le differenze e procede ad effettuare solo gli aggiornamenti richiesti. Come si può vedere dalla figura sopra, dato che la branch è stata appena creata ed il contenuto è identico a quello della Main, il comando non fa assolutamente nulla dato che capisce che tutti i file sono già aggoirnati e termina immediatamente. Ora si può tranquillamente aprire la solution da c:\ws\brian\ff ed iniziare a lavorare nella nuova branch creata. Per questo esempio si sono modificati due file di Controller MVC aggiungendo un semplice commento ed è stato fatto check-in, il tutto quindi nella branch $/FabrikamFiber/Pbi/1435.

Se si ha la necessità di lavorare su di un altra funzionalità, oppure tornare a sviluppare sulla main, è sufficiente modificare nuovamente il workspace, rimappando la cartella c:\ws\brian\ff sula branch desiderata ed effettuare nuovamente un tf get /remap.

Entrambe le operazioni possono tranquillamente essere fatte da riga di comando e si può pensare di automatizzarle semplicemente in un batch, ecco ad esempio i due comandi che permettono di switchare e di tornare a sviluppare nella Main Branch.

image

Come si può vedere il comando tf workfold effettua una rimappatura della cartella locale (indicata dal unto finale) ad un nuovo percorso ed il tf get /remap che segue esegue un get verificando le differenze tra la branch mappata precedentemente e la main. Dato che erano stati modificati due file, il comando cancella entrambi questi file e li scarica dalla branch correntemente mappata, il tutto in meno di un secondo. Creando un semplice file batch chiamato SwitchToPbi.bat con queste due righe di codice

[sourcecode language='bash'  padlinenumbers='true']
tf workfold $/FabrikamFiber/Pbi/%1
tf get /remap
[/sourcecode]

si può effettuare la chiamata SwitchToPbi 1435 per cambiare velocemente la branch mappata nella cartella con la branch della feature (in questo caso la 1453) su cui si vuole lavorare.

Questa soluzione è fondamentale in progetti complessi in cui la grandezza della cartella sorgenti può essere tranquillamente di qualche centinaia di MB. In questi scenari effettuare un get completo di tutti i file ogni volta che si vuole cambiare branch di lavoro, anche se il TFS è in rete locale, è sicuramente una perdita di tempo e di risorse del sistema.

Gian Maria.

5 Responses to Branch per Feature (Product Backlog Item) in TFS

  1.  
  2.  

    Articolo molto interessante

  3.  

    Scusa Gian Maria apprezzo molto il tuo sforzo nel provare a spiegare che TFS è un vero VCS ma queste soluzioni sanno molto di “arrampicarsi sugli specchi”.
    Ho utilizzato SourceSafe dal ’95, poi Mercurial poi ho provato a utilizzare TFS ma alla fine sono passato a Git.
    Il problema di TFS è che non hanno voluto allontanarsi troppo dalla logica di SourceSafe.

  4. E’ difficile comparare un centralizzato ad un distribuito, perchè hanno funzionalità molto differenti. Se parliamo di branching, git o qualsiasi distribuito ha sicuramente una marcia in più, ma non dimentichiamo che i distribuiti sono emersi solo in questi ultimi anni.

    TFS è uscito come prodotto commerciale nel 2005, il suo sviluppo quindi risale a ben prima, quando parlare di distribuito era sicuramente prematuro. Aggiungo inoltre che non tutti i team hanno la maturità per usare un distribuito come Git, che ha sicuramente molte funzionalità utilissime, ma che è abbastanza ostico da padroneggiare in maniera efficace.

    Per quanto riguarda la connessione con Source Safe, non esiste, nel senso che la struttura del Source Control di TFS è completamente differente. Quello che li rende simile è la logica di check-out e check-in, ma con il 2012 hai i workspace locali che supportano l’edit and commit come subversion. (in aggiunta ai workspace server che supportano il pattern check-in e check-out). Ti assicuro che entrambi hanno ragione di esistere, e molte delle scelte di TFS sono state prese perché è uno strumento usato prima di tutto in Microsoft, dove si hanno migliaia di sviluppatori sparsi per il mondo.

    Prova a lavorare su un disco 5.400 giri (i dischi che si avevano nel 2005) con una solution subversion (che supporta edit and commit) la cui cartella di lavoro è tipo 2 GB (progetti complessi fatti da team realmente grandi). Ricordo che fare un update richiedeva tipo 5 minuti di disco al massimo regime, affinche subversion capisse cosa ci stava di differente. Con un workspace lato server il tutto è istantaneo, perchè il server sa esattamente cosa è stato fatto. Chiaramente questo modello prevede di essere sempre connessi etc etc, però non è che è stato scelto senza cognizione di causa ;).

    Il tf get /remap è analogo ad una funzionalità di remapping di Subversion, ed è uno dei pochi modi che hai in un centralizzato di gestire molte branch efficacemente. Non rappresenta un “arrampicarsi sugli specchi”, ma una tecnica abbastanza standard e consolidata con cui un centralizzato tenta di rendere la vita più facile quando si hanno molte branch, ovvero rimappare più branch su una stessa cartella locale applicando solamente le differenze.
    Considera che questo approccio è analogo al checkout di Git, che non fa altro che riportare la stessa cartella locale ad una differente branch riapplicando i commit in maniera differenziale ;).

    Come ultima nota ti dico che oramai TFS supporta anche pienamente git in TF Service, e nella prossima versione lo avrai anche on premise. Per cui se il team ha necessità di utilizzare un distribuito puoi semplicemente scegliere git, tenendo tutto il resto di TFS. Ricordo infatti che il source control è solamente una parte di TFS, e sicuramente non la più corposa :).

    Ciao e grazie del feedback.

     
  5.  

    Ottimo, articolo davvero interessante, era proprio quello che cercavo! Grazie per lo spunto!