Git 🌙
Chapters â–Ÿ 2nd Edition

9.1 Git et les autres systĂšmes - Git comme client

Le monde n’est pas parfait. Habituellement, vous ne pouvez pas basculer immĂ©diatement sous Git tous les projets que vous pourriez rencontrer. Quelques fois, vous ĂȘtes bloquĂ© sur un projet utilisant un autre VCS et vous regrettez que ce ne soit pas Git. Dans la premiĂšre partie de ce chapitre, nous traiterons de la maniĂšre d’utiliser git comme client pour les projets utilisant un autre systĂšme.

À un moment, vous voudrez convertir votre projet Ă  Git. La seconde partie de ce chapitre traite la migration de votre projet dans Git depuis certains systĂšmes spĂ©cifiques et enfin par un script d’import personnalisĂ© pour les cas non-standards.

Git comme client

Git fournit de si bonnes sensations aux dĂ©veloppeurs que de nombreuses personnes ont cherchĂ© Ă  l’utiliser sur leur station de travail, mĂȘme si le reste de leur Ă©quipe utilise un VCS complĂštement diffĂ©rent. Il existe un certain nombre d’adaptateurs appelĂ©s « passerelles ». Nous allons en dĂ©crire certains des plus communs.

Git et Subversion

Aujourd’hui, la majoritĂ© des projets de dĂ©veloppement libre et un grand nombre de projets dans les sociĂ©tĂ©s utilisent Subversion pour gĂ©rer leur code source. Il a Ă©tĂ© le VCS libre le plus populaire depuis une bonne dĂ©cennie et a Ă©tĂ© considĂ©rĂ© comme le choix de facto pour les projets open-source. Il est aussi trĂšs similaire Ă  CVS qui a Ă©tĂ© le grand chef des gestionnaires de source avant lui.

Une des grandes fonctionnalitĂ©s de Git est sa passerelle vers Subversion, git svn. Cet outil vous permet d’utiliser Git comme un client valide d’un serveur Subversion pour que vous puissiez utiliser les capacitĂ©s de Git en local puis pousser sur le serveur Subversion comme si vous utilisiez Subversion localement. Cela signifie que vous pouvez rĂ©aliser localement les embranchements et les fusions, utiliser l’index, utiliser le rebasage et le picorage de commits, etc, tandis que vos collaborateurs continuent de travailler avec leurs mĂ©thodes ancestrales et obscures. C’est une bonne maniĂšre d’introduire Git dans un environnement professionnel et d’aider vos collĂšgues dĂ©veloppeurs Ă  devenir plus efficaces tandis que vous ferez pression pour une modification de l’infrastructure vers l’utilisation massive de Git. La passerelle Subversion n’est que la premiĂšre dose vers la drogue du monde des DVCS.

git svn

La commande de base dans Git pour toutes les commandes de passerelle est git svn. Vous préfixerez tout avec cette paire de mots. Les possibilités étant nombreuses, nous traiterons des plus communes pendant que nous détaillerons quelques petits modes de gestion.

Il est important de noter que lorsque vous utilisez git svn, vous interagissez avec Subversion qui est un systĂšme fonctionnant trĂšs diffĂ©remment de Git. Bien que vous puissiez rĂ©aliser des branches locales et les fusionner, il est gĂ©nĂ©ralement conseillĂ© de conserver votre historique le plus linĂ©aire possible en rebasant votre travail et en Ă©vitant des activitĂ©s telles qu’interagir dans le mĂȘme temps avec un dĂ©pĂŽt Git distant.

Ne rĂ©Ă©crivez pas votre historique avant d’essayer de pousser Ă  nouveau et ne poussez pas en parallĂšle dans un dĂ©pĂŽt Git pour collaborer avec vos collĂšgues dĂ©veloppant avec Git. Subversion ne supporte qu’un historique linĂ©aire et il est trĂšs facile de l’égarer. Si vous travaillez avec une Ă©quipe dont certains membres utilisent SVN et d’autres utilisent Git, assurez-vous que tout le monde n’utilise que le serveur SVN pour collaborer, cela vous rendra service.

Installation

Pour montrer cette fonctionnalitĂ©, il faut un serveur SVN sur lequel vous avez des droits en Ă©criture. Pour copier ces exemples, vous avez besoin de faire une copie inscriptible d’un dĂ©pĂŽt SVN de test accessible. Dans cette optique, vous pouvez utiliser un outil appelĂ© svnsync qui est livrĂ© avec les versions les plus rĂ©centes de Subversion — il devrait ĂȘtre distribuĂ© avec les versions Ă  partir de 1.4.

En préparation, créez un nouveau dépÎt local Subversion :

$ mkdir /tmp/test-svn
$ svnadmin create /tmp/test-svn

Ensuite, autorisez tous les utilisateurs à changer les revprops — le moyen le plus simple consiste à ajouter un script pre-revprop-change qui renvoie toujours 0 :

$ cat /tmp/test-svn/hooks/pre-revprop-change
#!/bin/sh
exit 0;
$ chmod +x /tmp/test-svn/hooks/pre-revprop-change

Vous pouvez à présent synchroniser ce projet sur votre machine locale en lançant svnsync init avec les dépÎts source et cible.

$ svnsync init file:///tmp/test-svn https://votre-serveur-svn.org/svn/

Cela initialise les propriétés nécessaires à la synchronisation. Vous pouvez ensuite cloner le code en lançant :

$ svnsync sync file:///tmp/test-svn
Committed revision 1.
Copied properties for revision 1.
Transmitting file data .............................[...]
Committed revision 2.
Copied properties for revision 2.
[
]

Bien que cette opĂ©ration ne dure que quelques minutes, si vous essayez de copier le dĂ©pĂŽt original sur un autre dĂ©pĂŽt distant au lieu d’un dĂ©pĂŽt local, le processus durera prĂšs d’une heure, en dĂ©pit du fait qu’il y a moins de 100 commits. Subversion doit cloner rĂ©vision par rĂ©vision puis pousser vers un autre dĂ©pĂŽt — c’est ridiculement inefficace mais c’est la seule possibilitĂ©.

DĂ©marrage

Avec des droits en Ă©criture sur un dĂ©pĂŽt Subversion, vous voici prĂȘt Ă  expĂ©rimenter une mĂ©thode typique. Commençons par la commande git svn clone qui importe un dĂ©pĂŽt Subversion complet dans un dĂ©pĂŽt Git local. Souvenez-vous que si vous importez depuis un dĂ©pĂŽt Subversion hĂ©bergĂ© sur Internet, il faut remplacer l’URL file://tmp/test-svn ci-dessous par l’URL de votre dĂ©pĂŽt Subversion :

$ git svn clone file:///tmp/test-svn -T trunk -b branches -t tags
Initialized empty Git repository in /private/tmp/progit/test-svn/.git/
r1 = dcbfb5891860124cc2e8cc616cded42624897125 (refs/remotes/origin/trunk)
    A	m4/acx_pthread.m4
    A	m4/stl_hash.m4
    A	java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
    A	java/src/test/java/com/google/protobuf/WireFormatTest.java


r75 = 556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae (refs/remotes/origin/trunk)
Found possible branch point: file:///tmp/test-svn/trunk => file:///tmp/test-svn/branches/my-calc-branch, 75
Found branch parent: (refs/remotes/origin/my-calc-branch) 556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae
Following parent with do_switch
Successfully followed parent
r76 = 0fb585761df569eaecd8146c71e58d70147460a2 (refs/remotes/origin/my-calc-branch)
Checked out HEAD:
  file:///tmp/test-svn/trunk r75

Cela Ă©quivaut Ă  lancer git svn init suivi de git svn fetch sur l’URL que vous avez fournie. Cela peut prendre un certain temps. Le projet de test ne contient que 75 commits et la taille du code n’est pas extraordinaire, ce qui prend juste quelques minutes. Cependant, Git doit extraire chaque version, une par une et les valider individuellement. Pour un projet contenant des centaines ou des milliers de commits, cela peut prendre littĂ©ralement des heures ou mĂȘme des jours Ă  terminer.

La partie -T trunk -b branches -t tags indique Ă  Git que ce dĂ©pĂŽt Subversion suit les conventions de base en matiĂšre d’embranchement et d’étiquetage. Si vous nommez votre trunk, vos branches ou vos Ă©tiquettes diffĂ©remment, vous pouvez modifier ces options. Comme cette organisation est la plus commune, ces options peuvent ĂȘtre simplement remplacĂ©es par -s qui signifie structure standard. La commande suivante est Ă©quivalente :

$ git svn clone file:///tmp/test-svn -s

À prĂ©sent, vous disposez d’un dĂ©pĂŽt Git valide qui a importĂ© vos branches et vos Ă©tiquettes :

$ git branch -a
* master
  remotes/origin/my-calc-branch
  remotes/origin/tags/2.0.2
  remotes/origin/tags/release-2.0.1
  remotes/origin/tags/release-2.0.2
  remotes/origin/tags/release-2.0.2rc1
  remotes/origin/trunk

Il est important de remarquer comment cet outil sous-classe vos références distantes différemment. Voyons de plus prÚs avec la commande Git de plomberie show-ref :

$ git show-ref
556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae refs/heads/master
0fb585761df569eaecd8146c71e58d70147460a2 refs/remotes/origin/my-calc-branch
bfd2d79303166789fc73af4046651a4b35c12f0b refs/remotes/origin/tags/2.0.2
285c2b2e36e467dd4d91c8e3c0c0e1750b3fe8ca refs/remotes/origin/tags/release-2.0.1
cbda99cb45d9abcb9793db1d4f70ae562a969f1e refs/remotes/origin/tags/release-2.0.2
a9f074aa89e826d6f9d30808ce5ae3ffe711feda refs/remotes/origin/tags/release-2.0.2rc1
556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae refs/remotes/origin/trunk

Git ne fait pas cela quand il clone depuis un serveur Git ; voici à quoi ressemble un dépÎt avec des étiquettes juste aprÚs le clonage :

$ git show-ref
c3dcbe8488c6240392e8a5d7553bbffcb0f94ef0 refs/remotes/origin/master
32ef1d1c7cc8c603ab78416262cc421b80a8c2df refs/remotes/origin/branch-1
75f703a3580a9b81ead89fe1138e6da858c5ba18 refs/remotes/origin/branch-2
23f8588dde934e8f33c263c6d8359b2ae095f863 refs/tags/v0.1.0
7064938bd5e7ef47bfd79a685a62c1e2649e2ce7 refs/tags/v0.2.0
6dcb09b5b57875f334f61aebed695e2e4193db5e refs/tags/v1.0.0

Git entrepose les Ă©tiquettes directement dans refs/tags, plutĂŽt que de les traiter comme des branches distantes.

Valider en retour sur le serveur Subversion

Comme vous disposez d’un dĂ©pĂŽt en Ă©tat de marche, vous pouvez commencer Ă  travailler sur le projet et pousser vos commits en utilisant efficacement Git comme client SVN. Si vous Ă©ditez un des fichiers et le validez, vous crĂ©ez un commit qui existe localement dans Git mais qui n’existe pas sur le serveur Subversion :

$ git commit -am 'Adding git-svn instructions to the README'
[master 4af61fd] Adding git-svn instructions to the README
 1 file changed, 5 insertions(+)

Ensuite, vous avez besoin de pousser vos modifications en amont. Remarquez que cela modifie la maniĂšre de travailler par rapport Ă  Subversion — vous pouvez rĂ©aliser plusieurs validations en mode dĂ©connectĂ© pour ensuite les pousser toutes en une fois sur le serveur Subversion. Pour pousser sur un serveur Subversion, il faut lancer la commande git svn dcommit :

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
    M	README.txt
Committed r77
    M	README.txt
r77 = 95e0222ba6399739834380eb10afcd73e0670bc5 (refs/remotes/origin/trunk)
No changes between 4af61fd05045e07598c553167e0f31c84fd6ffe1 and refs/remotes/origin/trunk
Resetting to the latest refs/remotes/origin/trunk

Cette commande rassemble tous les commits que vous avez validĂ©s par-dessus le code du serveur Subversion et rĂ©alise un commit sur le serveur pour chacun, puis rĂ©Ă©crit l’historique Git local pour y ajouter un identifiant unique. Cette Ă©tape est Ă  souligner car elle signifie que toutes les sommes de contrĂŽle SHA-1 de vos commits locaux ont changĂ©. C’est en partie pour cette raison que c’est une idĂ©e trĂšs pĂ©rilleuse de vouloir travailler dans le mĂȘme temps avec des serveurs Git distants. L’examen du dernier commit montre que le nouveau git-svn-id a Ă©tĂ© ajouté :

$ git log -1
commit 95e0222ba6399739834380eb10afcd73e0670bc5
Author: ben <ben@0b684db3-b064-4277-89d1-21af03df0a68>
Date:   Thu Jul 24 03:08:36 2014 +0000

    Adding git-svn instructions to the README

    git-svn-id: file:///tmp/test-svn/trunk@77 0b684db3-b064-4277-89d1-21af03df0a68

Remarquez que la somme de contrÎle SHA qui commençait par 4af61fd quand vous avez validé commence à présent par 95e0222. Si vous souhaitez pousser à la fois sur un serveur Git et un serveur Subversion, il faut obligatoirement pousser (dcommit) sur le serveur Subversion en premier, car cette action va modifier vos données des commits.

Tirer des modifications

Quand vous travaillez avec d’autres dĂ©veloppeurs, il arrive Ă  certains moments que ce qu’un dĂ©veloppeur a poussĂ© provoque un conflit lorsqu’un autre voudra pousser Ă  son tour. Cette modification sera rejetĂ©e jusqu’à ce qu’elle soit fusionnĂ©e. Dans git svn, cela ressemble Ă  ceci :

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...

ERROR from SVN:
Transaction is out of date: File '/trunk/README.txt' is out of date
W: d5837c4b461b7c0e018b49d12398769d2bfc240a and refs/remotes/origin/trunk differ, using rebase:
:100644 100644 f414c433af0fd6734428cf9d2a9fd8ba00ada145 c80b6127dd04f5fcda218730ddf3a2da4eb39138 M	README.txt
Current branch master is up to date.
ERROR: Not all changes have been committed into SVN, however the committed
ones (if any) seem to be successfully integrated into the working tree.
Please see the above messages for details.

Pour rĂ©soudre cette situation, vous pouvez lancer la commande git svn rebase qui tire depuis le serveur toute modification apparue entre temps et rebase votre travail sur le sommet de l’historique du serveur :

$ git svn rebase
Committing to file:///tmp/test-svn/trunk ...

ERROR from SVN:
Transaction is out of date: File '/trunk/README.txt' is out of date
W: eaa029d99f87c5c822c5c29039d19111ff32ef46 and refs/remotes/origin/trunk differ, using rebase:
:100644 100644 65536c6e30d263495c17d781962cfff12422693a b34372b25ccf4945fe5658fa381b075045e7702a M	README.txt
First, rewinding head to replay your work on top of it...
Applying: update foo
Using index info to reconstruct a base tree...
M	README.txt
Falling back to patching base and 3-way merge...
Auto-merging README.txt
ERROR: Not all changes have been committed into SVN, however the committed
ones (if any) seem to be successfully integrated into the working tree.
Please see the above messages for details.

À prĂ©sent, tout votre travail se trouve au-delĂ  de l’historique du serveur et vous pouvez effectivement rĂ©aliser un dcommit :

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
    M	README.txt
Committed r85
    M	README.txt
r85 = 9c29704cc0bbbed7bd58160cfb66cb9191835cd8 (refs/remotes/origin/trunk)
No changes between 5762f56732a958d6cfda681b661d2a239cc53ef5 and refs/remotes/origin/trunk
Resetting to the latest refs/remotes/origin/trunk

Il est important de se souvenir qu’à la diffĂ©rence de Git qui requiert une fusion avec les modifications distantes non prĂ©sentes localement avant de pouvoir pousser, git svn ne vous y contraint que si vos modifications provoquent un conflit (de la mĂȘme maniĂšre que svn). Si une autre personne pousse une modification Ă  un fichier et que vous poussez une modification Ă  un autre fichier, votre dcommit passera sans problĂšme :

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
    M	configure.ac
Committed r87
    M	autogen.sh
r86 = d8450bab8a77228a644b7dc0e95977ffc61adff7 (refs/remotes/origin/trunk)
    M	configure.ac
r87 = f3653ea40cb4e26b6281cec102e35dcba1fe17c4 (refs/remotes/origin/trunk)
W: a0253d06732169107aa020390d9fefd2b1d92806 and refs/remotes/origin/trunk differ, using rebase:
:100755 100755 efa5a59965fbbb5b2b0a12890f1b351bb5493c18 e757b59a9439312d80d5d43bb65d4a7d0389ed6d M	autogen.sh
First, rewinding head to replay your work on top of it...

Il faut s’en souvenir car le rĂ©sultat de ces actions est un Ă©tat du dĂ©pĂŽt qui n’existait pas sur aucun des ordinateurs quand vous avez poussĂ©. Si les modifications sont incompatibles mais ne crĂ©ent pas de conflits, vous pouvez crĂ©er des dĂ©fauts qui seront trĂšs difficiles Ă  diagnostiquer. C’est une grande diffĂ©rence avec un serveur Git — dans Git, vous pouvez tester complĂštement l’état du projet sur votre systĂšme client avant de le publier, tandis qu’avec SVN, vous ne pouvez jamais ĂȘtre totalement certain que les Ă©tats avant et aprĂšs validation sont identiques.

Vous devrez aussi lancer cette commande pour tirer les modifications depuis le serveur Subversion, mĂȘme si vous n’ĂȘtes pas encore prĂȘt Ă  valider. Vous pouvez lancer git svn fetch pour tirer les nouveaux commits, mais git svn rebase tire non seulement les commits distants mais rebase aussi vos commits locaux.

$ git svn rebase
    M	autogen.sh
r88 = c9c5f83c64bd755368784b444bc7a0216cc1e17b (refs/remotes/origin/trunk)
First, rewinding head to replay your work on top of it...
Fast-forwarded master to refs/remotes/origin/trunk.

Lancer git svn rebase de temps en temps vous assure que votre travail est toujours synchronisĂ© avec le serveur. Vous devrez cependant vous assurer que votre copie de travail est propre quand vous la lancez. Si vous avez des modifications locales, il vous faudra soit remiser votre travail, soit valider temporairement vos modifications avant de lancer git svn rebase, sinon la commande s’arrĂȘtera si elle dĂ©tecte que le rebasage provoquerait un conflit de fusion.

Le problĂšme avec les branches Git

AprĂšs vous ĂȘtre habituĂ© Ă  la maniĂšre de faire avec Git, vous souhaiterez sĂ»rement crĂ©er des branches thĂ©matiques, travailler dessus, puis les fusionner. Si vous poussez sur un serveur Subversion via git svn, vous souhaiterez Ă  chaque fois rebaser votre travail sur une branche unique au lieu de fusionner les branches ensemble. La raison principale en est que Subversion gĂšre un historique linĂ©aire et ne gĂšre pas les fusions comme Git y excelle. De ce fait, git svn suit seulement le premier parent lorsqu’il convertit les instantanĂ©s en commits Subversion.

Supposons que votre historique ressemble à ce qui suit. Vous avez créé une branche experience, avez réalisé deux validations puis les avez fusionnées dans master. Lors du dcommit, vous voyez le résultat suivant :

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
    M	CHANGES.txt
Committed r89
    M	CHANGES.txt
r89 = 89d492c884ea7c834353563d5d913c6adf933981 (refs/remotes/origin/trunk)
    M	COPYING.txt
    M	INSTALL.txt
Committed r90
    M	INSTALL.txt
    M	COPYING.txt
r90 = cb522197870e61467473391799148f6721bcf9a0 (refs/remotes/origin/trunk)
No changes between 71af502c214ba13123992338569f4669877f55fd and refs/remotes/origin/trunk
Resetting to the latest refs/remotes/origin/trunk

Lancer dcommit sur une branche avec un historique fusionnĂ© fonctionne correctement, Ă  l’exception que l’examen de l’historique du projet Git indique qu’il n’a rĂ©Ă©crit aucun des commits rĂ©alisĂ©s sur la branche experience, mais que toutes les modifications introduites apparaissent dans la version SVN de l’unique commit de fusion.

Quand quelqu’un d’autre clone ce travail, tout ce qu’il voit, c’est le commit de la fusion avec toutes les modifications injectĂ©es en une fois, comme si vous aviez lancĂ© git merge --squash. Il ne voit aucune information sur son origine ni sur sa date de validation.

Les embranchements dans Subversion

La gestion de branches dans Subversion n’a rien Ă  voir avec celle de Git. Évitez de l’utiliser autant que possible. Cependant vous pouvez crĂ©er des branches et valider dessus dans Subversion en utilisant git svn.

Créer une nouvelle branche SVN

Pour créer une nouvelle branche dans Subversion, vous pouvez utiliser la commande git svn branch [nom de la branche] :

$ git svn branch opera
Copying file:///tmp/test-svn/trunk at r90 to file:///tmp/test-svn/branches/opera...
Found possible branch point: file:///tmp/test-svn/trunk => file:///tmp/test-svn/branches/opera, 90
Found branch parent: (refs/remotes/origin/opera) cb522197870e61467473391799148f6721bcf9a0
Following parent with do_switch
Successfully followed parent
r91 = f1b64a3855d3c8dd84ee0ef10fa89d27f1584302 (refs/remotes/origin/opera)

Cela est Ă©quivalent Ă  la commande Subversion svn copy trunk branches/opera et rĂ©alise l’opĂ©ration sur le serveur Subversion. Remarquez que cette commande ne vous bascule pas sur cette branche ; si vous validez, le commit s’appliquera Ă  trunk et non Ă  la branche opera.

Basculer de branche active

Git devine la branche cible des dcommits en se rĂ©fĂ©rant au sommet des branches Subversion dans votre historique — vous ne devriez en avoir qu’un et celui-ci devrait ĂȘtre le dernier possĂ©dant un git-svn-id dans l’historique actuel de votre branche.

Si vous souhaitez travailler simultanément sur plusieurs branches, vous pouvez régler vos branches locales pour que le dcommit arrive sur une branche Subversion spécifique en les démarrant sur le commit de cette branche importée depuis Subversion. Si vous voulez une branche opera sur laquelle travailler séparément, vous pouvez lancer :

$ git branch opera remotes/origin/opera

À prĂ©sent, si vous voulez fusionner votre branche opera dans trunk (votre branche master), vous pouvez le faire en rĂ©alisant un git merge normal. Mais vous devez prĂ©ciser un message de validation descriptif (via -m), ou la fusion indiquera simplement « Merge branch opera » au lieu d’un message plus informatif.

Souvenez-vous que bien que vous utilisez git merge qui facilitera l’opĂ©ration de fusion par rapport Ă  Subversion (Git dĂ©tectera automatiquement l’ancĂȘtre commun pour la fusion), ce n’est pas un commit de fusion normal de Git. Vous devrez pousser ces donnĂ©es finalement sur le serveur Subversion qui ne sait pas tracer les commits possĂ©dant plusieurs parents. Donc, ce sera un commit unique qui englobera toutes les modifications de l’autre branche. AprĂšs avoir fusionnĂ© une branche dans une autre, il est difficile de continuer Ă  travailler sur cette branche, comme vous le feriez normalement dans Git. La commande dcommit qui a Ă©tĂ© lancĂ©e efface toute information sur la branche qui a Ă©tĂ© fusionnĂ©e, ce qui rend faux tout calcul d’antĂ©rioritĂ© pour la fusion. dcommit fait ressembler le rĂ©sultat de git merge Ă  celui de git merge --squash. Malheureusement, il n’y a pas de moyen efficace de remĂ©dier Ă  ce problĂšme — Subversion ne stocke pas cette information et vous serez toujours contraints par ses limitations si vous l’utilisez comme serveur. Pour Ă©viter ces problĂšmes, le mieux reste d’effacer la branche locale (dans notre cas, opera) dĂšs qu’elle a Ă©tĂ© fusionnĂ©e dans trunk.

Commandes Subversion

La boĂźte Ă  outil git svn fournit des commandes de nature Ă  faciliter la transition vers Git en mimant certaines commandes disponibles avec Subversion. Voici quelques commandes qui vous fournissent les mĂȘmes services que Subversion.

L’historique dans le style Subversion

Si vous ĂȘtes habituĂ© Ă  Subversion, vous pouvez lancer git svn log pour visualiser votre historique dans un format SVN :

$ git svn log
------------------------------------------------------------------------
r87 | schacon | 2014-05-02 16:07:37 -0700 (Sat, 02 May 2014) | 2 lines

autogen change

------------------------------------------------------------------------
r86 | schacon | 2014-05-02 16:00:21 -0700 (Sat, 02 May 2014) | 2 lines

Merge branch 'experiment'

------------------------------------------------------------------------
r85 | schacon | 2014-05-02 16:00:09 -0700 (Sat, 02 May 2014) | 2 lines

updated the changelog

Deux choses importantes Ă  connaĂźtre sur git svn log. PremiĂšrement, Ă  la diffĂ©rence de la vĂ©ritable commande svn log qui interroge le serveur, cette commande fonctionne hors connexion. DeuxiĂšmement, elle ne montre que les commits qui ont Ă©tĂ© effectivement remontĂ©s sur le serveur Subversion. Les commits locaux qui n’ont pas encore Ă©tĂ© remontĂ©s via dcommit n’apparaissent pas, pas plus que ceux qui auraient Ă©tĂ© poussĂ©s sur le serveur par des tiers entre-temps. Cela donne plutĂŽt le dernier Ă©tat connu des commits sur le serveur Subversion.

Annotations SVN

De la mĂȘme maniĂšre que git svn log simule une commande svn log dĂ©connectĂ©e, vous pouvez obtenir l’équivalent de svn annotate en lançant git svn blame [fichier]. Le rĂ©sultat ressemble Ă  ceci :

$ git svn blame README.txt
 2   temporal Protocol Buffers - Google's data interchange format
 2   temporal Copyright 2008 Google Inc.
 2   temporal https://code.google.com/apis/protocolbuffers/
 2   temporal
22   temporal C++ Installation - Unix
22   temporal =======================
 2   temporal
79    schacon Committing in git-svn.
78    schacon
 2   temporal To build and install the C++ Protocol Buffer runtime and the Protocol
 2   temporal Buffer compiler (protoc) execute the following:
 2   temporal

Ici aussi, tous les commits locaux dans Git ou ceux poussĂ©s sur Subversion dans l’intervalle n’apparaissent pas.

Information sur le serveur SVN

Vous pouvez aussi obtenir le mĂȘme genre d’information que celle fournie par svn info en lançant git svn info :

$ git svn info
Path: .
URL: https://schacon-test.googlecode.com/svn/trunk
Repository Root: https://schacon-test.googlecode.com/svn
Repository UUID: 4c93b258-373f-11de-be05-5f7a86268029
Revision: 87
Node Kind: directory
Schedule: normal
Last Changed Author: schacon
Last Changed Rev: 87
Last Changed Date: 2009-05-02 16:07:37 -0700 (Sat, 02 May 2009)

Comme blame et log, cette commande travaille hors connexion et n’est Ă  jour qu’à la derniĂšre date Ă  laquelle vous avez communiquĂ© avec le serveur Subversion.

Ignorer ce que Subversion ignore

Si vous clonez un dĂ©pĂŽt Subversion contenant des propriĂ©tĂ©s svn:ignore, vous souhaiterez sĂ»rement paramĂ©trer les fichiers .gitignore en correspondance pour vous Ă©viter de valider accidentellement des fichiers qui ne devraient pas l’ĂȘtre. git svn dispose de deux commandes pour le faire. La premiĂšre est git svn create-ignore qui crĂ©e automatiquement pour vous les fichiers .gitignore prĂȘts pour l’inclusion dans votre prochaine validation.

La seconde commande est git svn show-ignore qui affiche sur stdout les lignes nĂ©cessaires Ă  un fichier .gitignore qu’il suffira de rediriger dans votre fichier d’exclusion de projet :

$ git svn show-ignore > .git/info/exclude

De cette maniĂšre, vous ne parsemez pas le projet de fichiers .gitignore. C’est une option optimale si vous ĂȘtes le seul utilisateur de Git dans une Ă©quipe Subversion et que vos coĂ©quipiers ne veulent pas voir de fichiers .gitignore dans le projet.

Résumé sur Git-Svn

Les outils git svn sont utiles si vous ĂȘtes bloquĂ© avec un serveur Subversion pour le moment ou si vous devez travailler dans un environnement de dĂ©veloppement qui nĂ©cessite un serveur Subversion. Il faut cependant les considĂ©rer comme une version estropiĂ©e de Git ou vous pourriez rencontrer des problĂšmes de conversion qui vous embrouilleront vous et vos collaborateurs. Pour Ă©viter tout problĂšme, essayez de suivre les principes suivants :

  • Gardez un historique Git linĂ©aire qui ne contient pas de commits de fusion issus de git merge.

  • Rebasez tout travail rĂ©alisĂ© en dehors de la branche principale sur celle-ci ; ne la fusionnez pas.

  • Ne mettez pas en place et ne travaillez pas en parallĂšle sur un serveur Git. Si nĂ©cessaire, montez-en un pour accĂ©lĂ©rer les clones pour de nouveaux dĂ©veloppeurs mais n’y poussez rien qui n’ait dĂ©jĂ  une entrĂ©e git-svn-id. Vous devriez mĂȘme y ajouter un crochet pre-receive qui vĂ©rifie la prĂ©sence de git-svn-id dans chaque message de validation et rejette les remontĂ©es dont un des commits n’en contiendrait pas.

Si vous suivez ces principes, le travail avec un serveur Subversion peut ĂȘtre supportable. Cependant, si le basculement sur un vrai serveur Git est possible, votre Ă©quipe y gagnera beaucoup.

Git et Mercurial

L’univers des systĂšmes de gestion de version distribuĂ©s ne se limite pas Ă  Git. En fait, il existe de nombreux autres systĂšmes, chacun avec sa propre approche sur la gestion distribuĂ©e des versions. À part Git, le plus populaire est Mercurial, et ces deux-ci sont trĂšs ressemblants par de nombreux aspects.

La bonne nouvelle si vous prĂ©fĂ©rez le comportement de Git cĂŽtĂ© client mais que vous devez travailler sur un projet gĂ©rĂ© sous Mercurial, c’est que l’on peut utiliser Git avec un dĂ©pĂŽt gĂ©rĂ© sous Mercurial. Du fait que Git parle avec les dĂ©pĂŽts distants au moyen de greffons de protocole distant, il n’est pas surprenant que cette passerelle prenne la forme d’un greffon de protocole distant. Le projet s’appelle git-remote-hg et peut ĂȘtre trouvĂ© Ă  l’adresse https://github.com/felipec/git-remote-hg.

git-remote-hg

PremiÚrement, vous devez installer git-remote-hg. Cela revient simplement à copier ce fichier quelque part dans votre chemin de recherche, comme ceci :

$ curl -o ~/bin/git-remote-hg \
  https://raw.githubusercontent.com/felipec/git-remote-hg/master/git-remote-hg
$ chmod +x ~/bin/git-remote-hg


en supposant que ~/bin est prĂ©sent dans votre $PATH. git-remote-hg est aussi dĂ©pendant de la bibliothĂšque Mercurial pour Python. Si Python est dĂ©jĂ  installĂ©, c’est aussi simple que :

$ pip install mercurial

Si Python n’est pas dĂ©jĂ  installĂ©, visitez https://www.python.org/ et rĂ©cupĂ©rez-le.

La derniĂšre dĂ©pendance est le client Mercurial. Rendez-vous sur https://www.mercurial-scm.org/ et installez-le si ce n’est pas dĂ©jĂ  fait.

Maintenant, vous voilĂ  prĂȘt. Vous n’avez besoin que d’un dĂ©pĂŽt Mercurial oĂč pousser. Heureusement, tous les dĂ©pĂŽts Mercurial peuvent servir et nous allons donc simplement utiliser le dĂ©pĂŽt "hello world" dont tout le monde se sert pour apprendre Mercurial :

$ hg clone https://selenic.com/repo/hello /tmp/hello

DĂ©marrage

Avec un dĂ©pĂŽt « cĂŽtĂ© serveur » maintenant disponible, dĂ©taillons un flux de travail typique. Comme vous le verrez, ces deux systĂšmes sont suffisamment similaires pour qu’il y ait peu de friction.

Comme toujours avec Git, commençons par cloner :

$ git clone hg::/tmp/hello /tmp/hello-git
$ cd /tmp/hello-git
$ git log --oneline --graph --decorate
* ac7955c (HEAD, origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master, master) Create a makefile
* 65bb417 Create a standard "hello, world" program

Notez bien que pour travailler avec un dĂ©pĂŽt Mercurial, on utilise la commande standard git clone. C’est dĂ» au fait que git-remote-hg travaille Ă  un niveau assez bas, en utilisant un mĂ©canisme similaire Ă  celui du protocole HTTP/S de Git. Comme Git et Mercurial sont tous les deux organisĂ©s pour que chaque client rĂ©cupĂšre une copie complĂšte de l’historique du dĂ©pĂŽt, cette commande rĂ©alise rapidement un clone complet, incluant tout l’historique du projet.

La commande log montre deux commits, dont le dernier est pointĂ© par une ribambelle de refs. En fait, certaines d’entre elles n’existent par vraiment. Jetons un Ɠil Ă  ce qui est rĂ©ellement prĂ©sent dans le rĂ©pertoire .git :

$ tree .git/refs
.git/refs
├── heads
│   └── master
├── hg
│   └── origin
│       ├── bookmarks
│       │   └── master
│       └── branches
│           └── default
├── notes
│   └── hg
├── remotes
│   └── origin
│       └── HEAD
└── tags

9 directories, 5 files

Git-remote-hg essaie de rendre les choses plus idiomatiquement Git-esques, mais sous le capot, il gÚre la correspondance conceptuelle entre deux systÚmes légÚrement différents. Par exemple, le fichier refs/hg/origin/branches/default est un fichier Git de références, qui contient le SHA-1 commençant par « ac7955c », qui est le commit pointé par master. Donc le répertoire refs/hg est en quelque sorte un faux refs/remotes/origin, mais il contient la distinction entre les marque-pages et les branches.

Le fichier notes/hg est le point de départ pour comprendre comment git-remote-hg fait correspondre les empreintes des commits Git avec les IDs de modification de Mercurial. Explorons-le un peu :

$ cat notes/hg
d4c10386...

$ git cat-file -p d4c10386...
tree 1781c96...
author remote-hg <> 1408066400 -0800
committer remote-hg <> 1408066400 -0800

Notes for master

$ git ls-tree 1781c96...
100644 blob ac9117f...	65bb417...
100644 blob 485e178...	ac7955c...

$ git cat-file -p ac9117f
0a04b987be5ae354b710cefeba0e2d9de7ad41a9

Donc, refs/notes/hg pointe sur un arbre qui correspond dans la base de donnĂ©es des objets de Git Ă  une liste des autres objets avec des noms. git-ls-tree affiche le mode, le type, l’empreinte de l’objet et le nom de fichier des articles d’un arbre. Quand nous creusons un de ces articles, nous trouvons Ă  l’intĂ©rieur un blob appelĂ© « ac9117f » (l’empreinte SHA-1 du commit pointĂ© par master), avec le contenu « 0a04b98 » (qui est l’ID de la modification Mercurial au sommet de la branche default).

La bonne nouvelle est que nous n’avons quasiment pas Ă  nous soucier de tout ceci. Le mode de travail ne sera pas trĂšs diffĂ©rent de celui avec un serveur distant Git.

Il reste une chose Ă  gĂ©rer avant de passer Ă  la suite : les fichiers ignore. Mercurial et Git utilisent un mĂ©canisme trĂšs similaire pour cette fonctionnalitĂ©, mais il est trĂšs probable que vous ne souhaitez pas valider un fichier .gitignore dans un dĂ©pĂŽt Mercurial. Heureusement, Git dispose d’un moyen d’ignorer les fichiers d’un dĂ©pĂŽt local et le format Mercurial est compatible avec Git. Il suffit donc de le copier :

$ cp .hgignore .git/info/exclude

Le fichier .git/info/exclude se comporte simplement comme un fichier .gitignore, mais n’est pas inclus dans les commits.

DĂ©roulement

Supposons que nous avons travaillĂ© et validĂ© quelques commits sur la branche master et que nous sommes prĂȘts Ă  pousser ce travail sur un dĂ©pĂŽt distant. Notre dĂ©pĂŽt ressemble actuellement Ă  ceci :

$ git log --oneline --graph --decorate
* ba04a2a (HEAD, master) Update makefile
* d25d16f Goodbye
* ac7955c (origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Create a makefile
* 65bb417 Create a standard "hello, world" program

Notre branche master est en avance de deux commits par rapport Ă  origin/master, mais ces deux commits n’existent que sur notre machine locale. Voyons si quelqu’un d’autre a poussĂ© son travail dans le mĂȘme temps :

$ git fetch
From hg::/tmp/hello
   ac7955c..df85e87  master     -> origin/master
   ac7955c..df85e87  branches/default -> origin/branches/default
$ git log --oneline --graph --decorate --all
* 7b07969 (refs/notes/hg) Notes for default
* d4c1038 Notes for master
* df85e87 (origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Add some documentation
| * ba04a2a (HEAD, master) Update makefile
| * d25d16f Goodbye
|/
* ac7955c Create a makefile
* 65bb417 Create a standard "hello, world" program

Comme nous avons utilisĂ© l’option --all, nous voyons les rĂ©fĂ©rences « notes » qui sont utilisĂ©es en interne par git-remote-hg, mais nous pouvons les ignorer. Le reste Ă©tait attendu ; origin/master a avancĂ© d’un commit et notre historique a divergĂ©. À la diffĂ©rence d’autres systĂšmes que nous dĂ©crivons dans ce chapitre, Mercurial est capable de gĂ©rer les fusions, donc ce que nous allons faire n’a rien d’extraordinaire.

$ git merge origin/master
Auto-merging hello.c
Merge made by the 'recursive' strategy.
 hello.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git log --oneline --graph --decorate
*   0c64627 (HEAD, master) Merge remote-tracking branch 'origin/master'
|\
| * df85e87 (origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Add some documentation
* | ba04a2a Update makefile
* | d25d16f Goodbye
|/
* ac7955c Create a makefile
* 65bb417 Create a standard "hello, world" program

Parfait. Nous lançons les tests et tout passe, et nous voilĂ  prĂȘts Ă  partager notre travail avec l’équipe :

$ git push
To hg::/tmp/hello
   df85e87..0c64627  master -> master

C’est fini ! Si vous inspectez le dĂ©pĂŽt Mercurial, vous verrez que le rĂ©sultat se prĂ©sente comme attendu :

$ hg log -G --style compact
o    5[tip]:4,2   dc8fa4f932b8   2014-08-14 19:33 -0700   ben
|\     Merge remote-tracking branch 'origin/master'
| |
| o  4   64f27bcefc35   2014-08-14 19:27 -0700   ben
| |    Update makefile
| |
| o  3:1   4256fc29598f   2014-08-14 19:27 -0700   ben
| |    Goodbye
| |
@ |  2   7db0b4848b3c   2014-08-14 19:30 -0700   ben
|/     Add some documentation
|
o  1   82e55d328c8c   2005-08-26 01:21 -0700   mpm
|    Create a makefile
|
o  0   0a04b987be5a   2005-08-26 01:20 -0700   mpm
     Create a standard "hello, world" program

La modification numérotée 2 a été faite par Mercurial et celles numérotées 3 et 4 ont été faites par git-remote-hg, en poussant les commits réalisés avec Git.

Branches et marque-pages

Git n’a qu’un seul type de branche : une rĂ©fĂ©rence qui se dĂ©place quand des commits sont ajoutĂ©s. Dans Mercurial, ce type de rĂ©fĂ©rence est appelĂ© « marque-page » et se comporte de la mĂȘme maniĂšre qu’une branche Git.

Le concept de « branche » dans Mercurial est plus contraignant. La branche sur laquelle une modification est rĂ©alisĂ©e est enregistrĂ©e avec la modification, ce qui signifie que cette derniĂšre sera toujours prĂ©sente dans l’historique du dĂ©pĂŽt. Voici un exemple d’un commit ajoutĂ© Ă  la branche develop :

$ hg log -l 1
changeset:   6:8f65e5e02793
branch:      develop
tag:         tip
user:        Ben Straub <ben@straub.cc>
date:        Thu Aug 14 20:06:38 2014 -0700
summary:     More documentation

Notez la ligne qui commence par « branch ». Git ne peut pas vraiment rĂ©pliquer ce comportement (il n’en a pas besoin ; les deux types de branches peuvent ĂȘtre reprĂ©sentĂ©s par une ref Git), mais git-remote-hg a besoin de comprendre cette diffĂ©rence, puisque qu’elle a du sens pour Mercurial.

La création de marque-pages Mercurial est aussi simple que la création de branches Git. Du cÎté Git :

$ git checkout -b featureA
Switched to a new branch 'featureA'
$ git push origin featureA
To hg::/tmp/hello
 * [new branch]      featureA -> featureA

C’est tout ce qui est nĂ©cessaire. Du cĂŽtĂ© Mercurial, cela ressemble Ă  ceci :

$ hg bookmarks
   featureA                  5:bd5ac26f11f9
$ hg log --style compact -G
@  6[tip]   8f65e5e02793   2014-08-14 20:06 -0700   ben
|    More documentation
|
o    5[featureA]:4,2   bd5ac26f11f9   2014-08-14 20:02 -0700   ben
|\     Merge remote-tracking branch 'origin/master'
| |
| o  4   0434aaa6b91f   2014-08-14 20:01 -0700   ben
| |    update makefile
| |
| o  3:1   318914536c86   2014-08-14 20:00 -0700   ben
| |    goodbye
| |
o |  2   f098c7f45c4f   2014-08-14 20:01 -0700   ben
|/     Add some documentation
|
o  1   82e55d328c8c   2005-08-26 01:21 -0700   mpm
|    Create a makefile
|
o  0   0a04b987be5a   2005-08-26 01:20 -0700   mpm
     Create a standard "hello, world" program

Remarquez la nouvelle Ă©tiquette [featureA] sur la rĂ©vision 5. Elle se comporte exactement comme une branche Git du cĂŽtĂ© Git, avec une exception : vous ne pouvez pas effacer un marque-page depuis le cĂŽtĂ© Git (c’est une limitation des greffons de gestion distante).

Vous pouvez travailler aussi sur une branche « lourde » Mercurial : placez une branche dans l’espace de nom branches :

$ git checkout -b branches/permanent
Switched to a new branch 'branches/permanent'
$ vi Makefile
$ git commit -am 'A permanent change'
$ git push origin branches/permanent
To hg::/tmp/hello
 * [new branch]      branches/permanent -> branches/permanent

Voici à quoi ça ressemble du cÎté Mercurial :

$ hg branches
permanent                      7:a4529d07aad4
develop                        6:8f65e5e02793
default                        5:bd5ac26f11f9 (inactive)
$ hg log -G
o  changeset:   7:a4529d07aad4
|  branch:      permanent
|  tag:         tip
|  parent:      5:bd5ac26f11f9
|  user:        Ben Straub <ben@straub.cc>
|  date:        Thu Aug 14 20:21:09 2014 -0700
|  summary:     A permanent change
|
| @  changeset:   6:8f65e5e02793
|/   branch:      develop
|    user:        Ben Straub <ben@straub.cc>
|    date:        Thu Aug 14 20:06:38 2014 -0700
|    summary:     More documentation
|
o    changeset:   5:bd5ac26f11f9
|\   bookmark:    featureA
| |  parent:      4:0434aaa6b91f
| |  parent:      2:f098c7f45c4f
| |  user:        Ben Straub <ben@straub.cc>
| |  date:        Thu Aug 14 20:02:21 2014 -0700
| |  summary:     Merge remote-tracking branch 'origin/master'
[...]

Le nom de branche « permanent » a été enregistré avec la modification marquée 7.

Du cĂŽtĂ© Git, travailler avec les deux styles de branches revient au mĂȘme : employez les commandes checkout, commit, fetch, merge, pull et push comme vous feriez normalement. Une chose Ă  savoir cependant est que Mercurial ne supporte pas la rĂ©Ă©criture de l’historique mais seulement les ajouts. Voici Ă  quoi ressemble le dĂ©pĂŽt Mercurial aprĂšs un rebasage interactif et une poussĂ©e forcĂ©e :

$ hg log --style compact -G
o  10[tip]   99611176cbc9   2014-08-14 20:21 -0700   ben
|    A permanent change
|
o  9   f23e12f939c3   2014-08-14 20:01 -0700   ben
|    Add some documentation
|
o  8:1   c16971d33922   2014-08-14 20:00 -0700   ben
|    goodbye
|
| o  7:5   a4529d07aad4   2014-08-14 20:21 -0700   ben
| |    A permanent change
| |
| | @  6   8f65e5e02793   2014-08-14 20:06 -0700   ben
| |/     More documentation
| |
| o    5[featureA]:4,2   bd5ac26f11f9   2014-08-14 20:02 -0700   ben
| |\     Merge remote-tracking branch 'origin/master'
| | |
| | o  4   0434aaa6b91f   2014-08-14 20:01 -0700   ben
| | |    update makefile
| | |
+---o  3:1   318914536c86   2014-08-14 20:00 -0700   ben
| |      goodbye
| |
| o  2   f098c7f45c4f   2014-08-14 20:01 -0700   ben
|/     Add some documentation
|
o  1   82e55d328c8c   2005-08-26 01:21 -0700   mpm
|    Create a makefile
|
o  0   0a04b987be5a   2005-08-26 01:20 -0700   mpm
     Create a standard "hello, world" program

Les modifications 8, 9 et 10 ont Ă©tĂ© crĂ©Ă©es et appartiennent Ă  la branche permanent mais les anciennes modifications sont toujours prĂ©sentes. Ça a toutes les chances de perdre vos collĂšgues qui utilisent Mercurial, donc c’est Ă  Ă©viter Ă  tout prix.

Résumé Mercurial

Git et Mercurial sont suffisamment similaires pour que le travail pendulaire entre les deux se passe sans accroc. Si vous Ă©vitez de modifier l’historique qui a dĂ©jĂ  quittĂ© votre machine (comme il l’est recommandĂ©), vous pouvez tout simplement ignorer que le dĂ©pĂŽt distant fonctionne avec Mercurial.

Git et Perforce

Perforce est un systĂšme de version trĂšs populaire dans les environnements professionnels. Il existe depuis 1995, ce qui en fait le systĂšme le plus ancien abordĂ© dans ce chapitre. Avec cette information en tĂȘte, il apparaĂźt construit avec les contraintes de cette Ă©poque ; il considĂšre que vous ĂȘtes toujours connectĂ© Ă  un serveur central et une seule version est conservĂ©e sur le disque dur local. C’est certain, ses fonctionnalitĂ©s et ses contraintes correspondent Ă  quelques problĂšmes spĂ©cifiques, mais de nombreux projets utilisent Perforce lĂ  oĂč Git fonctionnerait rĂ©ellement mieux.

Il y a deux options pour mĂ©langer l’utilisation de Perforce et de Git. La premiĂšre que nous traiterons est le pont « Git Fusion » crĂ©Ă© par les dĂ©veloppeurs de Perforce, qui vous permet d’exposer en lecture-Ă©criture des sous-arbres de votre dĂ©pĂŽt Perforce en tant que dĂ©pĂŽts Git. La seconde s’appelle git-p4, un pont cĂŽtĂ© client qui permet d’utiliser Git comme un client Perforce, sans besoin de reconfigurer le serveur Perforce.

Git Fusion

Perforce fournit un produit appelé Git Fusion (disponible sur https://www.perforce.com/git-fusion), qui synchronise un serveur Perforce avec des dépÎts Git du cÎté serveur.

Installation

Pour nos exemples, nous utiliserons la mĂ©thode d’installation de Git Fusion la plus facile qui consiste Ă  tĂ©lĂ©charger une machine virtuelle qui embarque le daemon Perforce et Git Fusion. Vous pouvez obtenir la machine virtuelle depuis https://www.perforce.com/downloads/Perforce/20-User, et une fois tĂ©lĂ©chargĂ©e, importez-la dans votre logiciel favori de virtualisation (nous utiliserons VirtualBox).

Au premier lancement de la machine, il vous sera demandĂ© de personnaliser quelques mots de passe pour trois utilisateurs Linux (root, perforce et git), et de fournir un nom d’instance qui peut ĂȘtre utilisĂ© pour distinguer cette installation des autres sur le mĂȘme rĂ©seau. Quand tout est terminĂ©, vous verrez ceci :

L’écran de dĂ©marrage de la machine virtuelle Git Fusion.
Figure 145. L’écran de dĂ©marrage de la machine virtuelle Git Fusion.

Prenez note de l’adresse IP qui est indiquĂ©e ici, car nous en aurons besoin plus tard. Ensuite, nous allons crĂ©er l’utilisateur Perforce. SĂ©lectionnez l’option « Login » en bas de l’écran et appuyez sur EntrĂ©e (ou connectez-vous en SSH Ă  la machine), puis identifiez-vous comme root. Ensuite, utilisez ces commandes pour crĂ©er un utilisateur :

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

La premiĂšre commande va ouvrir un Ă©diteur VI pour personnaliser l’utilisateur, mais vous pouvez accepter les valeurs par dĂ©faut en tapant :wq et en appuyant sur EntrĂ©e. La seconde vous demandera d’entrer le mot de passe deux fois. C’est tout ce qu’il faut faire depuis une invite de commande, et on peut quitter la session.

L’action suivante consiste Ă  indiquer Ă  Git de ne pas vĂ©rifier les certificats SSL. L’image Git Fusion contient un certificat, mais celui-ci ne correspond pas au domaine de l’adresse IP de votre machine virtuelle, donc Git va rejeter la connexion HTTPS. Pour une installation permanente, consultez le manuel Perforce Git Fusion pour installer un certificat diffĂ©rent ; pour l’objet de notre exemple, ceci suffira :

$ export GIT_SSL_NO_VERIFY=true

Maintenant, nous pouvons tester que tout fonctionne correctement.

$ 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.

La machine virtuelle contient un projet exemple que vous pouvez cloner. Ici, nous clonons via HTTPS, avec l’utilisateur john que nous avons crĂ©Ă© auparavant ; Git demande le mot de passe pour cette connexion, mais le cache d’identifiant permettra de sauter cette Ă©tape par la suite.

Configuration de Fusion

Une fois que Git Fusion est installĂ©, vous dĂ©sirerez sĂ»rement modifier la configuration. C’est assez facile Ă  faire via votre client Perforce favori ; rapatriez simplement le rĂ©pertoire //.git-fusion du serveur Perforce dans votre espace de travail. La structure du fichier ressemble Ă  ceci :

$ tree
.
├── objects
│   ├── repos
│   │   └── [...]
│   └── trees
│       └── [...]
│
├── p4gf_config
├── repos
│   └── Talkhouse
│       └── p4gf_config
└── users
    └── p4gf_usermap

498 directories, 287 files

Le rĂ©pertoire objects est utilisĂ© en interne par Git Fusion pour faire correspondre les objets Perforce avec Git et vice versa et il n’y a pas lieu d’y toucher. Il y a un fichier p4gf_config global dans ce rĂ©pertoire, ainsi qu’un fichier pour chaque dĂ©pĂŽt. Ce sont les fichiers de configuration qui dĂ©terminent comment Git Fusion se comporte. Examinons le fichier Ă  la racine :

[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

Nous ne nous Ă©tendrons pas sur les significations des diffĂ©rents paramĂštres, mais on voit que c’est un simple fichier INI, du mĂȘme style que ceux utilisĂ©s par Git. Ce fichier spĂ©cifie les options globales, qui peuvent ĂȘtre surchargĂ©es par chaque fichier de configuration spĂ©cifique Ă  un dĂ©pĂŽt, tel que repos/Talkhouse/p4gf_config. Si vous ouvrez ce fichier, vous verrez une section [@repo] contenant des paramĂ©trages diffĂ©rents des paramĂštres globaux par dĂ©faut. Vous verrez aussi des sections ressemblant Ă  ceci :

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

C’est la correspondance entre une branche Perforce et une branche Git. Le nom de la section est libre, du moment qu’il est unique. git-branch-name vous permet de convertir un chemin du dĂ©pĂŽt qui serait encombrant sous Git en quelque chose de plus utilisable. L’entrĂ©e view contrĂŽle comment les fichiers Perforce sont transformĂ©s en dĂ©pĂŽts Git, en utilisant la syntaxe standard de description de vue. Des correspondances multiples peuvent ĂȘtre indiquĂ©es, comme dans cet exemple :

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

De cette maniĂšre, si votre montage d’espace de travail normal change de structure de rĂ©pertoires, vous pouvez rĂ©pliquer cette modification dans le dĂ©pĂŽt Git.

Le dernier fichier que nous examinerons est users/p4gf_usermap, qui fait correspondre les utilisateurs Perforce avec les utilisateurs Git, et qui n’est mĂȘme pas nĂ©cessaire. Quand une modification Perforce est convertie en commit Git, le comportement par dĂ©faut de Git Fusion consiste Ă  rechercher l’utilisateur Perforce et Ă  utiliser son adresse de courriel et son nom complet comme champs d’auteur/validateur dans Git. Dans l’autre sens, le comportement par dĂ©faut consiste Ă  rechercher l’utilisateur Perforce correspondant Ă  l’adresse de courriel stockĂ©e dans le champ auteur du commit Git et de soumettre une modification avec cet identifiant (si les permissions l’accordent). Dans la plupart des cas, ce comportement suffira, mais considĂ©rons tout de mĂȘme le fichier de correspondance suivant :

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"

Chaque ligne est de la forme <utilisateur> <courriel> <nom complet> et crĂ©e une correspondance unique. Les deux premiĂšres lignes font correspondre deux adresses de courriel distinctes avec le mĂȘme utilisateur Perforce. C’est utile si vous avez crĂ©Ă© des commits Git sous plusieurs adresses de courriel (ou modifiĂ© votre adresse de courriel), mais que vous voulez les faire correspondre au mĂȘme utilisateur Perforce. À la crĂ©ation d’un commit Git depuis une modification Perforce, la premiĂšre ligne correspondant Ă  l’utilisateur Perforce est utilisĂ©e pour fournir l’information d’auteur Ă  Git.

Les deux derniĂšres lignes masquent les noms rĂ©els de Bob et Joe dans les commits Git crĂ©Ă©s. C’est trĂšs utile si vous souhaitez ouvrir les sources d’un projet interne, mais que vous ne souhaitez pas rendre public le rĂ©pertoire de vos employĂ©s. Notez que les adresses de courriel et les noms complets devraient ĂȘtre uniques, Ă  moins que vous ne souhaitiez publier tous les commits Git avec un auteur unique fictif.

Utilisation

Perforce Git Fusion est une passerelle à double-sens entre les contrÎles de version Perforce et Git. Voyons comment cela se passe du cÎté Git. Nous supposerons que nous avons monté le projet « Jam » en utilisant le fichier de configuration ci-dessus, et que nous pouvons le cloner comme ceci :

$ 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.
[...]

La premiĂšre fois que vous le faites, cela peut durer un certain temps. Ce qui se passe, c’est que Git Fusion convertit toutes les modifications concernĂ©es de l’historique Perforce en commits Git. Cela se passe localement sur le serveur, donc c’est plutĂŽt rapide, mais si votre historique est long, ce n’est pas immĂ©diat. Les rĂ©cupĂ©rations subsĂ©quentes ne lancent que des conversions incrĂ©mentales, ce qui devrait correspondre Ă  la vitesse native de Git.

Comme vous pouvez le voir, notre dépÎt ressemble complÚtement à un autre dépÎt Git. Il y a trois branches et Git a utilement créé une branche master locale qui suit la branche origin/master. Travaillons un peu et créons une paire de commits :

# ...
$ 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.
[...]

Nous avons deux nouveaux commits. Maintenant, vĂ©rifions si quelqu’un d’autre a aussi travaillé :

$ 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.
[...]

Il semble bien ! Ça n’apparaĂźt pas sur cette vue, mais le commit 6afeb15 a en fait Ă©tĂ© crĂ©Ă© en utilisant un client Perforce. Il ressemble juste Ă  un commit normal du point de vue de Git, ce qui est exactement l’effet recherchĂ©. Voyons comment le serveur Perforce gĂšre le commit de fusion :

$ 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 pense que ça a marchĂ©. Voyons l’historique du fichier README du point de vue de Perforce, en utilisant la fonctionnalitĂ© de graphe de rĂ©vision de p4v :

Graphe de rĂ©vision de Perforce rĂ©sultant d’une poussĂ©e depuis Git.
Figure 146. Graphe de rĂ©vision de Perforce rĂ©sultant d’une poussĂ©e depuis Git.

Si vous n’avez jamais vu ceci auparavant, cela peut dĂ©router, mais c’est une vue similaire Ă  la vue graphique de l’historique Git. Nous visualisons l’historique du fichier README, donc l’arbre de rĂ©pertoire en haut Ă  gauche ne montre que ce fichier, aux endroits oĂč il apparaĂźt dans diffĂ©rentes branches. En haut Ă  droite, nous avons le graphe visuel des relations entre les diffĂ©rentes rĂ©visions du fichier et la vue en grand du graphe en bas Ă  droite. Le reste de l’écran concerne la visualisation des dĂ©tails pour la rĂ©vision sĂ©lectionnĂ©e (2 dans ce cas).

Une chose Ă  noter est que le graphe ressemble exactement Ă  celui de l’historique Git. Perforce n’avait pas de branche nommĂ©e pour stocker les commits 1 et 2, il a donc crĂ©Ă© une branche « anonymous » dans le rĂ©pertoire .git-fusion pour la gĂ©rer. Cela arrivera aussi pour des branches Git nommĂ©es qui ne correspondent pas Ă  une branche Perforce nommĂ©e (et que vous pouvez plus tard faire correspondre Ă  une branche Perforce en utilisant le fichier de configuration).

Tout ceci se passe en coulisse, mais le rĂ©sultat final est qu’une personne dans l’équipe peut utiliser Git, une autre Perforce et aucune des deux n’a Ă  se soucier du choix de l’autre.

Résumé Git-Fusion

Si vous avez accĂšs (ou pouvez avoir accĂšs) Ă  un votre serveur Perforce, Git Fusion est un excellent moyen de faire parler Git et Perforce ensemble. Cela nĂ©cessite un peu de configuration, mais la courbe d’apprentissage n’est pas trĂšs raide. C’est une des rares sections de ce chapitre oĂč il est inutile de faire spĂ©cifiquement attention Ă  ne pas utiliser toute la puissance de Git. Cela ne signifie pas que Perforce sera ravi de tout ce que vous lui enverrez — si vous rĂ©Ă©crivez l’historique qui a dĂ©jĂ  Ă©tĂ© poussĂ©, Git Fusion va le rejeter — Git Fusion cherche vraiment Ă  sembler naturel. Vous pouvez mĂȘme utiliser les sous-modules Git (bien qu’ils paraĂźtront Ă©tranges pour les utilisateurs Perforce), et fusionner les branches (ce qui sera enregistrĂ© comme une intĂ©gration du cĂŽtĂ© Perforce).

Si vous ne pouvez pas convaincre un administrateur de votre serveur d’installer Git Fusion, il existe encore un moyen d’utiliser ces outils ensemble.

Git-p4

Git-p4 est une passerelle Ă  double sens entre Git et Perforce. Il fonctionne intĂ©gralement au sein de votre dĂ©pĂŽt Git, donc vous n’avez besoin d’aucun accĂšs au serveur Perforce (autre que les autorisations d’utilisateur, bien sĂ»r). Git-p4 n’est pas une solution aussi flexible ou complĂšte que Git Fusion, mais il permet tout de mĂȘme de rĂ©aliser la plupart des activitĂ©s sans ĂȘtre invasif dans l’environnement serveur.

Note

Vous aurez besoin de l’outil p4 dans votre de chemin de recherche pour travailler avec git-p4. À la date d’écriture du livre, il est disponible Ă  https://www.perforce.com/downloads/Perforce/20-User.

Installation

Pour l’exemple, nous allons lancer le serveur Perforce depuis l’image Git Fusion, comme indiquĂ© ci-dessus, mais nous n’utiliserons pas le serveur Git Fusion et nous dialoguerons avec la gestion de version Perforce directement.

Pour utiliser le client p4 en ligne de commande (dont git-p4 dĂ©pend), vous devrez dĂ©finir quelques variables d’environnement :

$ export P4PORT=10.0.1.254:1666
$ export P4USER=john
DĂ©marrage

Comme d’habitude avec Git, la premiùre commande est un clonage :

$ 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

Cela crĂ©e ce qui en parlĂ© Git s’appelle un clone « superficiel » (shallow) ; seule la toute derniĂšre rĂ©vision Perforce est importĂ©e dans Git ; souvenez-vous que Perforce n’a pas Ă©tĂ© pensĂ© pour fournir toutes les rĂ©visions Ă  chaque utilisateur. C’est suffisant pour utiliser Git comme client Perforce, mais pour d’autres utilisations, ce n’est pas assez.

Une fois que c’est terminĂ©, nous avons un dĂ©pĂŽt Git complĂštement fonctionnel.

$ 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

Notez le dĂ©pĂŽt p4 distant pour le serveur Perforce, mais tout le reste ressemble Ă  un clone standard. En fait, c’est trompeur ; ce n’est pas rĂ©ellement dĂ©pĂŽt distant.

$ git remote -v

Il n’y a pas du tout de dĂ©pĂŽt distant. Git-p4 a crĂ©Ă© des rĂ©fĂ©rences qui reprĂ©sentent l’état du serveur et celles-ci ressemblent Ă  des rĂ©fĂ©rences de dĂ©pĂŽts distants dans git log, mais elles ne sont pas gĂ©rĂ©es par Git lui-mĂȘme et vous ne pouvez pas pousser dessus.

Utilisation

Donc, travaillons un peu. Supposons que vous avez progressĂ© sur une fonctionnalitĂ© trĂšs importante et que vous ĂȘtes prĂȘt Ă  la montrer au reste de votre Ă©quipe.

$ 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

Nous avons rĂ©alisĂ© deux nouveaux commits qui sont prĂȘts Ă  ĂȘtre soumis au serveur Perforce. VĂ©rifions si quelqu’un d’autre a poussĂ© son travail entre temps.

$ 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

Il semblerait que ce soit le cas, et master et p4/master ont divergĂ©. Le systĂšme de branchement de Perforce ne ressemble en rien Ă  celui de Git, donc soumettre des commits de fusion n’a aucun sens. Git-p4 recommande de rebaser vos commits et fournit mĂȘme un raccourci pour le faire :

$ 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(-)

Vous pouvez dĂ©jĂ  le deviner aux messages affichĂ©s, mais git p4 rebase est un raccourci pour git p4 sync suivi de git rebase p4/master. C’est lĂ©gĂšrement plus intelligent que cela, spĂ©cifiquement lors de la gestion de branches multiples, mais ça correspond bien.

À prĂ©sent, notre historique est linĂ©aire Ă  nouveau et nous sommes prĂȘts Ă  remonter nos modifications sur Perforce. La commande git p4 submit va essayer de crĂ©er une nouvelle rĂ©vision Perforce pour chaque commit Git entre p4/master et master. Son lancement ouvre notre Ă©diteur favori et le contenu du fichier ouvert ressemble Ă  ceci :

# 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="https://www.perforce.com/jam/jam.html">
+<a href="jam.html">
 Jam/MR</a>,
 a software build tool.
 </td>

C’est quasiment le mĂȘme contenu qu’on verrait en lançant p4 submit, mis Ă  part le bloc Ă  la fin que git-p4 a utilement inclus. Git-p4 essaye d’honorer vos rĂ©glages Git et Perforce individuellement quand il doit fournir un nom pour un commit ou une modification, mais dans certains cas, vous voudrez le modifier. Par exemple, si le commit Git que vous importez a Ă©tĂ© Ă©crit par un contributeur qui n’a pas de compte utilisateur dans Perforce, vous voudrez tout de mĂȘme que la modification rĂ©sultante ait l’air d’avoir Ă©tĂ© Ă©crite par lui, et non par vous.

Git-p4 a importĂ© le message du commit Git comme contenu de la modification Perforce, donc tout ce qu’il nous reste Ă  faire et de sauvegarder et de quitter, deux fois (une fois par commit). La sortie qui en rĂ©sulte ressemble Ă  ceci :

$ 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

À la sortie, c’est comme si nous avions fait un git push, ce qui est l’analogie la plus proche avec ce qui s’est rĂ©ellement passĂ©.

Notez aussi que durant ce processus, les commits Git sont transformĂ©s en modifications Perforce ; si vous voulez les comprimer en une seule modification, vous pouvez le faire avec un rebasage interactif avant de lancer git p4 submit. Notez aussi que les empreintes SHA-1 de tous les commits qui ont Ă©tĂ© soumis comme modifications ont changé ; c’est parce que git-p4 ajoute une ligne Ă  la fin de chaque message de validation qu’il convertit :

$ 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]

Que se passe-t-il si vous essayez de soumettre un commit de fusion ? Essayons pour voir. Voici la situation dans laquelle nous sommes :

$ 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

Les historiques Git et Perforce divergent Ă  partir de 775a46f. Le cĂŽtĂ© Git contient deux commits, puis un commit de fusion avec la tĂȘte Perforce, puis un autre commit. Nous allons essayer de les soumettre au sommet d’un seul changement cĂŽtĂ© Perforce. Voyons ce qui se passerait si nous essayions de soumettre cet historique maintenant :

$ 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

L’option -n est un raccourci pour --dry-run qui essaie d’afficher ce qui se passerait si la commande submit Ă©tait rĂ©ellement lancĂ©e. Dans ce cas, il semble que nous crĂ©erions trois modifications Perforce, ce qui correspond aux trois commits sans fusion qui n’existent pas encore sur le serveur Perforce. Cela ressemble exactement Ă  ce que nous souhaitons, voyons comment cela se passe :

$ 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

Notre historique est devenu linĂ©aire, comme si nous avions rebasĂ© avant de soumettre (ce qui est exactement ce qui s’est passĂ©). Cela signifie que vous ĂȘtes libre de crĂ©er, modifier, jeter et fusionner les branches du cĂŽtĂ© Git sans crainte que votre historique deviennent Ă  un moment incompatible avec Perforce. Si vous pouvez le rebaser, vous pourrez le reporter dans le serveur Perforce.

Branche

Si votre projet Perforce a de multiples branches, vous n’ĂȘtes pas malchanceux ; git-p4 peut gĂ©rer cette configuration d’une maniĂšre similaire Ă  Git. Supposons que votre dĂ©pĂŽt Perforce ait la forme suivante :

//depot
  └── project
      ├── main
      └── dev

Et supposons que vous ayez une branche dev qui contient une view spec qui ressemble à ceci :

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

Git-p4 peut dĂ©tecter automatiquement cette situation et faire ce qu’il faut :

$ 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

Notez le dĂ©terminant « @all » ; il indique Ă  git-p4 de cloner non seulement la derniĂšre modification pour ce sous-arbre, mais aussi toutes les modifications qui ont dĂ©jĂ  touchĂ© Ă  ces chemins. C’est plus proche du concept de clone dans Git, mais si vous travaillez sur un projet avec un long historique, cela peut prendre du temps Ă  se terminer.

L’option --detect-branches indique Ă  git-p4 d’utiliser les spĂ©cifications de branche de Perforce pour faire correspondre aux rĂ©fĂ©rences Git. Si ces correspondances ne sont pas prĂ©sentes sur le serveur Perforce (ce qui est une maniĂšre tout Ă  fait valide d’utiliser Perforce), vous pouvez dire Ă  git-p4 ce que sont les correspondances de branches, et vous obtiendrez le mĂȘme rĂ©sultat :

$ 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 .

Renseigner la variable de configuration git-p4.branchList Ă  main:dev indique Ă  git-p4 que main et dev sont toutes deux des branches et que la seconde est la fille de la premiĂšre.

Si nous lançons maintenant git checkout -b dev p4/project/dev et ajoutons quelques commits, git-p4 est assez intelligent pour cibler la bonne branche quand nous lançons git-p4 submit. Malheureusement, git-p4 ne peut pas mĂ©langer les clones superficiels et les branches multiples ; si vous avez un projet gigantesque et que vous voulez travailler sur plus d’une branche, vous devrez lancer git p4 clone une fois pour chaque branche Ă  laquelle vous souhaitez soumettre.

Pour crĂ©er ou intĂ©grer des branches, vous devrez utiliser un client Perforce. Git-p4 ne peut synchroniser et soumettre que sur des branches prĂ©existantes, et il ne peut le faire qu’avec une modification linĂ©aire Ă  la fois. Si vous fusionnez deux branches dans Git et que vous essayez de soumettre la nouvelle modification, tout ce qui sera enregistrĂ© sera une sĂ©rie de modifications de fichiers ; les mĂ©tadonnĂ©es relatives aux branches impliquĂ©es dans cette intĂ©gration seront perdues.

Résumé Git et Perforce

Git-p4 rend possible l’usage des modes d’utilisation de Git avec un serveur Perforce, et ce, de maniĂšre plutĂŽt rĂ©ussie. Cependant, il est important de se souvenir que Perforce gĂšre les sources et qu’on ne travaille avec Git que localement. Il faut rester vraiment attentif au partage de commits Git ; si vous avez un dĂ©pĂŽt distant que d’autres personnes utilisent, ne poussez aucun commit qui n’a pas dĂ©jĂ  Ă©tĂ© soumis au serveur Perforce.

Si vous souhaitez mĂ©langer l’utilisation de Git et de Perforce comme clients pour la gestion de source sans restriction et si vous arrivez Ă  convaincre un administrateur de l’installer, Git Fusion fait de Git un client de premier choix pour un serveur Perforce.

scroll-to-top