88 votes

Git pour les utilisateurs de Perforce

J'utilise Perforce depuis un certain nombre d'années. J'aimerais passer à l'utilisation de git pour mon code personnel, mais tous les tutoriels git que j'ai vus supposent que vous êtes un n00b du contrôle de source (ce qui les rend incroyablement fastidieux) ou que vous êtes habitué à svn (ce que je ne suis pas).

Je connais p4, et je comprends aussi l'idée derrière un système de contrôle de source distribué (donc je n'ai pas besoin d'un discours commercial, merci). Ce que j'aimerais, c'est une table de traduction des commandes p4 en commandes git équivalentes, ainsi que les commandes "incontournables" qui n'ont pas d'équivalent p4.

Comme je soupçonne que chaque utilisateur de p4 utilise un sous-ensemble différent de p4, voici quelques-unes des choses que je fais régulièrement dans p4 et que j'aimerais pouvoir faire dans git, mais qui ne sont pas immédiatement évidentes dans les documents que j'ai consultés :

  1. créer plusieurs listes de modifications en attente dans un seul client. ( p4 change )
  2. modifier une liste de modifications en attente. (également p4 change )
  3. voir une liste de toutes mes listes de modifications en attente ( p4 changes -s pending )
  4. liste de tous les fichiers modifiés dans mon client ( p4 opened ) ou dans une liste de changements en attente ( p4 describe )
  5. voir un diff d'une liste de modifications en attente (j'utilise un script pour cela qui utilise p4 diff y p4 describe )
  6. pour un fichier donné, voir quelles listes de modifications soumises ont affecté quelles lignes ( p4 annotate )
  7. pour un fichier donné, voir une liste des descriptions des listes de modifications qui ont affecté le fichier ( p4 log )
  8. soumettre une liste de modifications en attente ( p4 submit -c )
  9. interrompre une liste de modifications en attente ( p4 revert )

Beaucoup d'entre elles tournent autour des "changelists". "changelist" est la terminologie de p4. Quel est le terme équivalent dans git ?

Il semble que les branches soient ce que les utilisateurs de git utilisent à la place de ce que p4 appelle des listes de changements. Un peu déroutant, puisque p4 a aussi quelque chose appelé branche, bien qu'ils semblent n'être que des concepts vaguement liés. (Bien que j'ai toujours pensé que le concept de branche de p4 était assez bizarre ; il est encore différent du concept classique de branche du RCS).

Bref... Je ne suis pas sûr de savoir comment accomplir ce que je fais normalement dans les changelists de p4 avec les branches de git. Dans p4, je peux faire quelque chose comme ceci :

$ p4 edit a.txt
$ p4 change a.txt
Change 12345 created.

À ce stade, j'ai une liste de modifications qui contient un fichier .txt. Je peux modifier la description et continuer à travailler sans soumettre la changelist. De même, s'il s'avère que je dois apporter des modifications à d'autres fichiers, par exemple pour corriger un bogue dans une autre couche du code, je peux le faire dans le même client :

$ p4 edit z.txt
$ p4 change z.txt
Change 12346 created.

Maintenant, j'ai deux listes de modifications distinctes dans le même client. Je peux travailler dessus simultanément, et je n'ai pas besoin de faire quoi que ce soit pour passer de l'une à l'autre. Au moment de la validation, je peux les soumettre séparément :

$ p4 submit -c 12346  # this will submit the changes to z.txt
$ p4 submit -c 12345  # this will submit the changes to a.txt

Je n'arrive pas à trouver comment reproduire cela dans git. D'après mes expérimentations, il ne semble pas que git add est associé à la branche en cours. Pour autant que je puisse dire, lorsque je git commit il va commettre tous les fichiers que j'ai git add -quelle que soit la branche dans laquelle je me trouvais à l'époque :

$ git init
Initialized empty Git repository in /home/laurence/git-playground/.git/
$ ls
a.txt  w.txt  z.txt
$ git add -A .
$ git commit
 Initial commit.
 3 files changed, 3 insertions(+), 0 deletions(-)
 create mode 100644 a.txt
 create mode 100644 w.txt
 create mode 100644 z.txt
$ vi a.txt z.txt 
2 files to edit
$ git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   a.txt
#   modified:   z.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
$ git branch aardvark
$ git checkout aardvark
M   a.txt
M   z.txt
Switched to branch 'aardvark'
$ git add a.txt 
$ git checkout master
M   a.txt
M   z.txt
Switched to branch 'master'
$ git branch zebra
$ git checkout zebra
M   a.txt
M   z.txt
Switched to branch 'zebra'
$ git add z.txt 
$ git status
# On branch zebra
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   a.txt
#   modified:   z.txt
#
$ git checkout aardvark
M   a.txt
M   z.txt
Switched to branch 'aardvark'
$ git status
# On branch aardvark
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   a.txt
#   modified:   z.txt

Dans cet exemple, les branches aardvark et zebra semblent contenir exactement le même ensemble de modifications, et d'après la sortie de la commande git status il semble que faire un commit dans l'un ou l'autre aura le même effet. Est-ce que je fais quelque chose de mal ?

2 votes

Vous pourriez simplement utiliser perforce pour votre code personnel en supposant que les 5 clients gratuits sont suffisants.

3 votes

C'est ce que je faisais jusqu'à présent, mais j'aimerais passer à quelque chose qui soit open-source et également utilisé par des projets open-source. J'ai considéré à la fois git et Mercurial. J'ai penché pour git parce qu'il semble avoir plus d'élan.

2 votes

Vous feriez mieux d'apprendre Git à partir de zéro. Le flux de travail prescrit par Git est très différent du flux de travail prescrit par Perforce. La traduction des flux de travail sera maladroite, et essayer de mettre en équation les fonctionnalités rendra votre compréhension difficile. Heureusement, la communauté Git offre une abondance de documentation pour les débutants, par ex. git-scm.com/book

75voto

slebetman Points 28276

Je n'ai pas beaucoup utilisé perforce, donc il se peut que ce ne soit pas exactement une traduction 1:1. Mais encore une fois, les systèmes de contrôle de source distribués comme git et mercurial ont un flux de travail différent de toute façon, donc il n'y a pas vraiment (et il ne devrait pas) y avoir une traduction 1:1. Quoi qu'il en soit, c'est parti :

  • Créer plusieurs listes de modifications en attente -> Utiliser les branches à la place. Dans git, les branches sont légères et rapides, il faut moins d'une seconde pour les créer et généralement moins de deux secondes pour les fusionner. N'ayez pas peur des branches et rebasez souvent.

    git branch new-branch-name
    git checkout new-branch-name

    Ou faire tout cela en une seule ligne :

    git checkout -b new-branch-name
  • Voir une liste de toutes les listes de modifications en attente -> Comme l'équivalent de plusieurs listes de modifications en attente est de multiples branches, il suffit d'afficher les branches :

    git branch

    Si vous souhaitez également visualiser les branches distantes :

    git branch -a

    Il est considéré comme une bonne pratique de supprimer immédiatement une branche après une fusion réussie afin de ne pas avoir à garder la trace des branches en attente de fusion et de celles qui ont déjà été fusionnées.

  • Lister tous les fichiers modifiés -> Pour une seule "changelist" en attente dans une branche spécifique, git a un concept d'index ou de cache. Afin de valider une modification, vous devez d'abord ajouter des fichiers à cet index. Cela vous permet de sélectionner manuellement quel groupe de fichiers représente un seul changement ou d'ignorer les fichiers non pertinents. Pour voir l'état des fichiers qui sont ajoutés ou non à cet index, il suffit de faire :

    git status
  • Voir un diff d'une liste de modifications en attente -> Il y a deux parties à cela. La première consiste à voir une différence entre le répertoire de travail et l'index :

    git diff

    Mais si vous voulez connaître la différence entre ce que vous tapez maintenant et le dernier commit, alors vous demandez vraiment une différence entre le répertoire de travail+index et le HEAD :

    git diff HEAD
  • Pour un fichier donné, voir quelles listes de modifications soumises ont affecté quelles lignes -> C'est facile :

    git blame filename

    ou mieux encore, si vous êtes dans un environnement de fenêtrage :

    git gui blame filename

    Le gui Git prend plus de temps pour analyser le fichier (il a été écrit en tcl au lieu de C) mais il a beaucoup de fonctionnalités intéressantes, y compris la possibilité de "voyager dans le temps" dans le passé en cliquant sur un ID de commit. J'aimerais seulement qu'ils implémentent une fonction de "voyage dans le temps" vers le futur pour que je puisse découvrir comment un bug donné sera finalement résolu ;-)

  • Pour un fichier donné, voir une liste des descriptions des listes de modifications qui ont affecté le fichier -> également facile :

    git log filename

    Mais git log est un outil bien plus puissant que cela. En fait, la plupart de mes scripts personnels s'appuient sur git log pour lire le dépôt. Lisez la page de manuel.

  • Soumettre une liste de modifications en attente -> Également facile :

    git commit

Voir ma réponse à une question précédente pour voir mon flux de travail git typique : Apprendre Git. J'ai besoin de savoir si je suis sur la bonne voie.

Si vous suivez le flux de travail que j'ai décrit, vous trouverez des outils comme gitk beaucoup plus utiles, car ils vous permettent de voir clairement les groupes de changements.


Réponse supplémentaire :

Git est très flexible et il y a plusieurs façons de faire ce que vous décrivez. La chose à retenir est de toujours commencer une nouvelle branche pour chaque fonctionnalité sur laquelle vous travaillez. Cela signifie que la branche master n'est pas touchée et que vous pouvez toujours y revenir pour corriger des bogues. En travaillant dans git, il faut presque toujours commencer par :

git checkout -b new-feature-a

Maintenant vous pouvez éditer le fichier a.txt. Pour travailler en même temps sur une autre fonctionnalité, faites :

git checkout master
git checkout -b new-feature-z

Maintenant vous pouvez éditer le fichier z.txt. Pour revenir au fichier a.txt :

git checkout new-feature-a

Mais attendez, il y a des changements dans new-feature-z et git ne vous laisse pas changer de branche. A ce stade, vous avez deux choix. Le premier est le plus simple, livrer tous les changements dans la branche courante :

git add .
git commit
git checkout new-feature-a

C'est ce que je recommande. Mais si vous n'êtes vraiment pas prêt à livrer le code, vous pouvez le cacher temporairement :

git stash

Maintenant vous pouvez passer à la branche new-feature-a. Pour revenir au code sur lequel vous travailliez, il suffit d'ouvrir la cachette :

git checkout new-feature-z
git stash pop

Quand tout est fait, fusionnez tous les changements vers master :

git merge --no-ff new-feature-a
git merge --no-ff new-feature-z

Parce que les fusions sont si rapides et si faciles (faciles parce que les conflits sont si rares et la résolution des conflits, quand il y en a un, n'est pas trop difficile), nous utilisons les branches dans git pour tout.

Voici un autre exemple d'utilisation courante des branches dans git que vous ne voyez pas dans les autres outils de contrôle de source (sauf peut-être mercurial) :

Vous devez constamment modifier vos fichiers de configuration pour refléter votre environnement de développement ? Alors utilisez une branche :

git checkout -b dev-config

Modifiez maintenant vos fichiers de configuration dans votre éditeur préféré, puis validez les modifications :

git add .
git commit

Maintenant, chaque nouvelle branche peut commencer à partir de la branche dev-config au lieu de master :

git checkout dev-config
git checkout -b new-feature-branch

Une fois que vous avez terminé, supprimez les modifications dans dev-config de new-feature-branch en utilisant interactive rebase :

git rebase -i master

Supprimez les commits que vous ne voulez pas puis sauvegardez. Maintenant vous avez une branche propre sans modifications de la configuration personnalisée. Il est temps de fusionner vers master :

git checkout master
git merge --no-ff new-feature-branch
# because master have changed, it's a good idea to rebase dev-config:
git checkout dev-config
git rebase master

Il convient de noter que la suppression des modifications avec git rebase -i fonctionne même lorsque tous les changements ont lieu dans le même fichier. Git se souvient des changements, pas du contenu des fichiers*.

*Note : en fait, techniquement, ce n'est pas tout à fait vrai, mais en tant qu'utilisateur, c'est ce que l'on ressent.


Plus de réponse supplémentaire :

D'après vos commentaires, il semble que vous souhaitiez que deux branches existent simultanément afin de pouvoir tester le fonctionnement du code combiné. Eh bien, c'est une bonne façon d'illustrer la puissance et la flexibilité des branches.

Tout d'abord, un mot sur l'implication d'un branchement bon marché et d'un historique modifiable sur votre flux de travail. Lorsque j'utilisais CVS et SVN, j'étais toujours un peu réticent à commettre. C'est parce que commettre du code instable aurait inévitablement f**k up le code de travail d'autres personnes. Mais avec git, j'ai perdu cette crainte. En effet, dans git, les autres personnes n'auront pas accès à mes modifications tant que je ne les aurai pas fusionnées avec master. Donc maintenant je me retrouve à commettre du code toutes les 5 lignes que j'écris. Vous n'avez pas besoin d'être parfaitement prévoyant pour commiter. Vous devez simplement changer votre état d'esprit : commit-to-branch==add-to-changeset, merge-to-master==commit-changeset.

Donc, revenons aux exemples. Voici comment je m'y prendrais. Disons que vous avez une branche new-feature-z et vous voulez le tester avec new-feature-a . Je créerais simplement une nouvelle branche pour la tester :

# assume we are currently in branch new-feature-z
# branch off this branch for testing
git checkout -b feature-z-and-feature-a
# now temporarily merge new-feature-a
git merge --no-ff new-feature-a

Vous pouvez maintenant tester. Si vous devez modifier quelque chose pour que la fonctionnalité z fonctionne avec la fonctionnalité a, faites-le. Si c'est le cas, vous pouvez fusionner les changements vers la branche concernée. Utiliser git rebase -i pour supprimer les changements non pertinents de la fusion.

Alternativement, vous pouvez aussi utiliser git rebase pour changer temporairement la base de new-feature-z pour pointer vers new-feature-a :

# assume we are currently in branch new-feature-z
git rebase new-feature-a

Maintenant l'historique de la branche est modifié pour que new-feature-z soit basé sur new-feature-a au lieu de master. Maintenant vous pouvez tester. Tous les changements commis dans cette branche appartiendront à la branche new-feature-z. Si vous avez besoin de modifier new-feature-a, il suffit de revenir à cette branche et de rebaser pour obtenir les nouveaux changements :

git checkout new-feature-a
# edit code, add, commit etc..
git checkout new-feature-z
git rebase new-feature-a
# now new-feature-z will contain new changes from new-feature-a

Lorsque vous avez terminé, il suffit de revenir à master pour supprimer les changements de new-feature-a :

# assume we are currently in branch new-feature-z
git rebase master

N'ayez pas peur de créer une nouvelle branche. N'ayez pas peur de créer une branche à jeter. N'ayez pas peur de jeter des branches. Et puisque merge==submit et commit==add-to-changeset n'ayez pas peur de commiter souvent. Rappelez-vous, commit est l'outil ultime d'annulation d'un développeur.

Oh, et autre chose, dans git les branches supprimées existent toujours dans votre dépôt. Donc si vous avez accidentellement supprimé quelque chose dont vous vous rendez compte plus tard qu'il est utile, vous pouvez toujours le récupérer en cherchant dans l'historique. N'ayez donc pas peur de jeter des branches.

0 votes

J'ai essayé de comprendre comment utiliser les branches git pour accomplir ce que je fais avec les changelists dans p4, mais je n'ai pas réussi. J'ai ajouté plus de détails à la question.

1 votes

Est-ce que chaque branche a son propre "index", ou y a-t-il un index unique partagé entre les branches ? Mon expérience semble suggérer le dernier cas, mais vous dites "une branche spécifique git a un concept de l'index ou du cache" ce qui suggère le premier cas.

4 votes

C'est un outil différent. Vous avez besoin d'un flux de travail différent et, avec cela, d'un état d'esprit et d'une habitude différents. Non, Git ne fonctionne pas de la manière que vous décrivez. Ce sont des branches et rien d'autre. Mais il existe des outils très puissants de manipulation des branches. Je vous suggère de vous considérer comme un débutant qui ne connaît rien au contrôle de source et de lire les tutoriels de base. Considérez votre état d'esprit actuel comme une "mauvaise habitude" contre laquelle vous devez être rééduqué au pays de Git. Désolé

2voto

Elias Bachaalany Points 557

Je souffre comme vous de l'absence du concept de "changelist" qui n'est pas exactement le même que les branches git.

J'écrirais un petit script qui créera un fichier changelist avec la liste des fichiers de cette changelist.

Une autre commande pour soumettre seulement une certaine liste de changements en appelant simplement git commit -a @change_list_contents.txt et ensuite "git commit".

J'espère que cela vous aidera, Elias

0 votes

Oui, j'ai effectivement envisagé de faire quelque chose comme ça, bien qu'au moment où j'ai posé cette question, j'étais novice en matière de git et je voulais donc connaître la solution "native". Maintenant, je trouve que la principale chose qui me manque est la possibilité de travailler sur un message commit sans commiter réellement. Cela pourrait être résolu en ayant un fichier pour contenir le "message de commit en attente", et peut-être un peu de magie pour le lire automatiquement lors de l'écriture d'un message de commit.

1 votes

@LaurenceGonsalves, le workflow que j'utilise est de commiter des messages de commit imparfaits (ou même juste "WIP") pendant que je suis concentré sur le travail, puis de modifier plus tard puis pendant mon rebase. Comme les commits sont purement locaux, ils n'ont pas besoin d'être définitifs avant que vous ne rendiez votre branche disponible (en la poussant vers votre remote ou similaire).

1voto

Jakob Borg Points 10869

Je n'ai pas assez d'expérience de p4 pour produire un véritable aide-mémoire, mais il y a au moins quelques similitudes sur lesquelles s'appuyer. Un "changeset" p4 est un "commit" git.

Les modifications de votre espace de travail local sont ajoutées à l'"index" avec git add et l'index est ensuite validé avec git commit . L'index est donc votre liste de changements en attente, à toutes fins utiles.

Vous regardez les changements avec git diff y git status , donde git diff montre généralement les changements entre l'espace de travail et l'index, mais git diff --cached montre les changements entre l'index et le référentiel (= votre liste de changements en attente).

Pour des informations plus approfondies, je vous recommande http://progit.org/book/ . Comme vous connaissez le contrôle de version en général, vous pouvez probablement en parcourir une grande partie et extraire les informations spécifiques à git...

1 votes

Je ne suis pas d'accord avec l'affirmation "un p4 changeset est un commit git" ; ce sont les équivalents les plus proches, certes, mais un p4 changeset est beaucoup plus proche d'un ensemble de commits git. Un p4 changeset représente une fonctionnalité, alors qu'une branche git représente une fonctionnalité.

0 votes

@RJFalconer Erm. Une "branche" est une branche dans Perforce aussi, non ? Et un "changeset" est une collection atomique de changements à un ou plusieurs fichiers, très similaire à un commit ? Si non, quel est l'équivalent p4 de commit ?

0 votes

Je dirais que p4 n'a pas d'équivalent, simplement parce que le degré d'atomicité n'est pas le même ; dans git je peux faire plusieurs changements dans un fichier donné puis les commiter dans des commits différents (git add -p), séparant ainsi le refactoring/cleanup dans l'historique de la correction des fonctionnalités/bugs. Si je devais faire cela dans p4, je devrais développer les deux séparément. Même dans ce cas, mes commits peuvent ne pas être continus car d'autres développeurs peuvent les soumettre entre eux (à moins que je ne fasse une branche privée, ce qui implique une duplication sur disque souvent peu pratique).

1voto

Russell Gallop Points 489

Il existe une alternative plus légère dans git qui pourrait faire partie de votre flux de travail : l'utilisation de la zone de transit git.

Je me contente souvent de faire des modifications puis de les soumettre en tant que plusieurs commits (par exemple, ajouter des instructions de débogage, refactoriser, corriger réellement un bug). Plutôt que de configurer vos listes de modifications perforce, puis de faire des modifications, puis de les soumettre, vous pouvez simplement faire vos modifications puis choisir comment les soumettre (en utilisant éventuellement la zone de transit git).

Vous pouvez livrer des fichiers particuliers à partir de la ligne de commande avec :

git commit a.txt
git commit z.txt

Ou en mettant explicitement les fichiers en attente :

git add a.txt
git commit
git add z.txt
git commit

git gui vous permet de sélectionner des lignes ou des morceaux de fichiers pour créer un commit dans la zone de transit. C'est très utile si vous avez des changements dans un fichier que vous voulez voir figurer dans différents commits. Je suis passé de git à perforce et c'est une chose qui me manque vraiment.

Il y a un petit bémol à garder à l'esprit avec ce flux de travail. Si vous apportez des modifications A et B à un fichier, que vous testez le fichier, puis que vous livrez A, vous n'avez pas testé cette livraison (indépendamment de B).

0 votes

Il est certainement vrai que git vous permet de faire des commits encore plus fins que perforce (c'est-à-dire des lignes et des hunks). La chose qui me manque (encore) de perforce est la possibilité de garder la trace de la description du changement (aka message de commit) pour ce sur quoi je suis en train de travailler. Par exemple, lorsque je vais corriger le bogue #12345, je crée une liste de modifications indiquant que je le fais (mais je ne la soumets pas, c'est-à-dire que je la commets). Puis, au fur et à mesure que je travaille dessus, je mets à jour la description du changement pour indiquer ce que j'ai fait. Enfin, quand j'ai terminé, je livre la liste de modifications.

0 votes

Dans git, il semble que l'équivalent approximatif soit de livrer ces petits bouts (souvent non fonctionnels) à une branche de développement, puis, une fois que tout est correct, de fusionner les changements. Cela me semble toujours beaucoup plus fastidieux et maladroit. De plus, je ne me suis pas encore vraiment habitué à l'idée de livrer du code qui ne compile même pas.

0 votes

@LaurenceGonsalves Curieux de savoir si vous vous y êtes habitué entre-temps. Je viens de Git pour Perforce et la possibilité de commiter toutes les 15 minutes, puis de pousser quand je suis prêt, me manque.

0voto

Toby Allen Points 6734

Cela ne répond pas spécifiquement à votre question, mais je ne sais pas si vous êtes au courant qu'une version de perforce pour 2 utilisateurs et 5 espaces de travail peut être téléchargée et utilisée gratuitement à partir du site Web de la Commission européenne. site web de perforce .

De cette façon, vous pouvez utiliser perforce à la maison pour vos projets personnels si vous le souhaitez. Le seul inconvénient est le nombre de 5 espaces de travail qui peut être un peu limité, mais il est assez incroyable d'avoir perforce disponible pour un usage domestique.

3 votes

C'est ce que je faisais jusqu'à présent, mais j'aimerais passer à quelque chose qui soit open-source et également utilisé par des projets open-source.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X