Skip to content

Latest commit

 

History

History
675 lines (556 loc) · 31.3 KB

File metadata and controls

675 lines (556 loc) · 31.3 KB

Git en Perforce

Perforce is een erg populaire versie-beheer systeem in bedrijfsomgevingen. Het bestaal al sinds 1995, wat het het oudste systeem maakt dat we in dit hoofdstuk behandelen. Zoals het is, is het ontworpen met de beperkingen van die tijd; het gaat er vanuit dat je altijd verbonden bent met een enkele centrale server, en er wordt maar één versie bewaard op je lokale schijf. Het valt niet te ontkennen dat de mogelijkheden en beperkingen goed afgestemd zijn op een aantal specifieke werksituaties, maar er zijn veel projecten die Perforce gebruiken waar Git eigenlijk veel beter zou werken.

Er zijn twee opties als je Perforce en Git samen wilt gebruiken. De eerste die we gaan behandelen is de ``Git Fusion'' bridge van de makers van Perforce, die je de subtrees van je Perforce depot ter beschikking stelt als lees-schrijf Git repositories. De tweede is git-p4, een bridge op het werkstation die je Git als een Perforce client laat werken, zonder een herconfiguratie van de Perforce server af te dwingen.

Git Fusion

Perforce stelt een product ter beschikking met de naam Git Fusion (beschikbaar op http://www.perforce.com/git-fusion), welke een Perforce server synchroniseert met Git repositories aan de kant van de server.

Inrichten

Voor onze voorbeelden, zullen we de eenvoudigste installatie methode voor Git Fusion gebruiken, en dat is het downloaden van een virtual machine die de Perforce daemon en Git Fusion draait. Je kunt deze virtual machine image krijgen op http://www.perforce.com/downloads/Perforce/20-User, en als het eenmaal gedownload is, importeer je het in je favoriete virturalisatie software (wij zullen VirtualBox gebruiken).

Als de machine voor het eerst opstart, vraag het je om het wachtwoord van de drie Linux gebuikers (root, perforce en git) te wijzigen, en een instantie naam op te geven die kan worden gebruikt om deze installatie van andere te onderscheiden op hetzelfde netwerk. Als dat alles gereed is, zal je het volgende zien:

Het Git Fusion virtual machine opstart scherm.
Figure 1. Het Git Fusion virtual machine opstart scherm.

Let even specifiek op het IP adres dat hier wordt getoond, we zullen deze later gaan gebruiken. Vervolgens maken we een Perforce gebruiker aan. Kies de `Login'' optie onder aan het scherm en druk op enter (of SSH naar de machine), en log in als `root. Gebruik deze commando’s om een gebruiker aan te maken:

$ p4 -p localhost:1666 -u super user -f john
$ p4 -p localhost:1666 -u john passwd
$ exit

Het eerste opent een VI editor om de gebruiker aan te passen, maar je kunt de standaard-instellingen accepteren door :wq te typen en enter te drukken. Het tweede zal je twee keer vragen om een wachtwoord in te typen. Dat is alles wat we hebben te doen met een shell prompt, dus beëindigen we deze sessie.

Wat je daarna moet doen om ons te volgen is Git te vertellen om geen SSL certificaten te verifiëren. Het Git Fusion image wordt met een certificaat geleverd, maar dat is voor een domain die niet zal overeenkomen met het IP adres van je virtuele machine, dus Git zal de HTTPS connectie weigeren. Als het de bedoeling is dat dit een permanente installatie gaat worden, raadpleeg dan het handboek van Perforce Git Fusion om een ander certificaat te installeren; voor het doel van ons voorbeeld zal dit voldoende zijn:

$ export GIT_SSL_NO_VERIFY=true

Nu kunnen we gaan testen of alles werkt.

$ git clone https://10.0.1.254/Talkhouse
Cloning into 'Talkhouse'...
Username for 'https://10.0.1.254': john
Password for 'https://john@10.0.1.254':
remote: Counting objects: 630, done.
remote: Compressing objects: 100% (581/581), done.
remote: Total 630 (delta 172), reused 0 (delta 0)
Receiving objects: 100% (630/630), 1.22 MiB | 0 bytes/s, done.
Resolving deltas: 100% (172/172), done.
Checking connectivity... done.

Het virtuele machine image komt met een voorinstalleerd voorbeeld project dat je kunt klonen. Hier klonen we over HTTPS, met de john gebruiker die we hierboven aangemaakt hebben; Git vraagt om de inloggegevens voor deze connectie, maar de credential cache staat ons toe om deze stap voor de hierop volgende aanvragen over te slaan.

Fusion Configuratie

Als je eenmaal Git Fusion geïnstalleerd hebt, zal je de configuratie hier en daar willen aanpassen. Dit is eigenlijk behoorlijk eenvoudig te doen met gebruik van je favoriete Perforce client; map eenvoudigweg de //.git-fusion directory op de Perforce server naar je werkruimte. De bestandsstructuur zie er als volgt uit:

$ tree
.
├── objects
│   ├── repos
│   │   └── [...]
│   └── trees
│       └── [...]

├── p4gf_config
├── repos
│   └── Talkhouse
│       └── p4gf_config
└── users
    └── p4gf_usermap

498 directories, 287 files

De objects directory wordt door Git Fusion intern gebruikt om Perforce objecten op Git te mappen en andersom, je zou niet hoeven te rommelen met de inhoud daarvan. Er is een globaal p4gf_config bestand in deze directory, zowel als een voor elke repository – dit zijn de configuratie bestanden die bepalen hoe Git Fusion zich gedraagt. Laten we het bestand in de root eens bekijken:

[repo-creation]
charset = utf8

[git-to-perforce]
change-owner = author
enable-git-branch-creation = yes
enable-swarm-reviews = yes
enable-git-merge-commits = yes
enable-git-submodules = yes
preflight-commit = none
ignore-author-permissions = no
read-permission-check = none
git-merge-avoidance-after-change-num = 12107

[perforce-to-git]
http-url = none
ssh-url = none

[@features]
imports = False
chunked-push = False
matrix2 = False
parallel-push = False

[authentication]
email-case-sensitivity = no

We zullen niet ingaan op de betekenissen van al deze vlaggen, maar merk op dat dit niet meer is dan een INI-geformatteerd tekstbestand, vergelijkbaar met wat Git gebruikt voor configuratie. Dit bestand bepaalt de globale opties, die kunnen worden overschreven door repository-specifieke configuratie bestanden, zoals repos/Talkhouse/p4gf_config. Als je dat bestand opent, zal je een [@repo] sectie zien met wat instellingen die anders zijn dan de globale standaard instellingen. Je zult ook secties zien die er zo uit zien:

[Talkhouse-master]
git-branch-name = master
view = //depot/Talkhouse/main-dev/... ...

Dit is een mapping tussen een Perforce branch en een Git branch. De sectie kan elke naam zijn die je maar kunt verzinnen, zo lang als het maar uniek is. git-branch-name stelt je in staat een depot pad die maar moeizaam zou zijn in Git te converteren naar een handigere naam. De view instelling bepaalt hoe Perforce bestanden zijn gemapt op de Git repository, waarbij de standaard view mapping syntax wordt gebruikt. Er kunnen meer dan één mapping worden opgegeven, zoals in dit voorbeeld:

[multi-project-mapping]
git-branch-name = master
view = //depot/project1/main/... project1/...
       //depot/project2/mainline/... project2/...

Op deze manier kan je, als je reguliere werkruimte mapping wijzigingen in de struktuur van de directories in zich heeft, dat met een Git repository repliceren.

Het laatste bestand dat we zullen behandelen is users/p4gv_usermap, wat Perforce gebruikers op Git gebruikers mapt, en je zult deze waarschijnlijk niet eens nodig hebben. Bij het converteren van een Perforce changeset naar een Git commit, is het standaard gedrag van Git Fusion om de Perforce gebruiker op te zoeken, en het email adres en volledige naam die daar is opgeslagen voor het auteur/committer veld van Git te gebruiken. Bij het converteren de andere kant op, is de standaard om de Perforce gebruiker op te zoeken met het email adres dat is opgeslagen in het auteur veld in de Git commit, en om de changeset op te sturen als die gebruiker (waarbij de geldende permissies worden gerespecteerd). In de meeste gevallen, zal dit gedrag prima werken, maar bekijk nu eens het volgende mapping bestand:

john john@example.com "John Doe"
john johnny@appleseed.net "John Doe"
bob employeeX@example.com "Anon X. Mouse"
joe employeeY@example.com "Anon Y. Mouse"

Elke regel is van het formaat <user> <email> "<volledige naam>", en vormt de mapping van een enkele gebruiker. De eerste twee regels mappen twee verschillende email adressen naar de naam van dezelfde Perforce gebruiker. Dit is handig als je onder verschillende email adressen Git commits hebt gemaakt (of van email adres bent veranderd), en je deze naar dezelfde Perforce gebruiker wilt mappen. Bij het maken van een Git commit van een Perforce changeset, wordt de eerste regel die met de Perforce gebruiker overeenkomt in Git gebruikt voor informatie over het auteurschap.

De laatste twee regels voorkomen dat de echte namen en email adressen van Bob en Joe in de commits terechtkomen die voor Git worden gemaakt. Dit is handig als je een intern project openbaar wilt maken, maar je niet de hele personeelsbestand aan de wereld wilt blootstellen. Merk op dat de email adressen en volledige namen uniek moeten zijn, tenzij je wilt dat alle Git commits worden toegeschreven aan een enkele virtuele auteur.

Workflow

Perforce Git Fusion is een tweewegs bridge tussen Perforce en Git versie beheer. Laten we een kijken hoe het voelt om er vanaf de Git kant mee te werken. We zullen aannemen dat de het ``Jam'' project gemapt hebben met een configuratie bestand zoals hierboven, en die we kunnen klonen als volgt:

$ git clone https://10.0.1.254/Jam
Cloning into 'Jam'...
Username for 'https://10.0.1.254': john
Password for 'https://ben@10.0.1.254':
remote: Counting objects: 2070, done.
remote: Compressing objects: 100% (1704/1704), done.
Receiving objects: 100% (2070/2070), 1.21 MiB | 0 bytes/s, done.
remote: Total 2070 (delta 1242), reused 0 (delta 0)
Resolving deltas: 100% (1242/1242), done.
Checking connectivity... done.
$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/rel2.1
$ git log --oneline --decorate --graph --all
* 0a38c33 (origin/rel2.1) Create Jam 2.1 release branch.
| * d254865 (HEAD, origin/master, origin/HEAD, master) Upgrade to latest metrowerks on Beos -- the Intel one.
| * bd2f54a Put in fix for jam's NT handle leak.
| * c0f29e7 Fix URL in a jam doc
| * cc644ac Radstone's lynx port.
[...]

De eerste keer dat je dit doet kan het eventjes duren. Wat er gebeurt is dat Git Fusion alle van toepassing zijnde changesets in de Perforce historie naar Git commits converteert. Dit gebeurt lokaal op de server, dus het is relatief snel, maar als je veel historie hebt, kan het nog steeds lang duren. Toekomstige fetches voeren incrementele conversies uit, dus zal het meer als de normale snelheid van Git aanvoelen.

Zoals je kunt zien, lijkt onze repository precies op elke andere Git repository waar je mee zou kunnen werken. Er zijn drie branches, en Git heeft heel behulpzaam een lokale master-branch gemaakt die origin/master trackt. Laten we eens wat werk doen, en een paar nieuwe commits maken:

# ...
$ git log --oneline --decorate --graph --all
* cfd46ab (HEAD, master) Add documentation for new feature
* a730d77 Whitespace
* d254865 (origin/master, origin/HEAD) Upgrade to latest metrowerks on Beos -- the Intel one.
* bd2f54a Put in fix for jam's NT handle leak.
[...]

We hebben twee nieuwe commits. Laten we nu eens controleren of iemand anders aan het werk is geweest:

$ git fetch
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://10.0.1.254/Jam
   d254865..6afeb15  master     -> origin/master
$ git log --oneline --decorate --graph --all
* 6afeb15 (origin/master, origin/HEAD) Update copyright
| * cfd46ab (HEAD, master) Add documentation for new feature
| * a730d77 Whitespace
|/
* d254865 Upgrade to latest metrowerks on Beos -- the Intel one.
* bd2f54a Put in fix for jam's NT handle leak.
[...]

Het ziet er naar uit dat dat het geval was! Je zou het met deze uitvoer niet zeggen, maar de 6afeb15 commit was in gewoon gemaakt met behulp van een Perforce client. Het ziet er net zo uit als elke andere commit wat Git betreft, en dat is nu net de bedoeling. Laten we kijken hoe de Perforce gebruiker met een merge commit omgaat:

$ git merge origin/master
Auto-merging README
Merge made by the 'recursive' strategy.
 README | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git push
Counting objects: 9, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (9/9), 917 bytes | 0 bytes/s, done.
Total 9 (delta 6), reused 0 (delta 0)
remote: Perforce: 100% (3/3) Loading commit tree into memory...
remote: Perforce: 100% (5/5) Finding child commits...
remote: Perforce: Running git fast-export...
remote: Perforce: 100% (3/3) Checking commits...
remote: Processing will continue even if connection is closed.
remote: Perforce: 100% (3/3) Copying changelists...
remote: Perforce: Submitting new Git commit objects to Perforce: 4
To https://10.0.1.254/Jam
   6afeb15..89cba2b  master -> master

Git denkt dat het gelukt is. Laten we eens kijken naar de historie van het README bestand vanuit het oogpunt van Perforce, met het revisiegraaf gereedschap p4v.

Perforce revisie graaf als resultaat van Git push.
Figure 2. Perforce revisie graaf als resultaat van Git push.

Als je dit scherm nog nooit gezien hebt, kan het er nogal verwarrend uitzien, maar het laat dezelfde concepten zien als een grafisch programma voor Git historie. We kijken naar de geschiedenis van het README bestand, dus de directory tree links boven laat alleen dat bestand zien zoals deze voorkomt in de diverse branches. Rechtsboven hebben we een grafische kijk op hoe verschillende revisies van het bestand aan elkaar zijn gerelateerd, en het hoog-overzicht van dit plaatje is rechts onder. De rest van dit scherm wordt gegeven aan de details-scherm voor de geselecteerde revisie (2 in dit geval).

Een ding om op te merken is dat de graaf er precies hetzelfde uitziet als die in de historie van Git. Perforce had geen benoemde branch om de 1 en 2 commits in op te slaan, dus heeft het een `anonymous'' branch aangemaakt in de `.git-fusion directory om deze in op te slaan. Dit zal ook gebeuren voor Git branches met een naam die niet overeenkomen met een branchnaam in Perforce (en je kunt deze later op een Perforce branch mappen met gebruik van het configuratie bestand).

Het leeuwendeel van dit alles gebeurt achter de schermen, maar het eindresultaat is dat de ene persoon in een team Git kan gebruiken, een ander kan Perforce gebruiken, en geen van beiden heeft weet van de keuze van de ander.

Git-Fusion Samenvatting

Als je toegang hebt (of kan krijgen) naar je Perforce server, is Git Fusion een hele goede manier om Git en Perforce met elkaar te laten samenwerken. Het vergt een beetje configuratie, maar de leercurve is niet heel erg steil. Dit is een van de weinige paragrafen in dit hoofdstuk waar waarschuwingen over de volledige kracht van Git niet zullen voorkomen. Dat wil niet zeggen dat Perforce erg blij gaat zijn met alles wat je er naartoe stuurt – als je probeert de geschiedenis herschrijven die al gepusht is, zal Git Fusion dit weigeren – maar Git Fusion doet erg z’n best om natuurlijk aan te voelen. Je kunt zelfs Git submodulen gebruiken (al zullen ze er voor Perforce gebruikers vreemd uitzien), en branches mergen (dit wordt aan de Perforce kant als een integratie opgeslagen).

Als je de beheerder niet kunt overtuigen om Git Fusion op te zetten, is er nog steeds een manier om deze instrumenten samen te laten werken.

Git-p4

Git-p4 is een tweewegs bridge tussen Git en Perforce. Het draait volledig binnen je Git repository, dus je hebt geen enkele vorm van toegang tot de Perforce server nodig (buiten de login gegevens natuurlijk). Git-p4 is niet zo flexibel of compleet als oplossing als Git Fusion, maar het stelt je wel in staat om het meeste wat je zou willen doen uit te voeren zonder afbreuk te doen aan de omgeving van de server.

Note

Je zult de p4 tool ergens in je PATH moeten zetten om te kunnen werken met git-p4. Op het moment van schrijven is het voor iedereen te verkrijgen op http://www.perforce.com/downloads/Perforce/20-User.

Inrichting

Voor het voorbeeld, zullen we de Perforce server van het Git Fusion OVA als boven gebruiken, maar we slaan de Git Fusion server over en gaan direct naar het versie beheer van Perforce.

Om de p4 commando-regel client te gebruiken (waar git-p4 van afhankelijk is), zal je een aantal omgevingsvariabelen moeten inrichten:

$ export P4PORT=10.0.1.254:1666
$ export P4USER=john
Op gang komen

Zoals altijd in Git, is het eerste commando het klonen:

$ git p4 clone //depot/www/live www-shallow
Importing from //depot/www/live into www-shallow
Initialized empty Git repository in /private/tmp/www-shallow/.git/
Doing initial import of //depot/www/live/ from revision #head into refs/remotes/p4/master

Dit maakt wat in Git terminologie een ``shallow'' is; alleen de allerlaatste Perforce revisie wordt in Git geïmporteerd; onthoud dat Perforce niet ontworpen is om elke revisie aan elke gebruiker te geven. Dit is genoeg om Git te laten werken als een Perforce client, maar voor andere toepassingen is dit niet genoeg.

Als dit eenmaal klaar is, hebben we een volledig werkende Git repository:

$ cd myproject
$ git log --oneline --all --graph --decorate
* 70eaf78 (HEAD, p4/master, p4/HEAD, master) Initial import of //depot/www/live/ from the state at revision #head

Merk op dat er een ``p4'' remote is voor de Perforce server, maar al het overige ziet eruit als een standaard clone. Dit is echter een beetje misleidend; er is in het echt geen remote aanwezig.

$ git remote -v

Er bestaan in deze repository helemaal geen remotes. Git-p4 heeft een aantal refs gemaakt om de staat van de server te vertegenwoordigen, en ze zien er uit als remote refs voor git log, maar ze worden niet door Git onderhouden, en je kunt er niet naar pushen.

Workflow

Okay, laten we wat werk doen. Laten we aannemen dat je wat vorderingen gemaakt hebt op een zeer belangrijke feature, en je bent klaar om het te laten zien aan de rest van je team.

$ git log --oneline --all --graph --decorate
* 018467c (HEAD, master) Change page title
* c0fb617 Update link
* 70eaf78 (p4/master, p4/HEAD) Initial import of //depot/www/live/ from the state at revision #head

We hebben twee nieuwe commits gemaakt die klaar zijn om te worden gestuurd naar de Perforce server. Laten we kijken of er iemand anders aan het werk is geweest vandaag:

$ git p4 sync
git p4 sync
Performing incremental import into refs/remotes/p4/master git branch
Depot paths: //depot/www/live/
Import destination: refs/remotes/p4/master
Importing revision 12142 (100%)
$ git log --oneline --all --graph --decorate
* 75cd059 (p4/master, p4/HEAD) Update copyright
| * 018467c (HEAD, master) Change page title
| * c0fb617 Update link
|/
* 70eaf78 Initial import of //depot/www/live/ from the state at revision #head

Het ziet er naar uit van wel, en master en p4/master zijn uiteen gelopen. Het branching systeem van Perforce lijkt in niets op die van Git, dus het aanleveren van merge commits zal nergens op slaan. Git-p4 raadt aan dat je je commits rebaset, en levert zelfs een manier om dit snel te doen:

$ git p4 rebase
Performing incremental import into refs/remotes/p4/master git branch
Depot paths: //depot/www/live/
No changes to import!
Rebasing the current branch onto remotes/p4/master
First, rewinding head to replay your work on top of it...
Applying: Update link
Applying: Change page title
 index.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Je kunt het uit de uitvoer waarschijnlijk wel afleiden, maar git p4 rebase is kort voor git p4 sync gevolgd door een git rebase p4/master. Het is iets slimmer dan dat, vooral in het geval dat je met meerdere branches werkt, maar dit is een goede benadering.

Nu is onze historie weer lineair, en we zijn klaar om onze wijzigingen te delen met Perforce. Het git p4 submit commando zal proberen om een nieuwe Perforce revisie te maken voor elke Git commit tussen p4/master en master. Als we dit aanroepen komen we in onze favoriete editor, en de inhoud van het bestand ziet er ongeveer zo uit:

# A Perforce Change Specification.
#
#  Change:      The change number. 'new' on a new changelist.
#  Date:        The date this specification was last modified.
#  Client:      The client on which the changelist was created.  Read-only.
#  User:        The user who created the changelist.
#  Status:      Either 'pending' or 'submitted'. Read-only.
#  Type:        Either 'public' or 'restricted'. Default is 'public'.
#  Description: Comments about the changelist.  Required.
#  Jobs:        What opened jobs are to be closed by this changelist.
#               You may delete jobs from this list.  (New changelists only.)
#  Files:       What opened files from the default changelist are to be added
#               to this changelist.  You may delete files from this list.
#               (New changelists only.)

Change:  new

Client:  john_bens-mbp_8487

User: john

Status:  new

Description:
   Update link

Files:
   //depot/www/live/index.html   # edit


######## git author ben@straub.cc does not match your p4 account.
######## Use option --preserve-user to modify authorship.
######## Variable git-p4.skipUserNameCheck hides this message.
######## everything below this line is just the diff #######
--- //depot/www/live/index.html  2014-08-31 18:26:05.000000000 0000
+++ /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/index.html   2014-08-31 18:26:05.000000000 0000
@@ -60,7 +60,7 @@
 </td>
 <td valign=top>
 Source and documentation for
-<a href="http://www.perforce.com/jam/jam.html">
+<a href="jam.html">
 Jam/MR</a>,
 a software build tool.
 </td>

Dit is voor een groot gedeelte dezelfde inhoud die je zou zien bij het aanroepen van p4 submit, behalve het spul aan het eind dat git-p4 behulpzaam heeft toegevoegd. Git-p4 probeert jouw Git instellingen en die van Perforce elk te volgen als het een naam moet geven voor een commit of een changeset, maar in sommige gevallen zal je het willen overschrijven. Bijvoorbeeld, als de Git commit die je aan het importeren was geschreven is door iemand die geen Perforce gebruiker account heeft, zal je nog steeds de resulterende changeset eruit willen laten zien alsof zij het geschreven hebben (en niet jij).

Git-p4 heeft het bericht van de Git commit heel behulpzaam geïmporteerd als de inhoud voor deze Perforce changeset, dus alles wat we hoeven te doen is bewaren en stoppen, twee keer (een keer voor elke commit). De uiteindelijke shell uitvoer zal er ongeveer zo uit zien:

$ git p4 submit
Perforce checkout for depot path //depot/www/live/ located at /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/
Synchronizing p4 checkout...
... - file(s) up-to-date.
Applying dbac45b Update link
//depot/www/live/index.html#4 - opened for edit
Change 12143 created with 1 open file(s).
Submitting change 12143.
Locking 1 files ...
edit //depot/www/live/index.html#5
Change 12143 submitted.
Applying 905ec6a Change page title
//depot/www/live/index.html#5 - opened for edit
Change 12144 created with 1 open file(s).
Submitting change 12144.
Locking 1 files ...
edit //depot/www/live/index.html#6
Change 12144 submitted.
All commits applied!
Performing incremental import into refs/remotes/p4/master git branch
Depot paths: //depot/www/live/
Import destination: refs/remotes/p4/master
Importing revision 12144 (100%)
Rebasing the current branch onto remotes/p4/master
First, rewinding head to replay your work on top of it...
$ git log --oneline --all --graph --decorate
* 775a46f (HEAD, p4/master, p4/HEAD, master) Change page title
* 05f1ade Update link
* 75cd059 Update copyright
* 70eaf78 Initial import of //depot/www/live/ from the state at revision #head

Het resultaat is alsof we zojuist een git push gedaan hebben, wat beste analogie is van hetgeen er in werkelijkheid is gebeurd.

Merk op dat bij dit proces elke Git commit wordt omgezet in een Perforce changeset; als je deze naar een enkele changeset wilt terugbrengen, kan je dat doen met een intereactieve rebase voordat je git p4 submit aanroept. Merk ook op dat de SHA-1 hashes van alle commits die als changesets zijn opgestuurd gewijzigd zijn; dit is omdat git-p4 een regel toevoegt aan het eind van elke commit die het converteert:

$ git log -1
commit 775a46f630d8b46535fc9983cf3ebe6b9aa53145
Author: John Doe <john@example.com>
Date:   Sun Aug 31 10:31:44 2014 -0800

    Change page title

    [git-p4: depot-paths = "//depot/www/live/": change = 12144]

Wat gebeurt er als je probeert een merge commit op te sturen? Laten we het eens proberen. Hier is de situatie waar we ons in gewerkt hebben:

$ git log --oneline --all --graph --decorate
* 3be6fd8 (HEAD, master) Correct email address
*   1dcbf21 Merge remote-tracking branch 'p4/master'
|\
| * c4689fc (p4/master, p4/HEAD) Grammar fix
* | cbacd0a Table borders: yes please
* | b4959b6 Trademark
|/
* 775a46f Change page title
* 05f1ade Update link
* 75cd059 Update copyright
* 70eaf78 Initial import of //depot/www/live/ from the state at revision #head

De Git en Perforce historie lopen uiteen na 775a46f. Aan de Git kant zijn er twee commits, daarna een merge commit met de Perforce head, en daarna een andere commit. We zullen proberen deze in te sturen bovenop een enkele changeset aan de kant van Perforce. Laten we eens kijken wat er gebeurt als we proberen deze nu in te sturen:

$ git p4 submit -n
Perforce checkout for depot path //depot/www/live/ located at /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/
Would synchronize p4 checkout in /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/
Would apply
  b4959b6 Trademark
  cbacd0a Table borders: yes please
  3be6fd8 Correct email address

De -n vlag staat voor --dry-run, wat probeert te rapporteren wat er zou gaan gebeuren als het submit commando in het echt zou worden aangeroepen. In dit geval ziet het er naar uit dat we drie Perforce changesets zouden gaan aanmaken, wat overeenkomt met de drie non-merge commits die nog niet bestaan op de Perforce server. Dat klinkt precies als wat we willen, laten we kijken hoe het uitpakt:

$ git p4 submit
[…]
$ git log --oneline --all --graph --decorate
* dadbd89 (HEAD, p4/master, p4/HEAD, master) Correct email address
* 1b79a80 Table borders: yes please
* 0097235 Trademark
* c4689fc Grammar fix
* 775a46f Change page title
* 05f1ade Update link
* 75cd059 Update copyright
* 70eaf78 Initial import of //depot/www/live/ from the state at revision #head

Onze historie werd lineair, precies alsof we hadden gerebased voor het insturen (en dat is precies wat er is gebeurd). Dit houdt in dat je zonder problemen branches kunt maken, erop werken, weggooien en mergen aan de kant van Git zonder bang te zijn dat je historie op de een of andere manier niet meer compatible is met Perforce. Als je het kunt rebasen, kan je het insturen naar een Perforce server.

Branchen

Als je Perforce project meerdere branches heeft, is niet alles voor je verloren; git-p4 kan het op een manier behandelen die je doet denken aan Git. Laten we zeggen dat je Perforce depot zo is ingericht:

//depot
  |__ project
      |__ main
      |__ dev

En stel nu dat je een dev-branch hebt, die een view spec heeft die er zo uit ziet:

//depot/project/main/... //depot/project/dev/...

Git-p4 kan deze situatie automatisch herkennen en de juiste handeling uitvoeren:

$ git p4 clone --detect-branches //depot/project@all
Importing from //depot/project@all into project
Initialized empty Git repository in /private/tmp/project/.git/
Importing revision 20 (50%)
    Importing new branch project/dev

    Resuming with change 20
Importing revision 22 (100%)
Updated branches: main dev
$ cd project; git log --oneline --all --graph --decorate
* eae77ae (HEAD, p4/master, p4/HEAD, master) main
| * 10d55fb (p4/project/dev) dev
| * a43cfae Populate //depot/project/main/... //depot/project/dev/....
|/
* 2b83451 Project init

Merk de ``@all'' specificatie in het depot pad op; dat vertelt git-p4 om niet alleen de laatste changeset voor die subtree te klonen, maar alle changesets die ooit in aanraking zijn geweest met deze paden. Dit zit dichter bij het Git-concept van een klone, maar als je aan een project werkt met een lange historie, kan dit wel even duren.

De --detect-branches vlag instrueert git-p4 om de Perforce branch specificaties te gebruiken om de branches op Git refs te mappen. Als deze mappings niet aanwezig zijn op de Perforce server (wat een heel valide manier is om Perforce te gebruiken), kan je git-p4 aangeven wat de branch mappings zijn, en je krijgt hetzelfde resultaat:

$ git init project
Initialized empty Git repository in /tmp/project/.git/
$ cd project
$ git config git-p4.branchList main:dev
$ git clone --detect-branches //depot/project@all .

Door de git-p4.branchList configuratie variabele op main:dev te zetten wordt git-p4 geïnstrueerd dat main'' en dev'' beide branches zijn, en dat de tweede een kind is van de eerste.

Als we nu git checkout -b dev p4/project/dev doen en een aantal commits maken, is git-p4 slim genoeg om de juiste branch aan te spreken als we git p4 submit uitvoeren. Jammergenoeg kan git-p4 geen 'shallow' clones en meerdere branches tegelijk aan; als je een enorm groot project hebt en je wilt aan meer dan één branch werken, zal je git p4 clone voor elke branch waarnaar je wilt submitten moeten uitvoeren.

Voor het maken of integreren van branches, zal je een Perforce client moeten gebruiken. Git-p4 kan alleen met bestaande branches synchroniseren of daarnaar submitten, en het kan dit alleen doen voor één lineaire changeset per keer. Als je twee branches in Git merget en probeert de nieuwe changeset in te sturen, is alles wat er wordt opgeslagen een stel bestandswijzigingen; de metadata over welke branches er zijn betrokken bij de integratie gaat verloren.

Git en Perforce samenvatting

Git-p4 maakt het mogelijk om een Git workflow te gebruiken met een Perforce server, en het is er best wel goed in. Echter, het is belangrijk om te onthouden dat Perforce de baas is over de broncode, en dat je Git alleen maar gebruikt om er lokaal mee te werken. Wees vooral erg voorzichtig om Git commits te delen; als je een remote hebt die andere mensen ook gebruiken, push dan geen enkele commit die niet al eerder naar die Perforce server zijn gestuurd.

Als je vrijelijk zowel de Perforce en Git clients tegelijk wilt gebruiken voor broncode beheer, en je kunt de beheerder van de server ervan overtuigen om het te installeren, zal Git Fusion Git een eersterangs versiebeheer client maken voor een Perforce server.