Skip to content

Latest commit

 

History

History
413 lines (339 loc) · 20 KB

client-tfs.asc

File metadata and controls

413 lines (339 loc) · 20 KB

Git en TFS

Git wordt steeds populairder onder Windows ontwikkelaars, en als je code schrijft op Windows, is er een grote kans dat je de Team Foundation Server (TFS) van Microsoft gebruikt. TFS is een samenwerkings pakket die een defect- en werkbonvolgsysteem bevat, procesondersteuning voor Scrum en dergelijke, code review en versiebeheer. Er gaat wat verwarring aankomen: TFS is de server, die broncode beheer ondersteunt met behulp van zowel Git als hun eigen VCS, die ze TFVC (Team Foundation Version Control) hebben gedoopt. Git ondersteuning is een nogal nieuwe mogelijkheid voor TFS (geleverd met de 2013 versie), dus alle instrumenten die van voor die datum stammen verwijzen naar het versie-beheer gedeelte als ``TFS'', zelfs als ze voor het grootste gedeelte werken met TFVC.

Als je jezelf in een team zit dat TFVC gebruikt, en je zou liever Git gebruiken als je versie-beheer client, is dit een mooi project voor jou.

Welk instrument

Er zijn er in feite twee: git-tf en git-tfs.

Git-tfs (te vinden op https://github.com/git-tfs/git-tfs) is een .NET project, en (op het tijdstip van schrijven) kan alleen onder Windows draaien. Om met Git repositories te werken, gebruikt het de .NET bindings voor libgit2, een library-oriented implementatie van Git die zeer hoog performant is en die een hoge mate van flexibiliteit biedt met de pretentie van een Git repository. Libgit2 is geen volledige implementatie van Git, dus om dit verschil te compenseren zal git-tfs gewoon de commando-regel versie van de Git client aanroepen om bepaalde operaties uit te voeren, dus er zijn geen kunstmatige beperkingen in wat het met Git repositories kan doen. De ondersteuning van de TFVC functies is zeer volwassen, omdat het de mogelijkheden van Visual Studio gebruikt voor operaties met servers. Dit houdt in dat je toegang nodig hebt tot deze mogelijkheden, wat betekent dat je een recente versie van Visual Studio moet installeren (elke editie sinds versie 2010, inclusief Express sinds versie 2012), of de Visual Studio SDK.

Git-tf (welke huist op https://gittf.codeplex.com) is een Java project, en als zodanig loopt het op elke computer met een Java runtime omgeving. Het interacteert met Git repositories middels JGit (een JVM implementatie van Git), wat inhoudt dat het vrijwel geen beperkingen kent in termen van Git functies. Echter, de ondersteuning voor TFVC is beperkt ten opzichte van git-tfs - het ondersteunt bijvoorbeeld geen branches.

Dus elke tool heeft z’n voors en tegens, en er zijn genoeg situaties waarbij de een te prefereren is boven de ander. We zullen het normale gebruik van beide gaan behandelen in dit boek.

Note

Je zult toegang nodig hebben tot een TFVC-gebaseerde repository om deze instructies mee te doen. Ze zijn niet zo ruim voorhanden als Git of Subversion repositories, dus je zult misschien je eigen moeten gaan maken. Codeplex (https://www.codeplex.com) en Visual Studio Online (https://visualstudio.microsoft.com) zijn beide goede opties hiervoor.

Beginnen met: git-tf

Het eerste wat je doet, net als met elk andere Git project is klonen. Dit is hoe het er uit ziet met git-tf:

$ git tf clone https://tfs.codeplex.com:443/tfs/TFS13 $/myproject/Main project_git

Het eerste argument is de URL van een TFVC collectie, het tweede is er een in de vorm $/project/branch, en het derde is het pad naar de lokale Git repository die gemaakt moet worden (deze laatste is optioneel). Git-tf kan maar met een branch tegelijk werken; als je checkins wilt maken op een andere TFVC branch, zul je een nieuwe kloon moeten maken van die branch.

Dit maakt een volledig functionele Git repository:

$ cd project_git
$ git log --all --oneline --decorate
512e75a (HEAD, tag: TFS_C35190, origin_tfs/tfs, master) Checkin message

Dit wordt een shallow clone (oppervlakkige kloon) genoemd, wat inhoudt dat alleen de laatste changeset is gedownload. TFVC is niet ontworpen met het het idee dat elk werkstation een volledige kopie van de historie heeft, dus git-tf valt terug op het ophalen van de laatste versie, wat veel sneller is.

Als je de tijd hebt, is het waarschijnlijk de moeite om de gehele project historie te klonen, met de --deep optie:

$ git tf clone https://tfs.codeplex.com:443/tfs/TFS13 $/myproject/Main \
  project_git --deep
Username: domain\user
Password:
Connecting to TFS...
Cloning $/myproject into /tmp/project_git: 100%, done.
Cloned 4 changesets. Cloned last changeset 35190 as d44b17a
$ cd project_git
$ git log --all --oneline --decorate
d44b17a (HEAD, tag: TFS_C35190, origin_tfs/tfs, master) Goodbye
126aa7b (tag: TFS_C35189)
8f77431 (tag: TFS_C35178) FIRST
0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \
        Team Project Creation Wizard

Merk de tags op met namen als TFS_C35189; dit is een functionaliteit die je helpt met het relateren van Git commits aan TFVC changesets. Dit is een aardige manier om het weer te geven, omdat je met een simpele log commando kunt zien welke van jouw commits zijn gerelateerd aan een snapshot die leeft in TFVC. Ze zijn niet noodzakelijk (en je kunt ze gewoon uitschakelen met git config git-tf.tag false) - git-tf houdt de echte commit-changeset relaties bij in het .git/git-tf bestand.

Beginnen met: git-tfs

Het klonen met git-tfs gedraagt zich iets anders. Neem waar:

PS> git tfs clone --with-branches \
    https://username.visualstudio.com/DefaultCollection \
    $/project/Trunk project_git
Initialized empty Git repository in C:/Users/ben/project_git/.git/
C15 = b75da1aba1ffb359d00e85c52acb261e4586b0c9
C16 = c403405f4989d73a2c3c119e79021cb2104ce44a
Tfs branches found:
- $/tfvc-test/featureA
The name of the local branch will be : featureA
C17 = d202b53f67bde32171d5078968c644e562f1c439
C18 = 44cd729d8df868a8be20438fdeeefb961958b674

Merk de --with-branches vlag op. Git-tfs is in staat de TFVC branches aan Git branches te relateren, en deze vlag geeft aan dat er een lokale Git branch moet worden aangemaakt voor elke TFVC branch. Dit wordt sterk aangeraden als je ooit gebrancht of gemerged hebt in TFS, maar het gaat niet werken met een server die ouder is dan TFS 2010 - voor die versie waren ``branches'' gewoon folders, dus git-tfs kan ze niet onderscheiden van reguliere folders.

Laten we een kijkje nemen naar de Git repository die het resultaat is:

PS> git log --oneline --graph --decorate --all
* 44cd729 (tfs/featureA, featureA) Goodbye
* d202b53 Branched from $/tfvc-test/Trunk
* c403405 (HEAD, tfs/default, master) Hello
* b75da1a New project
PS> git log -1
commit c403405f4989d73a2c3c119e79021cb2104ce44a
Author: Ben Straub <ben@straub.cc>
Date:   Fri Aug 1 03:41:59 2014 +0000

    Hello

    git-tfs-id: [https://username.visualstudio.com/DefaultCollection]$/myproject/Trunk;C16

Er zijn twee lokale branches, master en featureA, die staan voor het initiele uitgangspunt van de kloon (Trunk in TFVC) en een afgesplitste branch (featureA in TFVC). Je kunt ook zien dat de tfs `remote'' een aantal refs heeft: `default en featureA, die staan voor de TFVC branches. Git-tfs relateert de branch die je hebt gekloont aan tfs/default, en de andere krijgen hun eigen namen.

Iets anders om op te merken is de git-tfs-id: regels in de commit berichten. In plaats van tags, gebruikt git-tfs deze markeringen om een relatie te leggen tussen TFVC changesets en Git commits. Dit heeft de implicatie dat je Git commits een andere SHA-1 hash zullen hebben voor- en nadat ze naar TFVC zijn gepusht.

Git-tf[s] Workflow
Note

Onafhankelijk van de tool die je gebruikt, moet je een aantal Git configuratie instellingen inrichten om te voorkomen dat je wat problemen gaat krijgen.

$ git config set --local core.ignorecase=true
$ git config set --local core.autocrlf=false

Het meest voor de hand liggende ding wat je hierna zult wilen doen is aan het project werken. TFVC en TFS hebben een aantal kenmerken die je workflow een stuk complexer kunnen maken:

  1. Feature branches die niet voorkomen in TFVC maken het wat ingewikkelder. Dit heeft te maken met de zeer verschillende manieren waarop TFVC en Git branches weergeven.

  2. Wees erop verdacht dat TFVC gebruikers in staat stelt om files van de server uit te checken (``checkout''), en ze op slot te zetten zodat niemand anders ze kan wijzigen. Uiteraard zal dit je niet stoppen om ze in je lokale repository te wijzigen, maar dit kan je in de weg zitten als het tijd wordt om je wijzigingen naar de TFVC server te pushen.

  3. TFS kent het concept van gated'' checkins, waarbij een TFS bouw-test stap succesvol moet zijn verlopen voordat de checkin wordt toegelaten. Dit maakt gebruik van de shelve'' functie in TFVC, waar we hier niet in detail op in zullen gaan. Je kunt dit op een handmatige manier naspelen met git-tf, en git-tfs wordt geleverd met het checkintool commando die bewust is van deze gates.

In het belang van beknoptheid, zullen we hier alleen het foutloze pad volgen, die de om de meeste van deze problemen heen leidt of die ze vermijdt.

Workflow: git-tf

Stel dat je wat werk gedaan hebt, je hebt een aantal Git commits op master gemaakt, en je staat gereed om je voortgang te delen op de TFVC server. Hier is onze Git repository:

$ git log --oneline --graph --decorate --all
* 4178a82 (HEAD, master) update code
* 9df2ae3 update readme
* d44b17a (tag: TFS_C35190, origin_tfs/tfs) Goodbye
* 126aa7b (tag: TFS_C35189)
* 8f77431 (tag: TFS_C35178) FIRST
* 0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \
          Team Project Creation Wizard

We willen snapshot die in de 4178a821 commit zit nemen en die pushen naar de TFVC server. Maar laten we bij het begin beginnen: laten we eerst kijken of een van onze teamgenoten iets gedaan heeft sinds we voor het laatst verbonden waren:

$ git tf fetch
Username: domain\user
Password:
Connecting to TFS...
Fetching $/myproject at latest changeset: 100%, done.
Downloaded changeset 35320 as commit 8ef06a8. Updated FETCH_HEAD.
$ git log --oneline --graph --decorate --all
* 8ef06a8 (tag: TFS_C35320, origin_tfs/tfs) just some text
| * 4178a82 (HEAD, master) update code
| * 9df2ae3 update readme
|/
* d44b17a (tag: TFS_C35190) Goodbye
* 126aa7b (tag: TFS_C35189)
* 8f77431 (tag: TFS_C35178) FIRST
* 0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \
          Team Project Creation Wizard

Het ziet er naar uit dat er iemand ook aan het werk is, en we hebben nu een uiteengelopen historie. Dit is waar Git uitblinkt, maar we hebben een keuze uit twee verschillende manieren om door te gaan:

  1. Het maken van een merge commit voelt als een Git gebruiker als natuurlijk aan (dat is tenslotte wat git pull doet), en git-tf kan dit voor je doen met een simpele git tf pull. Wees je er echter van bewust dat TFVC zo niet in elkaar zit, en als je merge commits pusht dat je historie er aan beide kanten anders uit gaat zien, wat verwarrend kan werken. Echter, als je van plan bent om al je wijzigingen als één changeset op te sturen, is dit waarschijnlijk de eenvoudigste optie.

  2. Rebasen maakt je commit historie lineair, wat inhoudt dat we de optie hebben om elk van onze Git commits te converteren in een TFVC changeset. Omdat dit de meeste opties openhoudt, raden we je aan om het op deze manier te doen; git-tf maakt het je zelfs makkelijk met git tf pull --rebase.

De keuze is aan jou. In dit voorbeeld zullen we rebasen:

$ git rebase FETCH_HEAD
First, rewinding head to replay your work on top of it...
Applying: update readme
Applying: update code
$ git log --oneline --graph --decorate --all
* 5a0e25e (HEAD, master) update code
* 6eb3eb5 update readme
* 8ef06a8 (tag: TFS_C35320, origin_tfs/tfs) just some text
* d44b17a (tag: TFS_C35190) Goodbye
* 126aa7b (tag: TFS_C35189)
* 8f77431 (tag: TFS_C35178) FIRST
* 0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \
          Team Project Creation Wizard

Nu zijn we gereed om een checkin te doen naar de TFVC server. Git-tf geeft je de keuze om een enkele changeset te maken die alle wijzigingen sinds de laatste (--shallow, wat standaard is) en het maken van een nieuwe changeset voor elke Git commit (--deep). In dit voorbeeld zullen we één changeset maken:

$ git tf checkin -m 'Updating readme and code'
Username: domain\user
Password:
Connecting to TFS...
Checking in to $/myproject: 100%, done.
Checked commit 5a0e25e in as changeset 35348
$ git log --oneline --graph --decorate --all
* 5a0e25e (HEAD, tag: TFS_C35348, origin_tfs/tfs, master) update code
* 6eb3eb5 update readme
* 8ef06a8 (tag: TFS_C35320) just some text
* d44b17a (tag: TFS_C35190) Goodbye
* 126aa7b (tag: TFS_C35189)
* 8f77431 (tag: TFS_C35178) FIRST
* 0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \
          Team Project Creation Wizard

Er is een nieuwe TFS_C35348 tag, wat aangeeft dat TFVC exact dezelfde snapshot heeft opgeslagen als de 5a0e25e commit. Het is belangrijk om op te merken dat niet elke Git commit perse een exacte evenknie in TFVC dient te hebben; de 6eb3eb5 commit bijvoorbeeld bestaat nergens op de server.

Dat is de belangrijkste workflow. Er zijn een aantal andere overwegingen die je in je achterhoofd dient te houden:

  • Er is geen branching. Git-tf kan alleen Git repositories maken van één TFVC branch per keer.

  • Werk samen met TFVC of Git, maar niet beide. Verschillende git-tf clones van dezelfde TFVC repository kunnen verschillende SHA-1 commit-hashes hebben, wat de bron is van een niet aflatende stroom ellende.

  • Als de workflow van je team samenwerken met Git inhoudt en periodiek synchroniseren met TFVC, maak met maar één van de Git repositories verbinding met TFVC.

Workflow: git-tfs

Laten we hetzelfde scenario doorlopen waarbij we git-tfs gebruiken. Hier zijn de nieuwe commits die we gemaakt hebben op de master-branch in onze Git repository:

PS> git log --oneline --graph --all --decorate
* c3bd3ae (HEAD, master) update code
* d85e5a2 update readme
| * 44cd729 (tfs/featureA, featureA) Goodbye
| * d202b53 Branched from $/tfvc-test/Trunk
|/
* c403405 (tfs/default) Hello
* b75da1a New project

En laten we nu eens kijken of iemand anders werk gedaan heeft terwijl wij lekker aan het kloppen waren:

PS> git tfs fetch
C19 = aea74a0313de0a391940c999e51c5c15c381d91d
PS> git log --all --oneline --graph --decorate
* aea74a0 (tfs/default) update documentation
| * c3bd3ae (HEAD, master) update code
| * d85e5a2 update readme
|/
| * 44cd729 (tfs/featureA, featureA) Goodbye
| * d202b53 Branched from $/tfvc-test/Trunk
|/
* c403405 Hello
* b75da1a New project

Ja, we kunnen zien dat onze collega een nieuwe TFVC changeset heeft toegevoegd, die getoond wordt als de nieuwe aea74a0 commit, en de tfs/default remote branch is verplaatst.

Net als met git-tf, hebben we twee basis opties hoe we deze uiteengelopen histories kunnen verwerken:

  1. Rebase om een lineaire historie te behouden

  2. Mergen om te bewaren wat er daadwerkelijk gebeurd is.

In dit geval zullen we een ``deep'' checkin uitvoeren, waar elke Git commit een TFVC changeset wordt, dus we willen gaan rebasen.

PS> git rebase tfs/default
First, rewinding head to replay your work on top of it...
Applying: update readme
Applying: update code
PS> git log --all --oneline --graph --decorate
* 10a75ac (HEAD, master) update code
* 5cec4ab update readme
* aea74a0 (tfs/default) update documentation
| * 44cd729 (tfs/featureA, featureA) Goodbye
| * d202b53 Branched from $/tfvc-test/Trunk
|/
* c403405 Hello
* b75da1a New project

Nu zijn we klaar om onze bijdrage te leveren door onze code in te checken bij de TFVC server. Ze zullen hier het rcheckin command gebruiken om een TFVC changeset te maken voor elke Git commit in het pad van HEAD naar de eerste tfs remote branch die gevonden wordt (het checkin commando zou slechts één changeset maken, vergelijkbaar met het squashen van Git commits).

PS> git tfs rcheckin
Working with tfs remote: default
Fetching changes from TFS to minimize possibility of late conflict...
Starting checkin of 5cec4ab4 'update readme'
 add README.md
C20 = 71a5ddce274c19f8fdc322b4f165d93d89121017
Done with 5cec4ab4b213c354341f66c80cd650ab98dcf1ed, rebasing tail onto new TFS-commit...
Rebase done successfully.
Starting checkin of b1bf0f99 'update code'
 edit .git\tfs\default\workspace\ConsoleApplication1/ConsoleApplication1/Program.cs
C21 = ff04e7c35dfbe6a8f94e782bf5e0031cee8d103b
Done with b1bf0f9977b2d48bad611ed4a03d3738df05ea5d, rebasing tail onto new TFS-commit...
Rebase done successfully.
No more to rcheckin.
PS> git log --all --oneline --graph --decorate
* ff04e7c (HEAD, tfs/default, master) update code
* 71a5ddc update readme
* aea74a0 update documentation
| * 44cd729 (tfs/featureA, featureA) Goodbye
| * d202b53 Branched from $/tfvc-test/Trunk
|/
* c403405 Hello
* b75da1a New project

Merk op hoe na elke succesvolle checkin naar de TFVC server, git-tfs het overblijvende werk rebased op wat het zojuist heeft gedaan. Dat is omdat het git-tfs-id veld onderaan de commitberichten wordt toegevoegd, wat de SHA-1 hashes verandert. Dit is precies volgens ontwerp, en er is niets om je zorgen over te maken, maar je moet je ervan bewust zijn dat dit gebeurt, vooral als je Git commits met anderen gaat delen.

TFS heeft veel functionaliteit die integreren met zijn eigen beheer systeem, zoals werkbonnen, aangewezen reviewers, gelaagde checkins (gated checkins) en zo voorts. Het kan nogal omslachtig zijn om met deze functionaliteit te werken met alleen maar een commando-regel tool, maar gelukkig stelt git-tfs je in staat om eenvoudig een grafische checkin tool aan te roepen:

PS> git tfs checkintool
PS> git tfs ct

En dat ziet er ongeveer zo uit:

De git-tfs checkin tool.
Figure 1. De git-tfs checkin tool.

Dit ziet er vertrouwd uit voor TFS gebruikers, omdat het dezelfde dialoog is die aangeroepen wordt vanuit Visual Studio.

Git-tfs laat je ook TFVC branches beheren vanuit je Git repository. Laten we als voorbeeld er eens een maken:

PS> git tfs branch $/tfvc-test/featureBee
The name of the local branch will be : featureBee
C26 = 1d54865c397608c004a2cadce7296f5edc22a7e5
PS> git log --oneline --graph --decorate --all
* 1d54865 (tfs/featureBee) Creation branch $/myproject/featureBee
* ff04e7c (HEAD, tfs/default, master) update code
* 71a5ddc update readme
* aea74a0 update documentation
| * 44cd729 (tfs/featureA, featureA) Goodbye
| * d202b53 Branched from $/tfvc-test/Trunk
|/
* c403405 Hello
* b75da1a New project

Een branch maken in TFVC houdt het maken van een changeset in waar die branch nu in bestaat, en dit is voorgesteld als een Git commit. Merk ook op dat git-tfs de tfs/featureBee remote branch aangemaakt heeft, maar dat HEAD nog steeds naar master wijst. Als je op de nieuw aangemaakte branch wilt werken, zal je je nieuwe commits op de 1d54865 willen baseren, mogelijk door een topic branch van die commit te maken.

Git en TFS samenvatting

Git-tf en Git-tfs zijn beide geweldige instrumenten om met een TFVC server te interacteren. Ze stellen je in staat om de kracht van Git lokaal te gebruiken, te voorkomen dat je voortdurend met de centrale TFVC server contact moet leggen, en je leven als ontwikkelaar veel eenvoudiger te maken, zonder je hele team te dwingen over te stappen op Git. Als je op Windows werkt (wat waarschijnlijk is als je team TFS gebruikt), zal je waarschijnlijk git-tfs willen gebruiken, omdat deze de meest complete functionaliteit biedt, maar als je op een ander platform werkt, zal je git-tf gebruiken die beperkter is. Zoals de meeste gereedschappen in dit hoofdstuk, zal je een van deze versie-beheer systemen als leidend kiezen, en de andere in een volgende rol gebruiken - Git of TFVC moet het middelpunt van de samenwerking zijn, niet beide.