Et si vous compreniez enfin Git et GitHub ?

Si Svn (Subversion) est la version « client-server » d'un système de gestion de version, alors Git en est sans conteste la version « peer-to-peer ».

Si vous découvrez le système de gestion de version Git et que vous l'utilisez seul et occasionnellement, il existe peut-être encore beaucoup de zones d'ombre pour vous sur son utilisation ainsi que sur la totalité des possibilités offertes. D'ailleurs, êtes-vous réellement sûr de comprendre la portée de ce système de gestion de version distant et distribué ?

Bien que le contexte de vie soit détruit, les zombis vivent toujours, enfermés, tel des variables dans une fermeture.
Réseau distribué : xkl.com

C'était également mon cas. Tout le long de mon amélioration continue de l'utilisation de Git, je vais maintenir cet aide-mémoire. Il abordera :

  • la raison d'être de Git par l'exemple,
  • la description des actions de Git pour un travail sur une branche,
  • la description d'une méthode de travail multi-branche avec Git et
  • le description de Git avec de multiples sources via GitHub.

Si vous ne connaissez vraiment pas grand chose à Git n'hésitez pas à lire : Démarrage rapide de GIT et particulièrement :

Git, comment ça marche ?

Créons un système de version local

Imaginons que je crée un dossier website et que je décide d'y créer divers fichiers destinés à être ouverts dans un navigateur. Actuellement je travail seul sur ce projet dans ma société et avec mon propre ordinateur.

Git étape 1


S'il me venait l'envie de modifier le site, mais de toujours être capable de revenir à sa version antérieur, je peux adopter une approche d'historisation dans un dossier annexe historique. Dans ce dossier, je placerais une copie du site appelé version-1. Ensuite je modifierais l'original.

Git étape 2


Pour permettre au site visionné dans le navigateur d'être toujours dans le même dossier, nous pourrions également décider de créer un dossier courante qui représenterait toujours la version du site la plus récente. En faisant cela je pourrais mettre mon dossier website dans l'état de la version-1 et je sais que je pourrais revenir à l'état de la version courante puisque j'en ai une copie dans l'historisation des versions.

Git étape 3


Ainsi après plusieurs versions du site, mon dossier d'historisation pourrait ressembler à celui ci-dessous. Mon dossier de travail serait sur la version courante.

Git étape 4


Nous venons de créer un système de version rudimentaire !

Créons un système de version centralisé

Imaginons maintenant qu'une seconde personne dans ma société rejoigne le développement du site. Pour travailler sur le même site que moi (Bruno), cette personne (Bob) copierait intégralement mon dossier website.

Git étape 5


Bruno pourrait très bien créer une version du site soleil pendant que Bob continuerait une version du site lune. Les deux dossiers pourraient donc ressembler respectivement à l'image ci-dessous. Bruno serait dans la version de travail courante et Bob serait revenu dans une version de travail version-lune pour une raison quelconque.

Git étape 6


Si à présent nous souhaitions chacun pouvoir afficher l'état du travail de l'autre, nous devrions pouvoir différencier nos historiques de version, et chacun nous partager notre historique. Nous devrions alors adopter une structure comme celle ci-dessous. Nous pouvons d'ailleurs voir que si nous souhaitions afficher la version-4 nous pourrions la prendre depuis n'importe quel historique puisque « les versions » version-4 sont identiques.

Git étape 7


Pour ne pas avoir à chaque fois à copier le projet d'un ordinateur à l'autre (en prévisions des autres ordinateurs qui pourraient nous rejoindre), nous décidons de copier nos deux historiques de projet sur un serveur distant qui servirait de référence. À présent nous pouvons supprimer ce que nous voulons sur nos machines, il suffira à chaque fois d'aller récupérer l'original sur le serveur. À chaque fois que nous ferrons des modifications sur les historiques, nous prendrons soin de les monter sur le serveur. Pour avoir nos historiques à jour, il nous faudra également le demander au serveur. Pour finir, le serveur n'a pas d'espace de travail, il ne contient en fait que les historiques. C'est Bruno ou Bob qui choisissent ce qu'ils vont souhaiter afficher sur leur PC.

Git étape 8


Nous venons de créer Svn (Subversion), un système de version centralisé !

Créons un système de version distribué

À présent un troisième développeur (Alice) veut également accéder au code du site pour le modifier. Alice ne fait pas partie de la société. La société ne souhaite pas qu'Alice puisse ajouter son historique au sien. La société souhaite cependant qu'elle puisse non seulement partir de son travail, mais aussi avoir accès à toutes les versions de celui-ci dans tous les historiques ! La société lui permet donc de copier l'intégralité du serveur... chez elle ! Dans l'exemple ci-dessous, Bruno ne travail par exemple plus sur la dernière version de son historique mais sur version-soleil et Alice travail sur la version courante de Bruno.

Git étape 9


Comme Alice travail maintenant sur son propre serveur, elle peut aménager ses historiques comme elle le souhaite. Tout le travail effectué après la copie sera versionner comme elle l'entend. Par exemple Alice pourra renommer l'historique bruno en historique base. Elle pourra supprimer l'historique de bob de son serveur ou encore copier l'historique base en historique solune et continuer son travail dans cet historique !

Git étape 10


Ajoutons à cela la possibilité

  • de reverser le travail effectué par Alice sur le serveur copié dans le serveur source ou de synchroniser le serveur copié avec les nouveautés du serveur source,
  • de directement se connecter à d'autres serveurs pour mettre à jour différents historiques ou encore
  • de fusionner le travail entre des historiques sur le même serveur ou même de serveur à serveur,

et vous venez de créer Git !

Réseau distribué

Imaginez qu'il y a pleins de dépôts distants différents pour un même projet avec des tas de répliques et que sur chaque poste de travail on en trouve des clones avec une version de travail précise. Un poste de travail peut très bien avoir plusieurs dossiers provenant d'un même dépôt distant et dans des états de version différents.

Pour finir, en réalité, sur vos postes machines, ce que vous voyez en réalité ce n'est pas cela :

Git étape 2

mais cela :

Git local

car tout est optimisé et rangé de manière à ne pas avoir la copie de toutes les versions, mais de pouvoir en sortir n'importe laquelle à partir des informations de « différence » d'un instantané (révision) à l'autre. On remarque d'ailleurs qu'une même révision peut exister dans deux branches différentes si celle-ci est une copie de l'autre à un certain point. Cela signifie que les branches « n'existe pas » mais sont une vue de Git pour présenter un groupement de révision. Il existe aussi des étiquettes (« tags ») qui permettent de réellement indiquer à partir de quel instantané on peut estimer qu'on en est à la version vX.X.X d'un dépôt ou utiliser des livrables (« release ») par exemple avec GitHub.

Gérer son projet Git avec une branche

Avant de commencer, il me semble important de se rappeler que Git copie l'intégralité d'un dépôt (« repository ») distant (« remote ») en local et que la majorité des actions effectuées par l'outil de commande reviendra en réalité à uniquement changer votre dépôt local. Ainsi recherche, changement de version, changement de branche, tout sera très rapide !

Voici un schéma interactif de toutes les interactions dans le système de gestion de version de Git, vous pourrez aisément constater les actions en local bien plus nombreuse que les autres. Cliquez sur un élément pour accéder à son descriptif ci-après.

commit -a
add
commit
push
pull [-r]
fetch
merge or rebase
checkout HEAD
checkout
reset
reset
diff HEAD
diff
Local
Workspace
Index
Internet
Local Repository
Remote Repository

Workspace

Le Workspace ou Working Tree ou Working Directory est l'espace de travail. C'est une extraction unique d'une version du projet à partir de laquelle vous pouvez travailler. Ce dossier est stocké sur votre machine. Les fichiers ici sont soit identiques à la dernière révision enregistrée dans le dépôt local soit à l'état « Modifié ».

Index

L'index ou Staging Area correspond à la liste complète des fichiers présents physiquement dans votre espace de travail qui ont été déclarés comme faisant partie de la prochaine révision que vous allez enregistrer. Il est donc possible qu'un fichier présent dans l'espace de travail ne soit pas présent dans l'index si vous ne l'avez pas ajouté. Les fichiers indexés sont dans un état « Indexé ».

Local Repository

Le Local Repository est le dépôt local. C'est le dossier .git stocké dans votre espace de travail. C'est une réplique totale, sur votre machine, du dépôt distant. C'est dans le dépôt local que vous aller stocker vos révisions du projet. Le couple « .git » et l'espace de travail constitue ce que l'on appel le clone du dépôt distant. Les fichiers ici sont dans un état « Validé ».

Remote Repository

Le Remote Repository est le dépôt distant. C'est le dossier dans lequel est stocké le projet sur le serveur qui fait office de référant. Vous ne pouvez pas directement modifier ces fichiers. C'est la référence lorsque vous clonez un projet sur votre environnement afin d'en créer une réplique local et d'en initialiser la révision la plus récente en tant qu'état des fichiers de l'espace de travail.

add

Utiliser add permet d'ajouter des fichiers présent dans votre espace de travail vers l'index en prévisions d'une action futur vers un dépôt. Chaque fichier passe donc de l'état « Modifié » à « Indexé ».

reset

Utiliser reset permet de retirer des fichiers de l'index ou annuler un instantané dans le dépôt local tout en conservant (ou non) les modifications faites. Pour annuler les modifications faites tout en laissant les index et dépôt local en place il faut utiliser revert.

commit

Utiliser commit permet d'acter l'intégralité des fichiers de votre index dans le dépôt local en tant que nouvel révision. Chaque fichier passe donc d'« Indexé » à « Validé ».

commit -a

Utiliser commit -a pour ajouter automatiquement la totalité des nouveaux fichiers à l'index puis les acter dans le dépôt local.

push

Utiliser push pour monter et aligner l'intégralité des fichiers du dépôt local sur le dépôt distant.

fetch

Utiliser fetch pour descendre et aligner l'intégralité des fichiers du dépôt local depuis votre dépôt distant.

merge ou rebase

Utiliser merge pour fusionner les modifications présentent entre les fichiers de votre dernière révision et ceux rapatrier du dépôt distant (pour plus d'information sur la différence entre merge et rebase voir ici).

pull [-r]

Utiliser pull pour descendre et ré-aligner les modifications présentent entre l'espace de travail, le dépôt local et le dépôt distant. En cas de conflit, l'action fetch aura été effectuée et vous devrez résoudre les conflits et utiliser merge vous même.

checkout

Utiliser checkout permet d'extraire un instantané (une révision) et d'aligner l'espace de travail avec cet instantané du dépôt local depuis : la branche courante, une autre branche ou l'index.

status ou diff

Utiliser status ou diff permet de comparer vos fichiers de l'espace de travail avec ceux de l'index ou du dépôt local. Vous pouvez ainsi voir ce qui a changé dans un comparateur de version.

stash

Utiliser stash pour remiser l'état de votre espace de travail et de votre index dans la remise afin de ne pas perdre votre travail lors d'une extraction. Cela vous permet de ne pas acter un travail à moitié fini.

Pour en savoir plus, vous pouvez lire Les Bases de GIT et plus particulièrement :

Gérer son projet Git sur plusieurs branches

Comme créer une branche ne revient qu'à créer des aiguillages d'instantanés, cette opération est très rapide. Il ne faut donc pas hésiter à le faire ! Je vous propose ici une structure de travail avec plusieurs branches pour un projet afin de vous organiser en équipe.

Il me semble que la structure proposée par SmartGit est pertinente aussi vais-je la décrire juste après ce schéma.

Model à plusieurs Branches

Le but d'une branche et sa position dans l'avancement du travail sur le projet depuis le développement jusqu'aux livrables doit être indiqué dans son nom, c'est pourquoi nous utiliserons les noms suivants :

  • release/{nom de branche} – chaque livrable est associé à une branche correspondant à une version final de l'application.
  • master – une branche permanente comme référence correspondant à la version définitive des modifications entre chaque version de l'application. Elle correspond donc à chaque instant à la dernière version de l'application.
  • develop – une branche permanente contenant l'avancement de l'application dans son ensemble au file des versions, avec des branches de fonctionnalités créées à partir de cette version et reversées dedans.
  • feature/{nom de branche} – chaque fonctionnalité correspond au travail sur un sujet particulier (ex: une correction de bug, une nouvelle fonctionnalité...).
  • hotfix/{nom de branche} – des branches pour s'occuper des fixes urgent à apporter qui seront prioritairement reversés dans le master puis reversés dans la develop en attendant de finir dans le prochain livrable.

Pour en savoir plus, vous pouvez lire Les Branches avec GIT. et plus particulièrement :

Partagez avec le monde : bienvenue sur GitHub

Parce que mettre en place des serveurs Git vous-même est fastidieux, vous pouvez utiliser le plus grand réseau distribué de projet au monde, GitHub. Pour utiliser Git et GitHub au mieux il va être nécessaire de bien associer le vocabulaire de Git avec les exemples que nous avons précédemment décrit.

Git étape 10

Faisons comme si tous les serveurs de notre exemple précédent était sur GitHub. Une société quelconque partage un projet sur GitHub et vous découvrez Git et GitHub en tant qu'Alice pour travailler avec le projet de cette société.

Réseau GitHub

Voici ce que nous pouvons dire de l'image ci-dessus avec le vocabulaire Git(Hub) :

  • Nous sommes l'utilisateur Alice.
  • Sur notre PC, notre dépôt local (« local repository ») dans le dossier website à un espace de travail (« workspace ») qui pointe sur la révision (« commit ») 9696190 de la branche (« branch ») solune.
  • La dernière révision de la branche solune est 9696190, c'est pourquoi on peut également dire que c'est HEAD.
  • Comme le pointeur du dossier est sur HEAD, cela signifie que nous sommes sur la branche solune en elle-même (sa version la plus à jour).
  • Depuis le poste d'Alice, la source (« remote ») depuis laquelle elle a fait un clone sur son poste est www.github.com/alice/website.
  • Un alias de www.github.com/alice/website pour le dépôt local d'Alice est origin.
  • Alice a fait une réplique (« fork ») de www.github.com/society/website vers www.github.com/alice/website
  • Le dépôt distant de Alice (aliasé « origin » pour son poste) possède les branches base et solune. Elle a donc ajouté/supprimé des branches après la réplication (sinon elle aurait les mêmes que celle de www.github.com/society/website).
  • Depuis le poste d'Alice, le dépôt distant www.github.com/society/website a pour alias upstream.
  • Si Alice monte (« push ») les modifications actés (« commited ») en local, une nouvelle révision va s'ajouter. Sa HEAD va être déplacée sur cette nouvelle révision.
  • Si Alice précise le serveur upstream comme destination de la monté, alors sa branche solune sera ajoutée aux branches sur le serveur www.github.com/society/website et pas sur www.github.com/alice/website.
  • Comme Bruno est sur une révision qui n'est pas une HEAD, il n'est pas sur une branche. Il est sur une branche détachée (« detached branch »). S'il modifie des choses ici, il devra les acter dans une HEAD et donc créer une nouvelle branche pour avoir une nouvelle HEAD.
  • Si la branche bruno reçoit de nouvelles révisions, alors si Alice veut mettre à jour sa branche base, elle devra faire une récupération (« fetch ») puis une fusion sur sa HEAD pour créer une nouvelle révision. Il faudra ensuite acter cela sous un nouvelle révision (ce qui déplacera la HEAD dessus).
  • Si Alice veut proposer des changements de sa branche origin/base à ré-introduire dans la branche upstream/bruno elle peut faire une proposition de fusion (« pull request »). Bruno pourra ensuite décider d'accepter ou refuser sa proposition, ou de lui demander des ajustements.

Etc.

Index de termes

Il existe encore énormément de cas de figure et voici un petit index pour mieux appréhender ceux-ci en fonction de la langue de votre interlocuteur.

  • dépôt (repository/repo) : ensemble de données constituant un projet et la totalité de ses historiques de modification.
  • dépôt local (local repository) : ensemble des historiques (.git) et de l'espace de travail sur une machine cliente.
  • dépôt distant (remote repository) : ensemble des historiques sur une machine serveur.
  • révision/instantané (commit) : entrée d'historisation créant un instantané de l'état du projet à un moment donné.
  • acter (to commit/commiter) : action de créer un instantané.
  • branche (branch) : ensemble de révisions formant un historique.
  • branche principale (master branch) : nom donné à la branche par défaut lors de la création d'un dépôt.
  • réplique (fork) : copie d'un dépôt distant à une autre adresse serveur. Cette copie pourra ensuite avoir des divergences avec l'original et recouper des similitudes.
  • répliquer (to fork/forker) : action de faire une réplique.
  • clone : copie d'un dépôt distant sur une machine en local. Créer le .git et l'espace de travail sur la révision courante.
  • cloner (to clone) : action de faire un clone.
  • récupérer (to fetch) : action de descendre l'état du dépôt distant dans le dépôt local .git.
  • fusionner (to merge/merger — to rebase/rebaser) : action de fusionner deux branches (local ou distante) sur une machine cliente.
  • descendre (to pull/puller) : action de récupérer l'état du dépôt distant et de fusionner la branche de travail avec.
  • monter (to push/pusher) : action d'aligner les révisions du dépôt distant avec les derniers ajouts de révision de votre dépôt local.
  • proposition de fusion (pull request/PR) : proposer la fusion de deux branches différentes (du même projet ou entre réplique).
  • origine (origin) : alias attribué à la réplique depuis laquelle vous avez fait un clone.
  • référent (upstream) : alias attribué à la réplique originale depuis laquelle la votre a été faites.
  • HEAD : alias de la révision utilisé comme état courant d'une branche.

Avant de finir

Cette article étant également un aide mémoire, toute remarque pertinente que vous souhaiteriez y apporter peut-être discuté dans les commentaires ci-dessous ! N'hésitez pas !

Lire dans une autre langue