Twgit

Denis Favreau edited this page Sep 12, 2017 · 13 revisions
Clone this wiki locally

[ Home ][ Workflow ][ Workflow EN ][ Twgit ][ Twgit EN ]

Table des matières

1. Introduction
2. Installation
    2.1. Installation de twgit
    2.2. Auto-update
    2.3. Transition
3. Aide
    3.1. Aide contextuelle
    3.2. Coloration syntaxique
    3.3. Auto-complétion
    3.4. Logs
4. Lister les branches
    4.1. Lister les features
    4.2. Lister les releases
    4.3. Lister les tags
    4.4. Lister les hotfixes
5. Créer une branche
    5.1. Créer une feature
    5.2. Créer un hotfix
    5.3. Créer une release
6. Fusionner/clôturer une branche
    6.1. Fusionner une feature dans la release
    6.2. Fusionner/clôturer un hotfix
    6.3. Fusionner/clôturer une release
7. Supprimer une branche
    7.1. Supprimer une feature
    7.2. Supprimer un hotfix
    7.3. Supprimer une release
8. Exemples
    8.1. Travailler sur une feature
    8.2. Un tag empêche de clôturer une release
    8.3. Fusionner une feature dans une release

1. Introduction

Afin de simplifier au maximum l'utilisation du nouveau workflow, un nouvel outil nommé twgit (Twenga git) a été développé sous licence Creative Commons Attribution-NonCommercial-ShareAlike 3.0, sur une architecture similaire à celle de git-flow. Le code source est hébergé sur Github : https://github.com/Twenga/twgit.

Ses fonctionnalités permettent :

  • de diminuer le nombre de manipulations git,
  • d'automatiser les vérifications associées,
  • de remonter facilement des informations pertinentes : quelles features sont dans la release, est-ce qu'une feature devrait récupérer les derniers tags, quels sont les principaux contributeurs d'une feature...

Il aide à la gestion des branches locales et distantes dans le nouveau workflow. Lorsqu'il crée, fusionne ou supprime une branche, il le fait toujours à la fois en local et sur le dépôt distant. Ce comportement ne concerne pas les commits et à tout moment nous avons la possibilité de passer par une commande Git « native » pour une action plus limitée. Les informations remontées portent systématiquement sur les branches distantes pour moins d'ambiguïté et pour prendre en compte le travail au niveau de l'équipe.

Les noms de branches sont contraints selon leur nature :

  • les features sont de la forme feature-<name>,
  • les hotfixes sont de la forme hotfix-<version>,
  • les releases sont de la forme release-<name|version>,
  • les tags sont de la forme v<version>.

<name> est une chaîne libre sans espace, et <version> est par défaut un numéro de version applicatif au sens major.minor.revision : les hotfixes incrémentent l'entier "revision" et les releases incrémentent les entiers "major" ou "minor".

À chaque fois qu'une commande twgit nécessite la saisie d'un nom de branche, celui-ci doit être entré sans son préfixe.

2. Installation

2.1. Installation de twgit

Prérequis :

  • bash v4 minimum (2009),
  • git v1.7.2 minimum (2010).

Dans le répertoire de votre choix, par exemple ~/twgit:

git clone https://github.com/Twenga/twgit.git .
sudo make install

Si ce n'est déjà le cas, le Makefile vous permettra de personnaliser votre prompt Bash pour qu'il remonte des informations Git lorsque l'on se trouve à l'intérieur de dépôts : cf. Des informations Git dans son prompt.

Résolution des éventuels problèmes :

  • Si vous avez le droit à un "-bash: git: command not found" lors du git clone, alors il faut d'abord installer le client git sur votre environnement. Par exemple, sur Ubuntu : sudo apt-get install git.
  • Si l'on vous demande un mot de passe que vous ne possédez pas (celui de l'utilisateur git), c'est qu'il faut ajouter/générer votre clé SSH sur Github : Account Settings.
  • Si vous avez le droit à un "-bash: make: command not found" lors du make install, alors il faut d'abord installer la commande make, présente dans le package "build-essential".

2.2. Auto-update

Twgit bénéficie d'un mécanisme de mise à jour semi-automatique. Ceci est d'autant plus intéressant que l'outil est jeune...

Tous les "N" jours (paramètre du fichier de configuration) et si le répertoire ".git" du répertoire d'installation de twgit n'est pas effacé, alors un test d'existence d'une version plus récente est effectué à l'occasion d'une sollicitation utilisateur.

Si l'installation est à jour, un simple message averti que le prochain test n'aura pas lieu avant "N" autres jours :

Dans le cas contraire, twgit propose à l'utilisateur la mise à jour :

2.3. Transition

Voici la traduction du Processus de transition présenté plus haut en instructions git :

  • Pour créer la branche "stable" à partir de "master" et créer le tag :
git checkout --track -b stable master
git push --set-upstream origin stable
git tag -a v4.11.0 -m 'premier tag'
git push --tags origin
  • Pour chaque branche de dev encore ouverte et que l'on souhaite migrer dans le nouveau système :
twgit feature migrate <oldfeaturefullname> <newfeaturename>

Par exemple : "twgit feature migrate rm7880 7880"

Cet appel exécute à peu de choses près les commandes suivantes :

git checkout --track -b feature-[new_name] origin/[old_name]
git push --set-upstream origin feature-[new_name]
git branch -D [old_name]
git push origin :[old_name]
git merge --no-ff stable

3. Aide

3.1. Aide contextuelle

Sur le même modèle que git, twgit emporte une aide contextuelle à chaque niveau. Aide principale :

Aide de la commande release :

3.2. Coloration syntaxique

Une coloration syntaxique cohérente sur l'ensemble de l'application a été mise en place et doit permettre d'identifier rapidement :

  • une erreur bloquante :
  • un warning :
  • une question :
  • un titre de section :
  • un sous-titre :
  • une information Redmine :
  • une information :
  • une vérification interne :
  • une commande git lancée par twgit :

3.3. Auto-complétion

L'auto-complétion (double touche "tab") est présente aux différents niveaux (commande, action, références) :

3.4. Logs

Twgit log systématiquement toute activité dans 2 fichiers :

  • les erreurs applicatives dans $TWGIT_HISTORY_ERROR_PATH, défini par défaut à $TWGIT_ROOT_DIR/.history.error,
  • tout le reste dans $TWGIT_HISTORY_LOG_PATH, défini par défaut à $TWGIT_ROOT_DIR/.history.log.

4. Lister les branches

4.1. Lister les features

Liste les features, avec le sujet Redmine du ticket associé, en les catégorisant :

  • celles dont le développement est arrêté et qui ont été livrées/mergées dans le release en cours ;
  • celles mergées dans la release en cours mais dont le développement s'est poursuivi (twgit empêchera la finalisation de la release tant que de telles branches existeront) ;
  • celles sans relation avec une release ;

Si twgit détecte des features fusionnées à la branche stable, alors il les listera précédées d'un warning : elles ne sont pas censées exister. Lors de la finalisation d'une release, toutes les features associées sont supprimées.

Par ailleurs sera listée ici précédée d'un warning :

  • toute branche hors nomenclature,
  • ainsi que toute branche n'ayant pas intégré les derniers tags (et dont le développement dure, a priori).

Il est possible d'obtenir un affichage plus compact avec l'option -c :

4.2. Lister les releases

Une seule release en cours est autorisée à la fois (twgit s'en assure et affichera au besoin un warning). Et comme les releases qualifiées sont fusionnées à la stable puis supprimées, la liste des releases se cantonne à afficher l'éventuelle release en cours.

Le cas échéant, les features en rapport avec cette release apparaîtront :

  • avec la mention merged pour celles dont le développement s'est arrêté dès la fusion dans la release,
  • avec la mention merged, then in progress pour celles reparties en évolution (twgit empêchera la finalisation de la release tant que de telles branches existeront),
  • dans tous les cas, avec le sujet du ticket Redmine associé si trouvé.

Comme pour les features, toute branche n'ayant pas intégré les derniers tags se verra accompagnée d'un warning précisant le problème.

Algorithme :

La détermination du lien entre une feature et la release en cours est complexe. Il faut commencer par calculer plusieurs nœuds :

  • "release/feature merge base" est le nœud qui serait retenu comme le meilleur ancêtre commun pour un merge entre la release et la feature
  • "(rel/feat)/stable merge base" est le nœud qui serait retenu comme le meilleur ancêtre commun pour un merge entre le nœud précédent et la branche stable
  • "dependency merge" est le nœud fils immédiat du nœud "release/feature merge base", de type merge et n'appartenant pas aux ancêtres de la release

Alors :

  • si "release/feature merge base" est identique au "HEAD" de la feature, alors la feature est de type merged
  • sinon si "release/feature merge base" est différent de "(rel/feat)/stable merge base" et que l'on ne trouve pas le nœud "dependency merge", alors la feature est de type merged, then in progress
  • sinon la feature est de type free

Ainsi si une feature a est mergée dans une feature b et si b est envoyée dans la release, alors ce lien de dépendance entre features sera traduit par le fait que a sera considérée comme envoyée dans la release.

4.3. Lister les tags

Liste les 5 derniers tags.

4.4. Lister les hotfixes

Un seul hotfix en cours est autorisée à la fois (twgit s'en assure et affichera au besoin un warning). Et comme les hotfixes finis sont fusionnés à la stable puis supprimés, la liste des hotfixes se cantonne à afficher l'éventuel hotfix en cours.

5. Créer une branche

5.1. Créer une feature

Permet :

  • de créer une nouvelle feature à la fois en local et sur le dépôt distant, à partir du dernier tag,
  • ou bien de se brancher sur une feature distante existante,
  • ou bien d'effectuer un checkout sur une feature existante à la fois localement et à distance.

Fournir comme nom soit un numéro de ticket Redmine (simple ou ticket parent), par exemple 4556, soit un nom de sous-projet tel qu'il apparaît dans les URL Redmine, par exemple payment-terms pour le sous-projet Conditions de paiement - CB.

Algorithme :

  • s'assure que le nom est valide
  • détecte si la branche locale existe déjà
  • si la branche locale existe déjà :
    • effectue un checkout dessus
  • sinon :
    • s'assure que le working tree (la branche courante) est dans un status "nothing to commit (working directory clean)"
    • met à jour les références distantes (y compris les suppressions de branche)
    • détecte s'il s'agit d'une création ou si une branche distante existe déjà
    • si branche distante existe déjà :
      • effectue un checkout de celle-ci et active le tracking (ce qui permet des simples git push et git pull sans argument)
    • sinon c'est une création :
      • s'assure qu'au moins un tag existe sur la branche stable et récupère le plus récent
      • crée localement la branche à partir de ce tag
      • effectue un premier commit blanc technique au commentaire préformaté
      • crée la branche distante associée et active le tracking (ce qui permet des simples git push et git pull sans argument)
  • dans tous les cas notifie si des tags ne sont pas présents dans la feature

5.2. Créer un hotfix

Permet :

  • de créer un nouveau hotfix à la fois en local et sur le dépôt distant, à partir du dernier tag.
  • ou bien de se brancher sur un hotfix distant existant,
  • ou bien d'effectuer un checkout sur un hotfix existant à la fois localement et à distance.

Si la version du tag est : major.minor.revision, alors celle du hotfix sera : major.minor.(revision+1).

Algorithme :

  • s'assure que le working tree (la branche courante) est dans un status nothing to commit (working directory clean)
  • met à jour les références distantes (y compris les suppressions de branche)
  • recherche l'existence d'un hotfix distant (on ne peut en avoir qu'un à la fois)
  • si nouveau hotfix :
    • s'assure qu'au moins un tag existe sur la branche stable,
    • récupère le tag le plus récent, puis incrémente son numéro de révision afin de constituer le nom du nouveau hotfix
    • crée localement une branche de ce nom à partir du dernier tag
    • effectue un premier commit blanc technique au commentaire préformaté
    • crée la branche distante associée et active le tracking (ce qui permet des simples git push et git pull sans argument)
  • sinon :
    • s'assure que le nom est valide
    • détecte si la branche locale existe déjà
    • si la branche locale existe déjà :
      • effectue un checkout dessus
    • sinon :
      • effectue un checkout de la branche distante et active le tracking (ce qui permet des simples git push et git pull sans argument)

5.3. Créer une release

Permet :

  • de créer une nouvelle release à la fois en local et sur le dépôt distant, à partir du dernier tag.
  • ou bien de se brancher sur une release distante existante,
  • ou bien d'effectuer un checkout sur une release existant à la fois localement et à distance.

Par défaut, si la version du tag est : major.minor.revision, alors celle de la release sera : major.(minor+1).revision. Il est possible d'incrémenter d'une version majeur avec l'option -M. Il est également possible de donner un nom quelconque à une release.

Algorithme :

  • s'assure que le working tree (la branche courante) est dans un status nothing to commit (working directory clean)
  • met à jour les références distantes (y compris les suppressions de branche)
  • s'assure qu'au moins un tag existe sur la branche stable,
  • recherche l'existence d'une release distante (on ne peut en avoir qu'une à la fois)
  • si l'on n'a pas fourni de nom de release :
    • si une release existe déjà alors faire comme si l'on avait entré son nom
    • sinon :
      • récupère le tag le plus récent, puis incrémente son numéro majeur ou mineur (selon options) afin de constituer le nom de la nouvelle release
      • demander confirmation
  • s'assure que le nom est valide
  • si une release existe déjà :
    • s'assure que le nom retenu pour la nouvelle release est identique à celui de la release existante
    • détecte si la branche locale existe déjà
    • si la branche locale existe déjà :
      • effectue un checkout dessus
    • sinon :
      • effectue un checkout de la branche distante et active le tracking (ce qui permet des simples git push et git pull sans argument)
  • sinon :
    • crée localement une branche du nom retenu à partir du dernier tag
    • effectue un premier commit blanc technique au commentaire préformaté
    • crée la branche distante associée et active le tracking (ce qui permet des simples git push et git pull sans argument)
  • dans tous les cas notifie si des tags ne sont pas présents dans la release

Il est possible de réinitialiser la release courante en appelant : twgit release reset. Cette commande la supprime avant de la créer à nouveau, vierge de toute feature.

6. Fusionner/clôturer une branche

6.1. Fusionner une feature dans la release

Permet de merger une feature dans la release en cours.

Algorithme :

  • s'assure que le working tree (la branche courante) est dans un status nothing to commit (working directory clean)
  • met à jour les références distantes (y compris les suppressions de branche)
  • s'assure qu'une release est en cours
  • s'assure que la feature existe sur le dépôt distant
  • essaye d'exécuter séquentiellement les commandes suivantes :
twgit feature start $feature
git pull $TWGIT_ORIGIN $feature_fullname
twgit release start
git pull $TWGIT_ORIGIN $release_fullname
git merge –no-ff $feature_fullname
git push $TWGIT_ORIGIN $release_fullname
  • à la moindre erreur, stop le workflow et indique à l'utilisateur les commandes non exécutées

Commande : twgit feature merge-into-release <featurename>.

6.2. Fusionner/clôturer un hotfix

Permet de clôturer le hotfix en cours en le fusionnant à la branche stable et en créant un tag associé. La branche du hotfix sera supprimée en fin de processus.

Algorithme :

  • s'assure que le working tree (la branche courante) est dans un status nothing to commit (working directory clean)
  • met à jour les références distantes (y compris les suppressions de branche)
  • s'assure qu'un hotfix est en cours et récupère son nom
  • s'il existe une branche locale pour ce hotfix, alors s'assure qu'elle n'est pas plus vieille que celle distante (ce n'est pas un problème si la locale est plus récente)
  • construit un nom de tag à partir du nom du hotfix et s'assure que le nom est valide
  • s'assure que ce nom de tag n'est pas déjà utilisé
  • effectue un checkout sur la branche locale stable
  • merge la stable distante dans la stable locale
  • merge la branche locale du hotfix dans la stable locale
  • crée le tag sur la branche stable
  • pousse le nouveau tag sur le dépôt distant
  • supprime le hotfix (cf. twgit hotfix remove)
  • si une release est en cours, averti de ne pas oublier de fusionner le nouveau tag dans la release avant de tenter de la clôturer (de toute façon twgit l'en empêchera)

6.3. Fusionner/clôturer une release

Permet de clôturer la release en cours en la fusionnant à la branche stable et en créant un tag associé. Toutes les branches des features associées à la release seront supprimées en fin de processus. La branche de la release sera supprimée en fin de processus.

Algorithme :

  • s'assure que le working tree (la branche courante) est dans un status nothing to commit (working directory clean)
  • met à jour les références distantes (y compris les suppressions de branche)
  • s'assure qu'une release est en cours et récupère son nom
  • construit un nom de tag à partir du nom de la release ou à partir de l'éventuel paramètre , et s'assure que le nom est valide
  • s'assure que ce nom de tag n'est pas déjà utilisé
  • s'assure qu'aucun hotfix n'est en cours
  • s'assure que si un ou plusieurs tags ont été créés depuis la création de la release, alors ceux-ci ont été mergés dans celle-ci
  • s'assure qu'aucune feature mergée à la release n'est encore en développement
  • s'il existe une branche locale pour cette release, et si la locale est plus vieille que celle distante alors :
    • si la locale est un ancêtre direct, alors propose d'effectuer un pull
    • sinon stop le processus
  • effectue un checkout sur la branche locale stable
  • merge la stable distante dans la stable locale
  • merge la branche locale de la release dans la stable locale
  • crée le tag sur la branche stable
  • pousse le nouveau tag sur le dépôt distant
  • supprime toutes les features associées (cf. twgit feature remove)
  • supprime la release (cf. twgit release remove)

7. Supprimer une branche

Afin de réduire le risque de mauvaise manipulation lors de la suppression d'une branche :

  • l'auto-complétion a été désactivée sur cette action
  • le nom de la branche est toujours obligatoire même s'il est déductible dans les cas hotfix et release.

7.1. Supprimer une feature

Permet de supprimer la feature spécifiée, à la fois localement et sur le dépôt distant.

Algorithme :

  • s'assure que le nom est valide
  • s'assure que le working tree (la branche courante) est dans un status nothing to commit (working directory clean)
  • s'assure que le working tree n'est pas positionné sur la branche en instance de suppression, auquel cas un checkout sur la branche stable est réalisé
  • met à jour les références distantes (y compris les suppressions de branche)
  • supprime la branche locale
  • supprime la branche distante

7.2. Supprimer un hotfix

Permet de supprimer le hotfix spécifié, à la fois localement et sur le dépôt distant.

Algorithme :

  • s'assure que le nom est valide
  • s'assure que le working tree (la branche courante) est dans un status nothing to commit (working directory clean)
  • s'assure que le working tree n'est pas positionné sur la branche en instance de suppression, auquel cas un checkout sur la branche stable est réalisé
  • met à jour les références distantes (y compris les suppressions de branche)
  • supprime la branche locale
  • supprime la branche distante

7.3. Supprimer une release

Permet de supprimer la release spécifiée, à la fois localement et sur le dépôt distant.

Algorithme :

  • s'assure que le nom est valide
  • s'assure que le working tree (la branche courante) est dans un status nothing to commit (working directory clean)
  • s'assure que le working tree n'est pas positionné sur la branche en instance de suppression, auquel cas un checkout sur la branche stable est réalisé
  • met à jour les références distantes (y compris les suppressions de branche)
  • supprime la branche locale
  • supprime la branche distante

8. Exemples

TODO à étoffer...

8.1. Travailler sur une feature

Qu'elle soit nouvelle ou non, locale ou distante :

twgit feature start [feature_name] # par exemple le numéro d'un ticket Redmine

Travailler puis commiter :

git add [path]
git commit -am '[msg]'
git push

8.2. Un tag empêche de clôturer une release

Si vous avez à l'exécution de la commande twgit release finish un message d'erreur du genre :

/!\\ You must merge following tag(s) into this release before close it: v1.1.7, v1.1.8

Alors :

git checkout release-1.2.6 # ou si release non présente localement : twgit release start 1.2.6
git pull
git merge --no-ff v1.1.8
git push

8.3. Fusionner une feature dans une release

Twgit propose désormais d'automatiser cette étape : twgit feature merge-into-release xxxx cf. Fusionner/clôturer une branche

Sinon, manuellement :

Si vous n'avez pas la feature en local :

twgit feature start 7990

La fusionner à la release :

git checkout release-1.2.6 # ou twgit release start
git pull
git merge --no-ff feature-7990
git push