logo chat

William Dodé - Informaticien indépendant

Traduction du tutoriel GnuArch de Thomas Lord

Version du 18/09/2004 21h16 : wilk@flibuste.net--libre   docs-tla--fr--1.0     patch-102 ... base-0

Sommaire

Notes des traducteurs

Ce tutoriel est la traduction de « Arch Meets Hello-World » par Thomas Lord, l'auteur principal de Gnu-Arch.

La version originale est disponible à cette adresse : http://regexps.srparish.net/tutorial-tla/arch.html

Le format source utilisé pour la traduction et la publication (html et pdf) est RST http://docutils.sf.net

Le texte est disponible en consultation en ligne à cette adresse : http://flibuste.net/libre/tlafr et en pdf ici : http://flibuste.net/libre/tlafr/integrale.pdf

Toute suggestion, remarque, aide, patch etc sont les bienvenus !

William Dode <wilk@flibuste.net> et Sébastien Mengin

Correctures et relections : Ollivier Robert, Raphaël Badin, Raphaël Fairise, Jérôme Sautret, Stephane Raimbault, Charles Longeau.


Certains termes n'ont pas été traduits ou ont été traduits mais peuvent prêter à confusion :

  • arborescence (tree) : arborescence des fichiers d'un projets.
  • arborescence initiale (source-tree)
  • révision (revision): version intermédiaire d'un projet, chaque application d'un patch crée une nouvelle révision.
  • branche (branch) :
  • cache : une mise en cache permet de copier un ensemble de fichiers localement afin de ne pas avoir à aller les chercher sur le réseau.
  • patch changeset delta patch-set : ces termes désignent la même chose, un ensemble de modifications regroupées.
  • id (id, inventory-id) : identifiant unique d'un fichier ou d'une personne.
  • archiver (commit) : envoyer un patch dans l'archive du projet.
  • récupérer (check-out) : récupère des données
  • message de log patch-log (log message, log patch) : message destiné à décrire une opération, un patch et enregistré dans l'archive.
  • tag : un tag crée une branche à partir d'une autre.
  • branche principale (mainline) : projet principal d'où partent les branches.
  • fusion (merge) : rejoindre deux branches

Les commandes, les noms de fichiers, de patchs etc. sont de la forme commande, PATCH-1

Introduction

Arch est un outil de contrôle de révision, de gestion de code source et de gestion de configuration.

Ce manuel est un tutoriel : son propos est de vous aider à commencer à utiliser arch, et ensuite de vous apprendre à manier certaines fonctionnalités avancées.

À qui se destine ce manuel ?

On suppose que le lecteur est familier avec les commandes unix de base (telles que ls, mv et find).

Par ailleurs, le lecteur devrait être familier avec les programmes diff et patch et avec le concept de patchset.

Il est très utile -- mais pas strictement nécessaire -- d'avoir déjà utilisé d'autres systèmes de contrôle de version, tels que CVS.

Où est le manuel de référence ?

Arch est, dans sa plus grande partie, un programme auto-documenté. La commande :

% tla help

fournit une liste ordonnée des commandes disponibles et, pour une commande foo,

% tla foo -H

affiche la documentation de cette commande.

D'autres sources d'aide -- La liste de discussion et le Wiki

Un Wiki (site internet édité de manière collective) créé par la communauté des utilisateurs de arch est disponible à :

http://wiki.gnuarch.org/

Ce site comporte des comparaisons avec d'autres systèmes de contrôle de versions, des exemples de plusieurs utilisations possibles de arch, des recettes pour les tâches communes et des liens vers de nombreux outils, tels que des « shell wrappers » puissants et des explorateurs d'archive (web-based archive browsers). Les contributions et les questions de nouveaux utilisateurs sont bienvenues sur le Wiki -- à l'heure où ces lignes sont écrites, le Wiki ne requiert pas encore d'inscription pour y écrire ou y effectuer des modifications. (Cela dit, le revers de la médaille de cet accès ouvert est que l'information qui y est consignée ne doit pas être tenue pour parole d'évangile, dès lors qu'un petit malin pourrait y avoir délibérément semé le trouble ou -- plus vraisemblablement -- un débutant pourrait avoir publié des informations fausses.)

Arch est différent des anciens (et concurrents) systèmes au point que les nouveaux utilisateurs sont souvent un peu désorientés dans les premiers jours de son utilisation. On pourra trouver utile de chercher de l'aide sur la liste de discussion « gnu-arch-users », que l'on peut trouver sur :

http://www.gnu.org/software/gnu-arch

Si vous avez des besoins particuliers qu'arch ne semble pas être en mesure de satisfaire, certains membres de la liste de discussions « gnu-arch-users » sont disponibles pour des travaux de consultants. Cependant, parlez de vos propositions sur la liste de discussion en premier lieu -- il peut arriver que ce dont vous avez besoin soit déjà supporté, mais pas d'une manière évidente.

Qu'est-ce que le contrôle de révision ?

Un « système de contrôle de révision » est un outil de catalogage et de coordination pour des arborescences de fichiers et pour les modifications qu'on y apporte. Par exemple, un projet type de logiciel utilise le contrôle de révision pour suivre le développement du code source à travers le temps, pour garder une trace de chaque modification qui a été apportée à ce code (par exemple chaque correction de bogue ou ajout de fonctionnalité), pour partager ces modifications avec tous les programmeurs qui travaillent sur le projet et les aider à rester synchronisés, en combinant les modifications effectuées à des moments différents et/ou par des programmeurs différents en une seule et même arborescence.

Un « outil de gestion de code source » aide à gérer un grand nombre de fichiers bien plus grand que ce que vous pourriez faire « à la main ». Par exemple, un outil de gestion de code source est capable d'établir l'inventaire des fichiers dans une arborescence, de faire la distinction entre les fichiers sources et les fichiers temporaires (scratch files) et d'autres fichiers qui peuvent être archivés. On peut également être averti des fichiers sources ajoutés ou effacés.

La « gestion de configuration » rejoint les attentes de projets qui combinent des arborescences multiples et séparées en une seule arborescence. Un outil de gestion de configuration facilite la mise en place du projet « combiné » et de garder la trace de la façon dont le développement des parties qui le constituent est synchronisé.

Pourquoi utiliser arch ?

Arch présente de nombreux avantages, comparé aux autres systèmes de contrôle de révision. Notamment :

Il travaille sur l'ensemble de l'arborescence

Arch suit l'ensemble de l'arborescence -- et pas seulement des fichiers individuels. Par exemple, on peut changer de nombreux fichiers dans une arborescence, arch peut enregistrer tous ces changements comme un ensemble de changements, plutôt que fichier par fichier. Si on renomme les fichiers ou si on réorganise l'arborescence, arch est capable d'enregistrer ces modifications, de la même manière qu'il le fait lors des modifications de fichiers.

Il est orienté changeset

Arch ne crée pas uniquement des snapshots des arborescences de vos projets. Il associe plutôt chaque révision avec un changeset particulier : une description précise de ce qui a changé. Arch fournit ainsi des commandes orientées changeset qui facilitent la relecture de ces changements, la fusion (merge) d'arborescences en appliquant les modifications, l'analyse de l'historique d'une arborescence en demandant quels changements y ont été appliqués, et ainsi de suite.

Intégralement réparti

Arch ne repose pas sur une « distribution centralisée ». Par exemple, il n'est pas indispensable de donner un accès en écriture à tous les contributeurs importants d'un projet. Au lieu de cela, chaque contributeur peut avoir sa propre archive pour son travail. Arch opère en souplesse parmi les liens entre les archives.

Configuration système requise

Certains logiciels doivent être installés pour pouvoir utiliser arch.

Outils utilisés pour compiler arch

GNU Make : Il est nécessaire d'avoir GNU Make pour pouvoir compiler arch.

Outils Shell aux standards Posix : Le paquet nécessite que les outils shell au standards Posix soient présents sur votre système :

awk     find    mkdir   sh      wc
cat     fold    printf  tee     xargs
chmod   grep    pwd     test
date    head    rm      touch
echo    ls      sed     tsort

Note

Sur certains systèmes, le programme /bin/sh n'est pas un shell Posix (il se peut qu'il s'agisse d'une variante de csh ou encore d'une intégration très « buggée » du sh Posix). Sur ces systèmes, on devrait utiliser un autre shell pour lancer configure comme, par exemple

/usr/local/bin/bash ../configure --config-shell /usr/local/bin/bash

Périphérique "null" : Votre système doit pouvoir envoyer des données vers /dev/null. Ces données devraient tout simplement disparaître de l'univers. En tant que logiciel « écologique », nous avons fait en sorte que votre ordinateur puisse un jour convertir ces informations non traitées en chaleur, que vous pourrez utiliser en complément des systèmes de chauffage traditionnels.

Outils utilisés de manière interne par arch

Le reste des outils est utilisé de manière interne par arch lui-même. Ils ne doivent pas nécessairement être dans votre path -- lorsque vous compilez arch à partir des sources, lancez le script de configuration :

% ./configure --help

et

% ./configure --help-options

pour savoir comment indiquer les bonnes options à arch.

GNU Tar : GNU Tar doit être présent sur votre système. Arch appelle tar de manière interne pour empaqueter et dépaqueter les fichiers qu'il archive. Il est important que toutes les versions de Arch utilisent une version compatible de tar, raison pour laquelle GNU tar a été choisi.

GNU diff et GNU patch : Après de nombreuses délibérations, j'ai décidé d'utiliser les versions GNU de diff et patch. Plus précisément, nous avons besoin d'une version de diff capable de générer du « format unifié » (option -u) et une version de patch qui comprenne ce format et qui comprenne l'option --posix. (Ce serait facile d'utiliser des « diffs contextuels » ("context diffs") et, ainsi, les diff et patch standards. Cependant, les « diffs unifiés » sont plus lisibles et j'espère que choisir l'intégration spécifiques de ces sous-composants critiques aidera à donner à arch une stabilité à long terme.

Généralités

Les commandes arch en général

Chaque commande de arch est appelée par le programme tla, via une syntaxe de sous-commande ordinaire :

% tla <sub-command> <options> <parameters>

On peut consulter une liste des sous-commandes disponibles :

% tla help

Un bref sommaire des options pour chaque commande est obtenu en saisissant :

% tla <sub-command> -h

Pour chacune, un message d'aide plus détaillé peut-être obtenu :

% tla <sub-command> -H

Par exemple, essayez :

% tla my-id -H
print or change your id
usage: tla my-id [options] [id]

  -h, --help     Display a help message and exit.
  -H             Display a verbose help message and exit.
  -V, --version  Display a release identifier string
                 and exit.
  -e, --errname  specify program name for errors
  -u, --uid      print only the UID portion of the ID

With no argument print your arch id.

With an argument, record ID-STRING as your id
in ~/.arch-params/=id

Your id is recorded in various archives and log messages
as you use arch.  It must consist entirely of printable
characters and fit on one line.  By convention, it should
have the form of an email address, as in this example:

        Jane Hacker <jane.hacker@gnu.org>

The portion of an id string between < and > is called your
uid.  arch sometimes uses your uid as a fragment when generating
unique file names.

The option -u (--uid) causes only the uid part of your id string
to be printed.

Un effort à été fait pour conserver une certaine régularité concernant le nom des options et la syntaxe des paramètres. Vous devriez retenir tout cela au long de votre apprentissage des différentes commandes.

Faire les présentations

my-id

Le premier pas dans l'utilisation de arch est de définir votre identité (id) avec la ligne de commande :

% tla my-id "Tom Lord <lord@emf.net>"

Votre id devrait être composée de votre nom, suivi de votre adresse courriel entre des chevrons.

Arch enregistre votre id dans plusieurs messages de log qu'il va créer.

On peut revoir son id en tapant :

% tla my-id
Tom Lord <lord@emf.net>

Comment ça marche ? -- Votre identité pour arch

Après la commande ci-dessus, vous aurez de nouveaux fichiers dans votre répertoire personnel :

% ls ~/.arch-params
=id

% cat ~/.arch-params/=id
Tom Lord <lord@emf.net>

Attention!

Il est en général préférable de ne pas modifier manuellement les fichiers contenus dans ~/.arch-params/.

Créer une nouvelle archive

Une archive est un répertoire dédié utilisé par arch pour maintenir une bibliothèque contenant les modifications (changesets) et les arborescences de vos projets. Ce chapitre explique comment créer une nouvelle archive.

Choisir un emplacement

Vous devez choisir où sera placée votre archive, dans quel répertoire elle sera rangée.

Astuce

Il est fort probable que vous souhaitiez travailler avec plusieurs archives. Raison pour laquelle c'est une bonne idée de créer un répertoire dans lequel vos archives seront rangées.

Dans les exemples qui suivent, nous allons créer une archive qui sera un sous-répertoire de ~/{archives}, ce dernier étant le répertoire où nous rangeons toutes nos archives.

Créons donc tout d'abord {archives} :

% mkdir ~/{archives}

Choisir un nom pour une archive

L'étape suivante consiste à faire le choix d'un nom pour votre archive. Un nom d'archive est constitué d'une adresse courriel, suivie par deux tirets (--), puis par un suffixe. Par convention, l'adresse courriel devrait être celle du propriétaire de l'archive.

Dans cet exemple, nous utiliserons le nom suivant :

lord@emf.net--2003-example

Indication

Si vous utilisez une seule archive pendant un grand laps de temps elle risque d'accumuler une grande quantité d'information. L'utiliser ainsi risque de devenir difficile. Grâce à la souplesse de arch, il n'est pas indispensable de tout conserver dans une seule et même archive. C'est donc une bonne idée d'envisager la division des archives par date. Ceci implique que vous intégriez une date dans le nom de l'archive. Dans l'exemple ci-dessus, l'archive est marquée « 2003 » : un an plus tard, on pourra créer lord@emf.net--2004-example et continuer le projet dans cette nouvelle archive. L'archive de 2003 continuera d'exister -- on cessera simplement d'y ajouter des informations.

On devrait par ailleurs choisir les noms de archives de manière à les distinguer, pour permettre de travailler avec plusieurs archives. Le suffixe « -example » ci-dessus nous indique que l'archive est créée uniquement pour nous aider à pouvoir travailler avec les exemples tout au long de ce tutoriel.

Créer l'archive

Pour créer une nouvelle archive, on utilise la commande make-archive, en lui indiquant le nom de l'archive et son emplacement:

# Créer la nouvelle archive
#
% tla make-archive lord@emf.net--2003-example ~/{archives}/2003-example

En faire votre archive par défaut

Afin de nous éviter de saisir le nom de l'archive à chaque commande, on déclare que cette nouvelle archive est notre archive par défaut :

% tla my-default-archive lord@emf.net--2003-example

On peut consulter le nom actuel de l'archive par défaut en tapant :

% tla my-default-archive
lord@emf.net--2003-example

On peut annuler ce réglage avec la commande :

% tla my-default-archive -d
user default archive removed

(Si vous jouez avec l'option -d, veillez à rétablir notre archive d'exemple par défaut, afin de pouvoir continuer de suivre le tutoriel.)

Comment ça marche ? -- De nouvelles archives

Examinons ce que font réellement ces commandes.

Tout d'abord, tla sait maintenant que la nouvelle archive existe :

Quelles sont les archives que tla connaît ?

% tla archives
lord@emf.net--2003-example
    /home/lord/{archives}/2003-example

% tla wheris-archive lord@emf.net--2003-example
/home/lord/{archives}/2003-example

Où est rangée l'information ?

 % ls ~/.arch-params
 =default-archive          =id          =locations

 % cat ~/.arch-params/=default-archive
lord@emf.net--2003-example

 % ls ~/.arch-params/=locations
 lord@emf.net--2003-example

 % cat ~/.arch-params/=locations/lord@emf.net--2003-example
 /home/lord/{archives}/2003-example

Le répertoire de l'archive a été créé et contient de nouveaux fichiers :

% ls ~/{archives}
2003-example

% ls -a ~/{archives}/2003-example
.                   .archive-version
..                  =meta-info

% cat ~/{archives}/2003-example/.archive-version
Hackerlab arch archive directory, format version 2.

% ls -a ~/{archives}/2003-example/=meta-info/
.        ..        name

% cat ~/{archives}/2003-example/=meta-info/name
lord@emf.net--2003-example

Attention!

Il est en général préférable de ne pas éditer les fichiers contenus dans ~/.arch-params/ ou dans l'archive, à la main.

Commencer un nouveau projet

Ce chapitre et les suivants vous montreront comment installer et gérer un projet simple avec arch, en prenant l'exemple d'un programme qu'on appelera « hello world ».

Nommer le nouveau projet

La première étape consiste à choisir une catégorie générale qui servira à nommer le projet. Dans les exemples qui vont suivre, nous utiliserons le nom :

hello-world

Choisir une branche pour ce projet

Arch vous encourage à diviser votre travail sur un projet en « branches » séparées.

Grosso modo, les branches permettent de séparer le travail sur un projet en deux chantiers (ou plus) largement indépendants. Supposons, par exemple, que le projet « hello world » ait deux besoins :

  1. Le besoin de publier des versions régulières du bon vieux « hello world », en apportant des corrections de bogues simples ou des modifications liées à la portabilité du programme, ou, enfin, en ajoutant de petites fonctionnalités ;
  2. le besoin de commencer à travailler sur l'interface graphique du projet « hello world », dont on suppose que la réalisation prendra une année.

Nous souhaitons que ces deux chantiers progressent en parallèle, mais qu'ils n'y ait pas d'interférence entre eux. Par exemple, nous ne souhaitons pas que le code de l'interface graphique soit publié avant qu'il ne soit relativement fonctionnel.

Dans cette situation, nous utilisons les « branches » : une pour les versions régulières (la branche mainline) et une autre pour l'interface graphique (la branche gui).

Il y a plusieurs autres utilisations possibles des « branches ». Nous en décrirons certaines dans le manuel. Pour le moment, nous n'avons besoin que d'une seule branche, pour les sources officielles de « hello world », que nous appelons :

hello-world--mainline
^^^^^^^^^^^  ^^^^^^^^
   |            |
category name  branch name

Notez que la catégorie et le nom de la branche sont séparés par deux tirets. En général, les noms de catégorie et de branche doivent être composés uniquement de lettres, de chiffres ou de tirets. Ils doivent commencer par une lettre mais ne doivent pas contenir deux tirets consécutifs ni se terminer par un tiret.

Choisir un numéro de version

Pour finir, on doit choisir un numéro de version pour la version de « hello world » sur laquelle on travaille. On créera cette version dans l'archive.

Avec arch, les numéros de versions ne portent pas les noms de version d'un « snapshot » particulier ou le nom de publication de votre projet -- bien qu'ils soient liés à ce concept. Les numéros de versions correspondent au nom d'une « ligne de développement » : une séquence de changement que vous apportez alors que vous publiez une version.

Dans notre cas, on utilisera le nom :

hello-world--mainline--0.1
                       ^^^
                        |
                 version number

Notez que les numéros de version sont toujours des entiers positifs, séparés par un point.

Préparer l'archive

Maintenant que nous avons choisi le nom d'archive de notre projet, il est temps de préparer l'archive à l'utilisation de ce nom :

% tla archive-setup hello-world--mainline--0.1

Après avoir passé cette commande, on peut interroger l'archive pour voir ce qu'on a fait :

% tla categories
hello-world

% tla branches hello-world
hello-world--mainline

% tla versions hello-world--mainline
hello-world--mainline--0.1

À quoi bon tout cela ?

Les personnes qui débutent avec arch sont parfois échaudés par la rigidité de l'espace de nommage1. Les deux questions les plus communes à ce sujet sont :

« Pourquoi avoir des catégories, des branches et des versions ? Pourquoi ne pas simplement nommer les projets avec des chaînes de caractères arbitraires ? » La meilleure manière de répondre à ces questions est de rappeler qu'un système de contrôle de révision est un bibliothécaire. Une partie de son travail consiste à aider les utilisateurs à naviguer et à faire des recherches parmi une très grande collection de projets et de code sources. Dans le but de rendre ces recherches pratiques, arch définit un système de catalogage :

  • catégories,
  • branches,
  • versions.

(voir l'introduction « Qu'est-ce que le contrôle de révision ? »)

[1]On voudra peut-être lire la définition donnée par le Grand dictionnaire terminologique pour l'expression « espace de nommage ». [ndt]

D'une certaine manière, ce fonctionnement est analogue à celui des systèmes de catalogage utilisés dans les bibliothèques de livres, tels que la classification décimale Dewey. C'est une catégorisation hiérarchique de tout ce qui est dans la bibliothèque. C'est le moyen de décrire de manière uniforme l'endroit où un objet donné est stocké, et cela facilite sa recherche en suggérant des liens entre les différents articles. Par exemple, une branche est probablement liée aux autre branches dans un même projet. Une version avec un numéro de version plus grand contient probablement un travail plus récent qu'une autre dans la même branche avec un numéro de version plus bas.

Comment ça marche ? -- Créer les catégories, les branches et les versions

Que fait la commande archive-setup ? C'est assez simple : elle crée de nouveaux répertoires dans votre archive :

% tla whereis-archive lord@emf.net--2003-example
/home/lord/{archives}/2003-example

% cd `tla whereis-archive lord@emf.net--2003-example`

Les catégories sont des répertoires de haut niveau :

% ls
=meta-info      hello-world

Les branches sont au niveau suivant :

% ls hello-world
hello-world--mainline

Les versions viennent au troisième niveau...

% ls hello-world/hello-world--mainline
hello-world--mainline--0.1

... et sont elles-mêmes des répertoires :

% ls hello-world/hello-world--mainline/hello-world--mainline--0.1/
+revision-lock      +version-lock

Note

Les fichiers de verrouillage (c'est-à-dire +revision-lock) sont utilisés de manière interne par arch. Lorsque de nouvelles informations sont ajoutées à une archive, arch ne fait pas que lancer mkdir. Il modifie les archives afin qu'elles restent dans un état toujours cohérent, même si des commandes sont passées simultanément, ou qu'une commande soit interrompue au cours de son exécution.

Commencer une nouvelle arborescence

Après avoir suivi les exemples des chapitres précédents, on devrait avoir une nouvelle archive et un nouveau projet « hello-world » dans cette archive.

Dans ce chapitre nous étudierons les différentes étapes de la préparation d'une arborescence afin qu'elle soit intégrée à ce projet.

L'arborescence initiale

Afin de fournir des exemples concrets, supposons que nous ayons une version initiale de « hello-world » :

% cd ~/wd


% ls
hello-world

% cd hello-world

% ls
hw.c    main.c

% cat hw.c

#include <stdio.h>

void
hello_world (void)
{
  (void)printf ("hello warld");
}


% cat main.c

extern void hello_world (void);

int
main (int argc, char * argv[])
{
  hello_world ();
  return 0;
}

Initialiser une arborescence

La première étape pour préparer une arborescence de code source ordinaire est de la convertir en « arborescence de projet ».

% cd ~/wd/hello-world

% tla init-tree hello-world--mainline--0.1

% ls
hw.c    main.c  {arch}

Notez que nous avons indiqué à init-tree le nom de la version de l'archive dans laquelle nous travaillerons. init-tree a créé un sous-répertoire à la racine de l'arborescence ({arch}).

Le sous-répertoire {arch} indique qu'il est la racine d'une arborescence de projet :

% tla tree-root
/usr/lord/wd/hello-world

tla sait pour quelle version de l'archive est cette arborescence :

% tla tree-version
lord@emf.net--2003-example/hello-world--mainline--0.1

Enfin, arch a créé quelque chose appelé patch-log pour la version passée à init-tree :

% tla log-versions
lord@emf.net--2003-example/hello-world--mainline--0.1

Nous expliquerons ce que sont les « patch logs » dans les chapitres suivants.

Initialiser une arborescence ne change pas une archive

Jusqu'à présent, nous avons seulement déclaré l'arborescence du projet en tant que source : nous n'avons pour l'instant rien stocké de nouveau dans cette archive. Nous y viendrons. Mais avant de faire cela, il y a un sujet important qui doit être abordé : les inventaires de sources (source inventories). Nous verrons cela dans le chapitre suivant.

Comment gérer une erreur avec init-tree ?

Supposons que dans l'exemple ci-dessus, nous ayons fait une erreur de frappe :

% tla init-tree hello-world--mainlin--0.1

Une solution « brutale » consisterait à simplement effacer le sous-répertoire {arch} et recommencer. Cependant, à terme, cette solution n'est pas souhaitable : le sous-répertoire {arch} peut contenir des informations que vous ne souhaitez pas perdre. Nous profiterons donc de cette occasion pour introduire quelques commandes avancées.

L'erreur dans la commande init-tree pose deux problèmes. Le résultat des deux commandes suivantes ne donne pas ce à quoi nous nous attendons :

% tla tree-version
lord@emf.net--2003-example/hello-world--mainlin--0.1

% tla log-versions
lord@emf.net--2003-example/hello-world--mainlin--0.1

On peut changer la tree-version d'une arborescence à n'importe quel moment :

% tla set-tree-version hello-world--mainline--0.1

% tla tree-version
lord@emf.net--2003-example/hello-world--mainline--0.1

Gérer les « patch logs » est un peu plus compliqué. Nous devons ajouter les logs que nous voulons...

% tla add-log-version hello-world--mainline--0.1

% tla log-versions
lord@emf.net--2003-example/hello-world--mainlin--0.1
lord@emf.net--2003-example/hello-world--mainline--0.1

... et effacer ceux que ne souhaitons pas conserver :

% tla remove-log-version hello-world--mainlin--0.1

% tla log-versions
lord@emf.net--2003-example/hello-world--mainline--0.1

Attention!

remove-log-version est une commande dangereuse. Elle effacera les « patch logs » dont vous pourriez avoir besoin. On devrait utiliser remove-log-version en étant certain, comme nous l'étions dans le cas ci-dessus, que ce qui est supprimé est ce que nous ne souhaitons pas conserver.

Comment ça marche ? -- Initialiser une nouvelle arborescence

init-tree a créé le sous-répertoire {arch} à la racine de l'arborescence. Qu'y a-t-il dedans ?

% ls {arch}
++default-version       =tagging-method         hello-world

% cat {arch}/++default-version
lord@emf.net--2003-example/hello-world--mainline--0.1

% cat {arch}/=tagging-method
[... long output ...]

{arch}/hello-world est la racine d'une arborescence assez profonde. Les « patch logs » sont stockés dans cette arborescence.

{arch}/=tagging-method est un fichier de configuration que vous pouvez utiliser pour personnaliser la procédure de nommage (naming conventions) qui s'applique à cette arborescence. Cela est expliqué dans un chapitre suivant (voir « Personnaliser les procédures de nommage de l'inventaire »).

Note

On ne devrait évidemment pas éditer le contenu de {arch} à la main.

Inventaires d'arborescence de projet

Attention!

Les concepts et les commandes présentés dans ce chapitre risquent de vous être peu familières, même si vous avez déjà utilisé d'autres systèmes de contrôle de révision. Ces commandes sont en fait vraiment simples une fois qu'on dépasse l'obstacle de leur apprentissage -- puis par la suite deviennent très pratiques.

Le concept d'inventaire par nom

(The Name-based inventory Concept)

Dans une arborescence de projet, certains fichiers et répertoires « font partie du code source » -- ils intéressent particulièrement arch. D'autres fichiers peuvent être des fichiers temporaires (scratch files), des sauvegardes générées par votre éditeur de texte et des fichiers temporaires (ou intermédiaires) générés par vos programmes. Ces fichiers devraient être ignorés ou traités spécifiquement par la plupart des commandes de arch.

Ce chapitre étudie comment arch reconnaît les fichiers auxquels il lui faut prêter attention et ceux qu'ils peut ignorer.

La commande d'inventaire

On utilise la commande tla inventory --names --source pour afficher une liste de fichiers sources telle que déterminée par la convention de nommage. Cette commande reconnaît de nombreuses options, notamment les options qui permettent d'afficher d'autres types de de fichiers (telles que les listes de tous les fichiers de sauvegarde générés par l'éditeur de texte, ou une liste de tous les fichiers qui ne sont pas liés au code source).

Supposons qu'après l'avoir édité, notre arborescence ait cet air là :

% ls
hw.c            hw.c.~1~        main.c          {arch}

Le fichier hw.c.~1~ est un fichier de sauvegarde de l'éditeur de texte. tla le sait et omet ce fichier dans l'inventaire des sources :

% tla inventory --names --source
./hw.c
./main.c

tla peut afficher d'autres listes :

% tla inventory --names --backups
./hw.c.~1~

Les conventions de nommage de arch

Cette section décrit les conventions de nommage par défaut utilisées par arch pour sélectionner les fichiers sources et les distinguer des autres types de fichiers. Dans un prochain chapitre nous décrirons comment personnaliser ces procédures pour une arborescence particulière (voir : « Personnaliser la convention de nommage de l'inventaire »).

La convention de nommage est basée sur plusieurs catégories de fichiers :

. et .. sont simplement ignorés par arch
excluded
(exclusions)
Les fichiers exclus sont normalement omis lors de l'affichage de l'inventaire, mais si l'option --all est passée à la commande inventory, ces fichiers sont alors rangés dans une des catégories suivantes et inclus dans la liste.
source Ce sont les fichiers sources apparents.
precious
(précieux)
Fichiers non sources qui ne doivent pas être automatiquement effacés
junk
(poubelle)
Fichiers non sources qui peuvent être effacés automatiquement
backups
(sauvegardes)
Ce sont les fichiers non sources qui peuvent être automatiquement effacés, mais tout programme qui les efface devrait les traiter comme des fichiers de sauvegarde d'éditeur de texte (c'est-à-dire conserver le plus ancien et le plus récent des deux).
unrecognized
(inconnus)
Ce sont les fichiers qu'arch ne sait pas classer -- ils ne remplissent aucune des procédures de nommage ou ont des noms qui paraissent « suspects ».

L'algorithme de classification des fichiers par nom a plusieurs règles. Pour chaque nom de fichier, chacune de ces règles est vérifiée dans l'ordre listé ci-dessus. La première règle rencontrée qui correspond au classement est alors utilisée.

Fichiers exclus (dot files)
Les fichiers spéciaux . et .. sont toujours exclus des inventaires.
Les noms « non compatibles » (non portable) ne sont pas reconnus
Les noms de fichiers qui contiennent des espaces, des caractères non imprimables ou un « globbing-character » sont toujours classés comme non reconnus. Les « globbing-characters » sont :
? [ ] * \
Test des fichiers exclus
Si l'option --all n'est pas passée à la commande inventory, les noms de fichiers qui correspondent au motif d'exclusion sont exclus de la liste. Si le nom d'un répertoire est exclu, son contenu est également exclu. Par défaut, le motif d'exclusion des fichiers correspond au fichiers de contrôle créés par arch lui-même :
^(.arch-ids|\{arch\})$
Test des fichiers poubelles
Tous les noms de fichiers qui atteignent cette étape et qui commencent avec deux virgules (,,) sont classés comme « à jeter » (junk). Les fichiers temporaires créés par arch lui-même commencent par deux virgules. Par défaut, ce motif correspond aux noms de fichiers qui commencent par (au moins) une virgule :
^,.*$

Astuce

Par ailleurs, ce motif par défaut donne lieu à une astuce pratique. Si on a besoin de créer un fichier d'essai dans une arborescence, on peut lui donner un nom qui commence par une virgule.

Test des fichiers de sauvegardes
Par défaut, tout fichier qui atteint cette étape et qui correspond au motif suivant est considéré comme un fichier de sauvegarde :
^.*(~|\.~[0-9]+~)$
^.*\.bak|\.orig|\.rej|\.original|\.modified|\.reject)$
Test des fichiers précieux
Par défaut, tout fichier qui atteint cette étape et qui correspond au motif suivant :
^\+.*$
^(\.gdbinit|\.#ckpts-lock)$
^(=build\.*|=install\.*)$
^(CVS|CVS\.adm|RCS|RCSLOG|SCCS|TAGS)$
Test des fichiers suspects (non reconnus)
Certains noms de fichiers qui atteignent cette étape sont explicitement traités comme « non reconnus » en présumant qu'ils ne devraient probablement pas être présents dans une arborescence. Par défaut, les noms qui se terminent par une des extensions suivantes sont « non reconnus » :
.o
.a
.so
.core

Par ailleurs, le nom de fichier « core » est (par défaut) traité comme « non reconnu ».

Test des fichiers sources
Les fichiers qui atteignent cette étape sont comparés au motif des fichiers sources. Le motif par défaut est montré ci-dessous. On devrait noter que ce motif chevauche celui qui correspond aux fichiers « exclus » donné plus haut. Si l'option --all est passée à la commande inventory, le motif « exclus » n'est pas activé et les fichiers qui y correspondent « retombent » à une étape ultérieure de cet algorithme.
^([_=a-zA-Z0-9].*|\.arch-ids|\{arch\}|\.arch-project-tree)$

En d'autres termes, par défaut, les fichiers et les répertoires de contrôle d'arch sont les sources (si ils ne sont pas exclus). Les fichiers qui commencent par des lettres, des nombres, des underscores ou un signe équivalent sont des fichiers sources.

Fichiers non reconnus
Tout fichier laissé à cet étape est traité comme « non reconnu ».

Exemples de conventions de nommage

En s'appuyant sur notre exemple nous pouvons illustrer quelques-unes des conventions de nommage de fichiers.

Souvenez-vous que notre arborescence de projet a l'aspect suivant :

% ls
hw.c                hw.c.~1~        main.c          {arch}

Donc la liste standard des sources donne :

% tla inventory --names --source
./hw.c
./main.c

Et la liste de tous les fichiers sources (sans en exclure aucun) donne :

% tla inventory --names --source --all
./hw.c
./main.c
./{arch}/.arch-project-tree
./{arch}/=tagging-method

On peut inclure les répertoires dans la liste :

% tla inventory --names --source --all --both
./hw.c
./main.c
./{arch}
./{arch}/.arch-project-tree
./{arch}/=tagging-method
./{arch}/hello-world
./{arch}/hello-world/hello-world--mainline
[... sortie interrompue ...]

On peut aussi regarder les listes de fichiers non sources :

% tla inventory --names --backups
./hw.c.~1~

La commande inventory a de nombreuses options qu'on pourra explorer.

Personnaliser la convention de nommage

On peut modifier les motifs utilisés par inventory pour classer les fichiers. Ceci est expliqué dans un chapitre ultérieur (« Adaptation de la convention de nommage dans l'inventaire »).

À quoi bon tout cela ? -- Conventions de nommage d'inventaire

De nombreux systèmes fournissent des conventions de nommage pour reconnaître les fichiers sources mais les utilisateurs qui débutent avec arch se demandent souvent pourquoi arch a besoin de tant de catégories de fichiers. Souvenons-nous que arch utilise les catégories :

excluded
source
precious
junk
backups
unrecognized

Chaque catégorie est explicitée ci-dessous.

excluded
Est simplement là pour faire en sorte que les listes d'inventaires restent brèves, entendu que, dans la plupart des cas, les fichiers de contrôle de arch ne sont pas particulièrement utiles. C'est un peu pareil que le traitement des répertoires . et .. (dot files) par ls; de même l'option --all de la commande inventory est similaire à l'option -a de la commande ls.
source
Permet à arch de distinguer ces fichiers de manière fiable. Par exemple, lorsqu'il compare deux arborescences, arch ne compare que les fichiers de la catégorie source.
precious
Ces fichiers sont ceux pour lesquels arch devrait faire un effort afin de les préserver. Par exemple, si vous demandez à arch de faire une copie d'une arborescence de projet, il copiera les fichiers « précieux » en même temps que les fichiers « sources ». Supposons, par exemple, que vous prenez des notes pendant que vous travaillez sur votre code source. On ne souhaitera pas que nos notes soient prises pour nos sources, mais on ne voudra pas pour autant les perdre. Une astuce consiste à donner à ce fichier un « nom précieux » (par exemple : +notes).
junk

Il est souvent utile, lorsqu'on travaille sur un projet, de créer des fichiers « à effacer ». On pourrait vouloir compiler un petit programme de test ou sauvegarder, pour un moment, la sortie d'une commande. Lorsqu'on a accumulé plusieurs de ces fichiers à effacer, il peut être pratique de pouvoir s'en débarrasser d'un seul coup, sans avoir à méticuleusement les identifier et déterminer lequel jeter, lequel conserver. Les fichiers « junk » sont parfaits pour ça. Quand on crée un de ces fichiers à effacer, on lui donne un nom du type ,foo. Plus tard, on pourra tranquillement passer des commandes du type :

% rm ,*

% find . -name ',*' | xargs rm

% tla inventory --junk | xargs rm

Du point de vue de arch, les fichiers « junk » ont deux caractéristiques importantes. Tout d'abord, lorsqu'on copie une arborescence, les fichiers à effacer ne sont pas copiés. Ensuite, on considère comme sécurisant pour arch de pouvoir écraser un fichier à effacer. En fait, arch écrasera un fichier à effacer si ce nom de fichier commence par : ,.

backups

Les fichiers de sauvegardes des éditeurs de texte, ainsi que les fichiers de sauvegarde créés par les programmes tels que patch sont souvent traités de manière particulière. Par exemple, si votre éditeur crée des sauvegardes numérotées (numbered backups), ceux-ci sont presque des fichiers à effacer. Mais plutôt que de tous les effacer, on pourrait vouloir n'en effacer que certains.

Pour arch ce qui est important c'est que lors d'une copie d'arborescence, les fichiers de sauvegarde ne devraient pas être copiés. Pour les utilisateurs, ce qui est probablement le plus efficace est d'utiliser l'astuce suivante, qui n'effacera pas les fichiers de sauvegarde :

% tla inventory --junk | xargs rm
unrecognized
L'apparence d'un fichier qui ne correspond à aucun motif d'une arborescence (ou qui a un nom suspect) indique la plupart du temps que quelque chose n'est pas correct. Plutôt que d'ignorer ces fichiers ou de les traiter comme des fichiers précieux ou à effacer, arch les marque explicitement afin de pouvoir en avertir les utilisateurs.

Adopter les conventions de nommage des fichiers est une discipline que de nombreux programmeurs peuvent trouver inhabituelle, mais nous la recommandons pourtant fortement. Il est simple de suivre ces conventions et les outils tels que inventory et tree-lint (qui seront présentés plus tard) vous aideront à maintenir vos sources en évitant que leur contrôle vous échappe.

Identifiants d'inventaire des sources

Attention!

Passage difficile à appréhender Comme dans les chapitres précédents, les concepts et commandes introduites ici peuvent ne pas vous être familiers, même si vous avez l'habitude d'autres systèmes de contrôles de versions. En revanche, une fois que vous aurez « saisi », cela vous semblera assez naturel. La bonne nouvelle, c'est qu'il s'agit de la dernière étape subtile avant de pouvoir stocker l'arborescence dans l'archive.

L'air d'un source ou source réel

Dans les chapitres précédents, nous avons vu comment trouver les fichiers par rapport à la convention de nommage :

% tla inventory --names --source
hw.c
main.c

Dans ce chapitre, il y a une nouvelle distinction : les fichiers qui ont l'air d'un source par rapport à leur nom, par rapport aux fichiers réellement sources.

Lorsque vous archivez votre projet dans l'archive, arch va stocker les fichiers qui sont réellement des sources et ignorer le reste. Nous pouvons demander quels sont les fichiers sources réels en omettant l'option --names de inventory :

% tla inventory --source
[no output]

C'est un peu plus intéressant si on inclut les propres fichiers de arch « fichiers et répertoires systèmes » dans le listing :

% tla inventory --source --all --both
{arch}
{arch}/.arch-project-tree
{arch}/=tagging-method
{arch}/hello-world
[....]

Mais ce qu'il faut noter ici c'est que hw.c et main.c ne sont pas listés. Arch pense que ce sont des sources par le nom seulement. La prochaine section indique le moyen de corriger ça, et la section d'après explique ce qui se passe réellement.

La commande add

Nous pouvons indiquer à arch que nos fichiers sont réellement des sources, et qu'ils doivent donc être archivés avec le projet, en utilisant la commande tla add :

% tla add hw.c
% tla add main.c

Et maintenant nous pouvons obtenir une meilleure réponse à :

% tla inventory --source
hw.c
main.c

Une commande complémentaire est tla delete :

% tla delete hw.c

Cela n'efface pas le fichier hw.c lui-même :

% ls
hw.c            hw.c.~1~        main.c          {arch}

mais ça l'efface de la liste officielle des sources :

% tla inventory --source
main.c

Pour la poursuite de nos exemples, nous devons remettre hw.c dans la liste :

% tla add hw.c

% tla inventory --source
hw.c
main.c

Regardons plus en profondeur ce qui se passe lorsque nous ajoutons des fichiers avec tla add.

Deux noms pour chaque fichier

Dans le monde de arch, chaque fichier source (et répertoire) de notre arborescence a deux noms : un « chemin d'accès » (file path) et un « identifiant d'inventaire » (inventory id).

Le « chemin d'accès » du fichier est le chemin relatif du fichier par rapport à la racine de l'arborescence. Il décrit le fichier est placé dans l'arborescence.

L'« identifiant d'inventaire » du fichier est (généralement) une chaîne arbitraire unique du fichier dans l'arborescence. L'identifiant d'inventaire reste constant même si le fichier est renommé. Ainsi, alors que le chemin d'accès indique où le fichier est placé, l'identifiant d'inventaire indique quel fichier est stocké à cet endroit.

Le but de tla add est d'assigner un identifiant d'inventaire à un fichier.

Dans notre exemple, nous pouvons examiner les identifiants :

   % tla inventory --source --ids
   hw.c    x_very_long_string
   main.c  x_another_very_long_string
   ^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                |
    |           inventory ids
file paths

Généralement, quand un fichier est déplacé, son emplacement change, mais son identifiant d'inventaire reste le même. La commande tla move nous aide pour cela. Supposons que nous fassions :

% mv hw.c hello.c

nous devrions faire ensuite :

% tla move hw.c hello.c

après quoi :

% tla inventory --source --ids
hello.c   x_very_long_string
main.c    x_another_very_long_string

Notez que hello.c a le même identifiant que celui que hw.c avait.

Nous reviendrons sur ce sujet du changement de nom plus tard, pour l'instant, revenons où nous avions démarré :

% mv hello.c hw.c
% tla move hello.c hw.c

Section rapide -- ajout de répertoires

La commande tla add peut s'appliquer aux répertoires également. Si nous avions ajouté un nouveau répertoire à l'arborescence, nous devrions l'ajouter par tla add :

% mkdir docs

% tla inventory --names --source --both
docs
hw.c
hello.c

mais

% tla inventory --source --both
hw.c
hello.c

jusqu'à

% tla add docs

et ensuite

% tla inventory --source --both
docs
hw.c
hello.c

Mais, à nouveau, pour la poursuite de notre exemple, nous n'avons pas besoin de docs. Nous pouvons faire simplement :

% rm -rf docs

Il n'est pas nécessaire d'utiliser tla delete pour un répertoire physiquement effacé.

Comment ça marche ? -- tla add

Ce que fait tla add est assez simple. Notez que quand nous avons ajouté hw.c et main.c, un nouveau répertoire a été créé :

% ls -a
.               .arch-ids       hw.c.~1~        {arch}
..              hw.c            main.c

.arch-ids est un nouveau répertoire :

% ls .arch-ids
hw.c.id         main.c.id

% cat .arch-ids/hw.c.id
very long string

Les données déterminant l'identifiant des fichiers sont stockées dans les fichiers *.id. La commande tla delete efface ces fichiers. La commande tla move les renomme.

L'identifiant d'un répertoire est stocké un peu différemment. Par exemple, quand nous avions créé le sous-répertoire docs et que l'avions ajouté avec tla add, cela a créé un fichier docs/.arch-ids/=id.

Garder les choses ordonnées et rangées

La commande :

% tla tree-lint

est utile pour garder les choses ordonnées et rangées.

tree-lint vous indiquera les identifiants pour lesquels le fichier n'existe pas. Il vous indiquera quels sont les fichiers qui passent la convention de nommage, mais pour lesquels il n'y a pas d'identifiant.

Il va également vous alerter pour les fichiers qui ne suivent pas la convention de nommage.

Identifiants d'inventaire -- Plusieurs façons de procéder

« there is more than one way to do it »

Dans ce chapitre, vous avez appris les commandes de base add, move, et delete.

Ces outils pour gérer les identifiants d'inventaire ont été choisis pour leur ressemblance, du moins superficielle, avec les commandes des systèmes tels que CVS dont de nombreux utilisateurs sont familiers.

Il y a d'autres façons de gérer les identifiants d'inventaires. Parfois les autres méthodes sont plus adaptées. Un chapitre supplémentaire devrait parler de ces techniques...

Pourquoi est-ce comme cela ? -- Le but des identifiants d'inventaire

Comme vous le verrez dans les chapitres suivants, arch est pratique pour gérer les modifications effectuées sur les arborescences et les fichiers qu'elles contiennent, et pratique pour vous indiquer l'historique des arborescences et fichiers.

Comme exemple, supposons qu'Alice et Bob soient tous les deux en train de travailler sur le projet hello-world. Dans son arborescence, Alice effectue quelques modifications sur hw.c. Dans son arborescence, Bob renomme hw.c en hello.c.

À un moment donné il est nécessaire de « synchroniser » Alice et Bob. Bob doit récupérer les modifications qu'Alice a effectuées. Alice doit récupérer le fichier renommé par Bob.

Arch fournit plusieurs mécanismes pour synchroniser -- c'est une des choses les plus importantes qu'il peut faire -- mais pratiquement toutes aboutissent au calcul et à l'application d'un changeset.

Alice peut demander à arch de créer un changeset décrivant le travail qu'elle a effectué, et ce changeset décrira les modifications qu'elle a apportées à hw.c. Bob peut créer un changeset et ce changeset décrira le renommage qu'il a effectué.

Si Alice applique le changeset de Bob à son arborescence, sa copie de hw.c devrait être renommée en hello.c. Mais un cas plus subtile est celui-ci : que ce passe-t-il si Bob applique le changeset d'Alice à son arborescence ?

Alice a modifié un fichier nommé ./hw.c, mais dans l'arborescence de Bob, cette même modification devrait être appliquée à un fichier nommé ./hello.c. Heureusement, ces deux fichiers ont le même identifiant d'inventaire :

file path               inventory id
---------               -------------

         Alice's tree:
./hw.c                  x_very_long_string
                                          \
                                           - the same long string
         Bob's tree:                      /
./hello.c               x_very_long_string

Dans le changeset d'Alice, les modifications sont décrites comme ayant été effectuées sur le fichier dont l'identifiant est x_very_long_string.

Ensuite, lorsqu'il est appliqué sur l'arborescence de Bob, arch sait qu'il faut appliquer les modifications sur le fichier ayant le même identifiant ; il sait donc que les modifications s'appliquent sur ./hello.c.

Cet exemple illustre l'utilité des identifiants d'inventaire : ils permettent à arch de décrire les modifications effectuées sur une arborescence en terme d'identité logique des fichiers plutôt que de leur emplacement physique. Il y a bien d'autres exemples plus complexes de l'utilisation des identifiants d'inventaire, mais maintenant vous avez vu le principe de base.

Pourquoi est-ce comme cela ? -- Pourquoi tla move ne déplace pas les fichiers ?

Pourquoi tla delete n'efface pas le fichier de l'arborescence ou tla move ne le renomme pas ?

Ces commandes permettent d'ajuster les identifiants dans une arborescence même si d'autres outils qui ne connaissent pas arch ont réarrangé les fichiers. Par exemple, si vous utilisez un « gestionnaire de fichiers » pour renommer vos fichiers, tla move sera toujours capable de prendre en compte les changements que le gestionnaire a effectué.

Cependant, il y a maintenant deux commandes qui modifient en même temps les identifiants et les fichiers correspondants : tla mv et tla rm. Elles fonctionnent comme leurs équivalents UNIX, avec en plus la gestion de l'identifiant.

Importer la première révision

Mémo : si vous avez suivi les exemples des chapitres précédents, nous avons maintenant :

Votre identifiant arch

Dans « Faire les présentations », vous avez créé votre première archive et fait en sorte qu'elle soit celle par défaut. Dans « Commencer un nouveau projet » vous avez ajouté le projet hello-world à cette archive.

Votre arborescence initiale

Dans « Démarrer une nouvelle arborescence » vous avez commencé en initialisant les sources pour hello-world comme un projet arch et dans « Identifiants d'inventaire des sources » vous avez attribué des identifiants aux fichiers sources de ce projet.

Maintenant c'est enfin le moment d'importer les sources de hello-world dans l'archive. Cela va se dérouler en deux étapes : (1) créer un fichier de log; (2) importer les sources.

Créer le premier fichier de log

Vous êtes sur le point de créer une nouvelle « révision » de hello-world dans votre archive : un enregistrement de ce projet à un instant donné.

Lorsque vous créez une révision, la première étape consiste à créer un fichier de log pour cette révision :

% cd ~/wd/hello-world

% tla make-log
++log.hello-world--mainline--0.1--lord@emf.net--2003-example

La sortie de cette commande est le nom d'un fichier que nous devons éditer. Au départ il contient :

Summary:
Keywords:

Vous devriez remplir ce fichier comme vous le feriez pour un email. Ajouter une description succinte de la révision dans le champ « Summary: », et une description complète dans le corps du message. Exactement comme un email, le corps du texte doit être séparé de l'entête par une ligne vide. Lorsque c'est fait, le log doit avoir cet aspect :

Summary: initial import
Keywords:

Ceci est l'importation initiale de « hello-world »,
l'application qui tue tout et qui propulsera votre nouvelle
boite .com au zénith du succès.

Note

Pour les fans de vi : Le nom du fichier par défaut pour les messages de log commence avec le caractère +. vi est un programme non standard dans le sens où il traite les arguments commençants par + comme des options plutôt que comme des arguments classiques. Aussi, vous devez vous assurer de bien taper le nom du fichier pour vi en commençant par ./, comme ceci :

% vi ./++log.hello-world--mainline--0.1--lord@emf.net--2003-example

ou, tout simplement :

% vi `tla make-log`

Note

Raccourci : Cette section décrit la « manière longue » pour créer le message de log de votre importation initiale. Il existe un raccourci pour vous éviter cette étape : les options -L et -s de tla import. Nous avons utilisé la manière longue mais plus tard vous devriez essayer tla import -H pour en savoir davantage sur ce racourcis.

Stocker la première révision dans l'archive

Finalement, nous pouvons demander à arch d'ajouter nos sources à l'archive :

% tla import
[....]

Note

Si vous obtenez une erreur comme « These apparent source files lack inventory ids » (il manque des identifiants d'inventaire pour des fichiers qui semblent être des sources), relisez la section « Identifiants d'inventaire des sources » et soit ajoutez chaque fichier, soit modifiez la convention de nommage.

Nous pouvons observer l'effet de bord de cette commande de plusieurs manières.

Nous pouvons demander à arch quelles révisions existent dans l'archive pour notre projet :

% tla revisions hello-world--mainline--0.1
base-0

En fait, nous pouvons obtenir plus de détails :

% tla revisions --summary --creator --date \
                  hello-world--mainline--0.1
base-0
    2003-01-28 00:45:50 GMT
    Tom (testing) Lord <lord@emf.net>
    initial import

Qu'est-ce qui a changé dans notre arborescence ? Souvenez-vous que nous avons quelque chose appelé « patch log » :

% tla log-versions
lord@emf.net--2003-example/hello-world--mainline--0.1

Maintenant il y a un message :

% tla logs hello-world--mainline--0.1
base-0

% tla logs --summary --creator --date \
               hello-world--mainline--0.1
base-0
    2003-01-28 00:45:50 GMT
    Tom (testing) Lord <lord@emf.net>
    initial import

% tla cat-log hello-world--mainline--0.1--base-0
Revision: hello-world--mainline--0.1--base-0
Archive: lord@emf.net--2003-example
Creator: Tom (testing) Lord <lord@emf.net>
Date: Mon Jan 27 16:45:50 PST 2003
Standard-date: 2003-01-28 00:45:50 GMT
Summary: initial import
Keywords:
New-files: ./hw.c ./main.c
New-patches: \
  lord@emf.net--2003-example/hello-world--mainline--0.1--base-0

Ceci est l'importation initiale de « hello-world »,
l'application qui tue tout et qui propulsera votre nouvelle
boite .com au succès.

Le nom des révisions importées

import a créé une nouvelle révision dans l'archive. Notez que cette révision est appelée base-0 et que nous pouvons former un nom plus complet de cette révision en le préfixant par la catégorie, la branche, et la version :

hello-world--mainline--0.1--base-0
^^^^^^^^^^^  ^^^^^^^^  ^^^  ^^^^^^
     |          |       |     |
     |          |       |    patch level name
     |          |       |
     |          |     version number
     |          |
     |     branch name
     |
 category name

Si nous y ajoutons le nom de l'archive, on obtient quelque chose appelé « nom pleinement qualifié de la révision » (fully qualified revision name), qui est un identifiant globalement unique de la révision :

lord@emf.net--2003-example/hello-world--mainline--0.1--base-0
^^^^^^^^^^^^^^^^^^^^^^^^^^
            |
      archive name

Les noms pleinement qualifiés vont être de plus en plus importants au fur et à mesure que vous étudierez les « dépôts répartis » dans les chapitres suivants.

Comment ça marche ? -- Que fait import ?

Regardons ce que import a fait au niveau de l'archive :

Allons dans le répertoire de notre version de travail

% cd ~/{archives}
% cd 2003-example/
% cd hello-world/
% cd hello-world--mainline/
% cd hello-world--mainline--0.1/
% ls
base-0

Il a créé un nouveau répertoire base-0 pour la nouvelle révision.

% cd base-0
% ls
+revision-lock
hello-world--mainline--0.1--base-0.src.tar.gz
log

Comme toujours, le fichier +revision-lock est utilisé par arch en interne pour garder l'archive dans un état cohérent dans toutes les circonstances.

Le fichier log est une copie du message de log que vous avez écrit, avec quelques entêtes supplémentaires :

% cat log
Revision: hello-world--mainline--0.1--base-0
Archive: lord@emf.net--2003-example
Creator: Tom (testing) Lord <lord@emf.net>
Date: Mon Jan 27 16:45:50 PST 2003
Standard-date: 2003-01-28 00:45:50 GMT
Summary: initial import
Keywords:
New-files: ./hw.c ./main.c
New-patches: \
  lord@emf.net--2003-example/hello-world--mainline--0.1--base-0

Ceci est l'importation initiale de « hello-world »,
l'application qui tue tout et qui propulsera votre nouvelle
boite .com au succès.

Finalement, le fichier compressé .tar.gz est une copie de l'arborescence de votre projet :

% tar ztf hello-world--mainline--0.1--base-0.src.tar.gz
hello-world--mainline--0.1--base-0/
hello-world--mainline--0.1--base-0/hw.c
hello-world--mainline--0.1--base-0/main.c
hello-world--mainline--0.1--base-0/{arch}/
hello-world--mainline--0.1--base-0/{arch}/.arch-project-tree
hello-world--mainline--0.1--base-0/{arch}/=tagging-method
hello-world--mainline--0.1--base-0/{arch}/hello-world/
[....]

Vous devriez noter que le fichier tar n'inclut pas tous les fichiers de votre arborescence. Il contient spécifiquement les fichiers listés par :

% cd ~/wd/hello-world

% tla inventory --source --both --all
[....]

Finalement, si vous parcourez le répertoire {arch} de votre arborescence, vous verrez deux nouvelles données :

% ls
++default-version       =tagging-method
++pristine-trees        hello-world

Le répertoire ++pristine-trees contient (à une certaine profondeur) une copie de l'arborescence que vous venez d'importer. C'est une copie mise en cache utilisée par certaines commandes de arch. (À noter : dans les prochaines versions de arch, le répertoire ++pristine-trees sera remplacé par un mécanisme différent).

Si vous creusez, dans le répertoire patch-log de hello-world, vous trouverez une copie du fichier de log de la révision que vous venez de créer (avec quelques entêtes supplémentaires).

Archiver les changements

Jusqu'à présent, si vous avez suivi les exemples, nous avons créé une nouvelle archive et un projet hello-world. Dans cette archive, nous avons importé la version initiale de hello-world.

L'opération la plus courante que vous aimerez effectuer en tant que programmeur utilisant un système de contrôle de révision est d'archiver (commit) un ensemble de modifications. Dans ce chapitre, nous verrons les méthodes les plus basiques pour effectuer cela.

warld != world\n

si vous regardez le source, vous noterez une faute d'orthographe et un bogue sur le retour à la ligne :

% cat hw.c

#include <stdio.h>

void
hello_world (void)
{
  (void)printf ("hello warld");
}

C'est clair, nous voulions dire « hello world », pas « hello warld », et nous voulions probablement un retour à la ligne à la fin du message. Réparons ces bogues maintenant.

Quelques conseils gratuits sur les messages de log

Les conseils gratuits méritent d'être payés

anonyme

Voilà le plan : nous modifierons le source pour réparer les bogues. Ensuite nous demanderons à arch d'archiver les modifications nécessaires pour réparer ces bogues. Cette seconde étape va créer une nouvelle révision dans l'archive.

Comme nous l'avons noté précédement, à chaque fois que vous créez une nouvelle révision, vous devez fournir un message de log pour cette révision (voir « Créer le premier fichier de log »).

Les bogues particuliers que nous sommes en train de réparer dans notre exemple ludique sont simplistes -- mais dans une situation réelle, ils seront sûrement plus complexes. Nous avons le choix : vous pouvez soit attendre que les modifications soient effectuées pour écrire le message de log décrivant vos changements, soit écrire le message de log au fur et à mesure.

Voici le conseil gratuit : écrivez le message de log au fur et à mesure. En d'autres termes, prenez des notes en cours de travail. Au niveau des commandes tla ça signifie que vous devez démarrer le processus de correction des bogues par :

% cd ~/wd/hello-world

tla make-log
++log.hello-world--mainline--0.1--lord@emf.net--2003-example

Ensuite éditez votre nouveau fichier de log pour y lire :

Summary: Réparation des bogues dans la chaine "hello world"
Keywords:

Le « Summary » décrit ce que vous êtes censé effectuer comme nouvelles modifications. En cours de travail, vous pouvez remplir le corps du message de log.

Le cycle modification/mise à jour du log

Mettons que ces bogues soient plus complexes qu'ils ne le sont actuellement, voilà comment le travail pourrait se dérouler :

Change warld en world.

Mise à jour du message de log.

Ajoutez une note au fichier de log :

Summary: Réparation des bogues dans la chaine "hello world"
Keywords:

Écriture correcte de "world" (et non "warld").

Ajout d'un retour à la ligne à la chaine.

Mise à jour du message de log à nouveau.

Summary: Réparation des bogues dans la chaine "hello world"
Keywords:

Écriture correcte de "world" (et non "warld").

Ajout d'une nouvelle ligne à la chaine "hello world"

Oh mon dieu -- Qu'ai-je fait ?

Vous venez juste d'effectuer un long et difficile travail pour réparer ces bogues. Ne serait-ce pas une bonne idée que de revoir ce que vous avez fait avant de le publier ?

Pas de problème, arch est là pour ça :

% tla changes --diffs
[....]
*** patched regular files

**** ./hw.c
[....]
     @@ -4,7 +4,7 @@
      void
      hello_world (void)
      {
     -  (void)printf ("hello warld");
     +  (void)printf ("hello world\n");
      }
[....]

Aha ! maintenant nous savons. C'est le moment d'archiver ces modifications.

Enregistrer les changements dans l'archive

Maintenant, enregistrons ces changements dans l'archive.

Si vous n'avez pas tenu compte de notre conseil gratuit (voir Quelques conseils gratuits sur les messages de log), c'est maintenant le moment de créer le message de log (astuce : tla make-log).

Pour sauvegarder vos changements dans l'archive, simplement :

% tla commit
[....]

Après ce commit, il y a une nouvelle révision dans l'archive.

% tla revisions hello-world--mainline--0.1
base-0
patch-1

ou, en plus détaillé :

% tla revisions --summary hello-world--mainline--0.1
base-0
    initial import
patch-1
    Réparation des bogues dans la chaine "hello world"

Notre arborescence de patch-log a également été mise à jour :

% tla logs hello-world--mainline--0.1
base-0
patch-1

% tla logs --summary hello-world--mainline--0.1
base-0
    initial import
patch-1
    Réparation des bogues dans la chaine "hello world"

Comment ça marche ? -- Archiver une nouvelle révision

Que fait commit au niveau de l'archive ?

Allons dans le répertoire de la version dans laquelle nous travaillons

% cd ~/{archives}
% cd 2003-example/
% cd hello-world/
% cd hello-world--mainline/
% cd hello-world--mainline--0.1/
% ls
+version-lock   =README         base-0          patch-1

Le sous-répertoire patch-1 est nouveau :

% cd patch-1

% ls
+revision-lock
hello-world--mainline--0.1--patch-1.patches.tar.gz
log

Comme d'habitude, le fichier de log est celui que vous avez écrit, avec quelques entêtes supplémentaires :

% cat log
Revision: hello-world--mainline--0.1--patch-1
Archive: lord@emf.net--2003-example
Creator: Tom (testing) Lord <lord@emf.net>
Date: Mon Jan 27 22:26:13 PST 2003
Standard-date: 2003-01-28 06:26:13 GMT
Summary: Réparation des bogues dans la chaine "hello world"
Keywords:
New-files: \
  {arch}/hello-world/ [....] /patch-log/patch-1
Modified-files: hw.c
New-patches: \
  lord@emf.net--2003-example/hello-world--mainline--0.1--patch-1

Écriture correcte de "world" (et pas "warld").

Ajout d'un retour à la ligne à la fin de la chaine.

Le fichier .patches.tar.gz est appelé un changeset. Il décrit les changements que vous avez effectués par les différences entre la révision base-0 et la révision patch-1. Vous en apprendrez davantage sur la nature des changesets dans les chapitres suivants. Pour l'instant, vous pouvez considérer un changeset comme un équivalent de la sortie d'un diff -r qui serait utilisé pour comparer la révision base-0 d'avant vos changements, avec l'arborescence d'après vos changements (ou, comme dirait un utilisateur de arch : un « patch set on steroids »).

Dans l'arborescence du projet :

% cd ~/wd/hello-world

La commande commit a eu deux effets. Premièrement, elle a ajouté un fichier de log dans {arch}/hello-world. Deuxièmement, elle a modifié {arch}/++pristine-trees pour contenir une copie mise en cache de la révision patch-1 à la place de la révision base-0.

Récupérer des révisions antérieures

Si vous avez suivi les exemples des chapitres précédents jusqu'ici, vous devriez avoir :

Votre première archive

qui est également votre archive par défaut :

% tla my-default-archive
lord@emf.net--2003-example

% tla whereis-archive lord@emf.net--2003-example
/usr/lord/examples/{archives}/2003-example

Deux révisions du projet hello-world

% tla revisions hello-world--mainline--0.1
base-0
patch-1

Dans ce chapitre, vous apprendrez comment récupérer les révisions d'une archive.

Récupérer la dernière révision

Vous devriez également avoir une arborescence en plus. Si c'est le cas, débarrassons-nous en :

% cd ~/wd

% ls
hello-world

% rm -rf hello-world

Supposons maintenant que vous vouliez récupérer les derniers sources du projet hello-world. Pour cela, vous utiliserez la commande get :

% tla get hello-world--mainline--0.1 hello-world
[...]


% ls
hello-world

% ls hello-world
hw.c    main.c  {arch}

Récupérer une révision antérieure

Supposons que nous voulions récupérer une version antérieure du projet hello-world.

Notez que dans l'exemple précédent, nous avons simplement demandé une version particulière du projet :

% tla get hello-world--mainline--0.1 hello-world
          ^^^^^^^^^^^  ^^^^^^^^  ^^^ ^^^^^^^^^^^
               |           |      |       |
               |           |      |  target directory
               |           |      |
               |           |      |
               |           |   version number
               |           |
               |      branch name
               |
         category name

Nous pouvons récupérer une version antérieure en spécifiant son niveau de patch explicitement :

% tla get hello-world--mainline--0.1--base-0 hello-world-0
          ^^^^^^^^^^^  ^^^^^^^^  ^^^  ^^^^^^ ^^^^^^^^^^^^^
               |           |      |      |        |
               |           |      |      |  target directory
               |           |      |      |
               |           |      | patch level name
               |           |      |
               |           |   version number
               |           |
               |      branch name
               |
         category name


% ls
hello-world     hello-world-0

% ls hello-world-0
hw.c    main.c  {arch}

Vous pouvez voir les modifications effectuées entre base-0 et patch-1 avec, par exemple, diff -r :

% diff -r hello-world-0 hello-world
diff -r hello-world-0/hw.c hello-world/hw.c
7c7
<   (void)printf ("hello warld");
---
>   (void)printf ("hello world\n");
[...]

Comment ça marche ? -- Récupérer une révision avec get

Récupérer la révision base-0 est facile. Comme on s'en souvient, la révision base-0 est stockée dans un fichier tar compressé contenant l'arborescence complète (voir « Comment ça marche ? -- que fait import »). Quand vous demandez la récupération base-0, la commande get extrait simplement l'arborescence du fichier tar.

Récupérer la révision patch-1 se déroule en deux étapes. Souvenez-vous que patch-1 est stocké comme un changeset qui décrit les différences entre base-0 et patch-1 (voir « Comment ça marche ? -- enregistrer une nouvelle révision »). Néanmoins, get procède en récupérant la révision base-0, et ensuite récupère le changeset patch-1, puis utilise ce changeset pour modifier l'arborescence base-0 qui devient alors l'arborescence patch-1. En interne, get utilise la commande tla dopatch pour appliquer le changeset. Mais si vous êtes familier avec les patchsets diff/patch, vous pouvez considérer dopatch comme un patch on steroids.

Supposons qu'au lieu d'archiver simplement un changement vous en ayez archivé plusieurs : pas seulement la révision patch-1, mais patch-2, patch-3 et ainsi de suite. En l'occurrence, get va appliquer chaque changeset dans l'ordre pour créer la révision demandée.

Note

En fait, get est un petit peu plus compliqué que ce qui est décrit ici. D'une part, certaines optimisations peuvent éviter à get d'appliquer une longue liste de changesets. D'autre part, il peut y avoir des révisions créées par tag au lieu de commit, pour lesquelles différentes règles s'appliquent. Vous en apprendrez plus sur ces exceptions dans les prochains chapitres.

Archives partagées et publiques

Dans les chapitres précédents, vous avez appris à créer votre première archive, démarrer un projet, récupérer l'arborescence initiale et les modifications consécutives, et récupérer les révisions précédentes.

Dans ce chapitre vous allez apprendre à créer une archive disponible sur le réseau et vous initier au partage d'archive entre plusieurs développeurs.

Inscrire une archive pour un accès en réseau

Souvenez-vous, une archive a à la fois un nom logique et un emplacement physique.

% tla archives
lord@emf.net--2003-example
^^^^^^^^^^^^^^^^^^^^^^^^^^
  |     /usr/lord/{archives}/2003-example
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |                     |
  |              archive location
  |
archive name

(voir « créer une nouvelle archive »)

Certaines archives peuvent être accessibles à travers le réseau, pour l'instant à partir des protocoles suivants :

FTP
SFTP
WebDAV
plain HTTP

Plus loin dans ce chapitre, vous apprendrez comment créer de telles archives.

Pour l'instant, vous devez savoir que pour accéder à une telle archive, vous devez inscrire son nom et son emplacement physique, en utilisant une URL pour l'emplacement physique.

Par exemple, pour accéder à une archive par HTTP ou WebDAV :

% tla register-archive lord@emf.net--2003b \
        http://regexps.srparish.net/{archives}/lord@emf.net--2003b

ou par FTP :

% tla register-archive lord@regexps.com--2002 \
        ftp://ftp.regexps.com/{archives}/lord@regexps.com--2002

Vous pouvez voir que ces commandes ont eu un effet :

% tla archives
lord@emf.net--2003b
        http://regexps.srparish.net/{archives}/lord@emf.net--2003b
lord@emf.net--2003-example
        /usr/lord/examples/{archives}/2003-example
lord@regexps.com--2002
        ftp://ftp.regexps.com/{archives}/lord@regexps.com--2002

Travailler avec plusieurs archives à la fois

Après avoir enregistré de nouvelles archives, comment y accéder ?

La manière la plus simple est de rendre l'archive souhaitée comme archive par défaut.

% tla my-default-archive lord@emf.net--2003

% tla categories
[...categories de l'archive distante...]

Il n'est pas toujours souhaitable de changer l'archive par défaut. Pour l'instant, remettons par défaut l'archive que l'on a utilisée pour les exemples.

% tla my-default-archive lord@emf.net--2003-example

Sélectionner une archive avec -A

Toutes les commandes qui opèrent sur des archives acceptent l'option -A qui permet d'outrepasser la valeur par défaut :

% tla my-default-archive
lord@emf.net--2003-example

% tla categories -A lord@emf.net--2003
[... categories de lord@emf.net--2003 ...]

Note

L'option -A a priorité par rapport à l'archive par défaut mais est surpassée par un nom de projet pleinement qualifié (voir ci-après).

Nom de projet pleinement qualifié

Les commandes qui acceptent un nom de projet prennent en compte l'utilisation d'un nom pleinement qualifié. C'est à dire formé en faisant précéder le nom du projet par le nom de l'archive suivie d'une barre oblique.

category name:
tla                     => lord@emf.net--2003/tla

branch name:
tla--devo               => lord@emf.net--2003/tla--devo

version name:
tla--devo--1.0          => lord@emf.net--2003/tla--devo--1.0

revision name:
tla--devo--1.0--patch-1 => lord@emf.net--2003/tla--devo--1.0--patch-1

Dans cet exemple :

% tla my-default-archive
lord@emf.net--2003-example

% tla branches lord@emf.net--2003/hello-world
[... branches de hello-world dans lord@emf.net--2003 ...]

Note

Un nom de projet pleinement qualifié est prioritaire sur l'option -A et l'archive par défaut.

Archives en lecture seule

Le système d'exploitation et les contrôles d'accès au niveau du serveur peuvent être utilisés pour limiter l'accès à certains ou à tous les utilisateurs en lecture seule. Par exemple, FTP est généralement configuré pour que les utilisateurs anonymes puissent lire, mais pas modifier l'archive.

Créer des miroirs locaux, distants, et des archives distantes

Un « miroir » est une archive dont le contenu est dupliqué à partir d'une autre archive. Vous ne pouvez pas archiver vers un miroir de la manière habituelle, vous pouvez seulement mettre à jour cette copie à partir de sa source.

Il y a deux utilisations principales des miroirs d'archives : une est de faire une copie locale d'un miroir distant (pour pouvoir accéder à son contenu sans passer par le réseau); l'autre est de faire une copie distante d'une archive locale (pour que d'autres puissent y accéder).

Créer un miroir local d'une archive distante

Supposons que, pour avoir un accès le plus rapide possible, ou pour pouvoir travailler dessus en étant déconnecté, vous vouliez créer un miroir local d'une archive distante pour y accéder localement plutôt que par le réseau.

Supposons que vous vouliez le faire avec lord@emf.net--2003b, il y a trois étapes (supposons que $remote_location soit quelque chose du genre http://my.site.com//archives/lord@emf.net--2003b).

Premièrement, enregistrer l'archive distante sous un nouveau nom, formé en ajoutant -SOURCE à son nom :

% tla register-archive lord@emf.net--2003b-SOURCE $remote_location

Ensuite, créer le miroir local :

% tla make-archive --mirror-from lord@emf.net--2003b-SOURCE $local_location

Cette commande va en même temps inscrire lord@emf.net--2003b comme nom du miroir local.

Une fois que l'archive distante a été inscrite, vous pouvez mettre à jour votre miroir en répétant l'étape tla archive-mirror.

Si vous ne voulez pas créer un miroir de l'archive entière, vous pouvez en option limiter le miroir à certaines catégories, branches, ou versions. (voir tla archive-mirror -H).

Créer un miroir distant d'une archive locale

Supposons que vous ayez une archive locale mine@somewhere.com, et que vous souhaitiez « publier » un miroir de cette archive sur Internet pour que d'autres puissent la lire.

Admettons que vous ayez déjà inscrit mine@somewhere.com, vous pouvez créer un miroir distant avec :

% tla make-archive --mirror mine@somewhere.com $remote_location

Arch va écrire directement sur $remote_location, il faut donc y avoir un accès en écriture comme avec SFTP, mais pas comme avec HTTP.

Vous pouvez initialiser ou mettre à jour le contenu de ce miroir distant avec :

% tla archive-mirror mine@somewhere.com

Une situation courante pour de nombreuses personnes est de pouvoir installer des fichiers statiques sur un site web, mais sans pouvoir y fournir un accès WebDAV. Même dans ces conditions, vous pouvez toujours publier une archive arch avec, cependant, quelques subtilités.

Premièrement, lors du make-archive, vous devez utiliser une option supplémentaire :

% tla make-archive --listing --mirror mine@somewhere.com \
                $remote_location

L'option --listing permet de conserver un fichier .listing à jour sur le miroir, ce qui permet, du coup, d'autoriser les gens à accéder à l'archive à partir d'un simple HTTP (sans le support WebDAV).

Deuxièmement, il peut arriver que le fichier .listing ne soit plus à jour (par exemple, si vous tuez une commande archive-mirror au mauvais moment. Si vous savez ou si vous soupçonnez que c'est arrivé, vous pouvez réparer l'archive en question en lançant archive-fixup comme dans notre exemple :

% tla archive-fixup mine@somewhere.com-MIRROR

Créer un dépôt distant

Même si la création de miroir est courante pour les dépôts distants, il est possible de créer un dépôt distant qui ne soit pas un miroir, et ainsi pouvoir archiver sur celui-ci directement.

On peut créer un dépôt distant avec cette commande :

% tla make-archive $archive_name $remote_location

Ou créer un dépôt distant avec un fichier .listing :

% tla make-archive --listing $archive_name $remote_location

Mélanger des modes d'accès différents

Rien n'empêche de rendre une archive disponible à partir de méthodes différentes. Par exemple, vous pouvez rendre une archive de votre système de fichier local accessible par FTP, vous devrez indiquer aux autres utilisateurs de l'inscrire en tant que FTP (avec une url ftp:)

Coopération à base de update/commit

Dans les chapitres précédents, vous avez appris à ajouter un projet à une archive, archiver l'arborescence initiale, archiver les changements effectués sur les sources, et récupérer les révisions de cette archive.

Dans le chapitre précédent, vous avez appris à rendre une archive accessible par le réseau.

Ce chapitre va commencer à explorer la manière dont plusieurs programmeurs peuvent partager une archive dans laquelle chacun d'eux effectue des modifications sur des projets particuliers.

Notez en premier lieu qu'il y a de nombreuses manières de partager des archives et d'organiser la coopération entre les développeurs d'un même projet. Nous démarrerons par la technique la plus simple.

Alice et Bob travaillent sur main

Supposons qu'Alice et Bob soient tous les deux en train de travailler sur hello-world et qu'ils partagent la même archive. Dans les exemples suivants, nous allons jouer le rôle de chacun d'eux.

Pour commencer, chaque programmeur va avoir besoin de sa propre arborescence :

% cd ~/wd

% [ ... effacez les répertoires laissés par les exemples précédents ...]


% tla get hello-world--mainline--0.1  hello-world-Alice
[....]

% tla get hello-world--mainline--0.1  hello-world-Bob
[....]

L'objectif d'Alice est d'ajouter quelques mentions légales à chaque fichier. Lorsque c'est fait (mais pas encore archivé par commit), les fichiers sont ainsi :

% cd ~/wd/hello-world-Alice

% head -3 main.c
/* Copywrong 1998 howdycorp inc.  All rights reversed.*/

extern void hello_world (void);

% head hw.c
/* Copywrong 1998 howdycorp inc.  All rights reversed. */

#include <stdio.h>

Bob, pendant ce temps, a ajouté un commentaire indispensable à main:

% cd ~/wd/hello-world-Bob

% cat main.c
extern void hello_world (void);

int
main (int argc, char * argv[])
{
  hello_world ();

  /* Exit with status 0
   */
  return 0;
}

Notez que les deux programmeurs ont maintenant des versions modifiées de hello-world, mais aucun d'eux n'a les modifications de l'autre.

Bob archive en premier

Supposons que Bob soit le premier à essayer d'archiver ses modifications. Pour se rappeler, voici les deux étapes :

En premier lieu, Bob prépare un message de log :

% cd ~/wd/hello-world-Bob

% tla make-log
++log.hello-world--mainline--0.1--lord@emf.net--2003-example

[Bob edits the log message.]

% cat ++log.hello-world--mainline--0.1--lord@emf.net--2003-example
Summary: commented return from main
Keywords:

Added a comment explaining how the return from `main'
relates to the exit status of the program.

Ensuite il appelle commit:

% tla commit
[...]

Alice ne peux pas archiver maintenant

Maintenant c'est au tour d'Alice

% cd ~/wd/hello-world-Alice

% tla make-log
++log.hello-world--mainline--0.1--lord@emf.net--2003-example

[Alice edits the log message.]

% cat ++log.hello-world--mainline--0.1--lord@emf.net--2003-example
Summary: added copywrong statements
Keywords:

Added copywrong statements to the source files so
that nobody can steal HowdyCorp's code.

Et ensuite elle essaye d'archiver :

% tla commit
commit: tree is not up-to-date
  (missing latest revision is
    lord@emf.net--2003b--2003-example/hello-world--mainline--0.1--patch-2)

Le problème ici est que les modifications de Bob ont déjà été archivées, mais l'arborescence d'Alice ne contient pas ces modifications.

Étudions pourquoi Alice ne peut pas archiver

La commande commit indique à Alice qu'elle n'est « pas à jour ». Ça signifie que son arborescence ne contient pas certaines modifications archivées.

Elle peut examiner la situation plus en détail en demandant ce qui manque à son arborescence :

% tla missing
patch-2

ou plus en détail :

% tla missing --summary
patch-2
    commented return from main

dans lequel vous pourrez reconnaître le « Summary: » du message de log de Bob.

Elle peut consulter le message de log de Bob en entier :

% tla cat-archive-log hello-world--mainline--0.1--patch-2
Revision: hello-world--mainline--0.1--patch-2
Archive: lord@emf.net--2003-example
Creator: Tom (testing) Lord <lord@emf.net>
Date: Wed Jan 29 12:46:50 PST 2003
Standard-date: 2003-01-29 20:46:50 GMT
Summary: commented return from main
Keywords:
New-files: {arch}/hello-world/[....]
Modified-files: main.c
New-patches: \
  lord@emf.net--2003-example/hello-world--mainline--0.1--patch-2

Added a comment explaining how the return from `main'
relates to the exit status of the program.

En regardant les entêtes de ce message, Alice peut voir, par exemple, que Bob a modifié le fichier main.c.

Dans des chapitres ultérieurs, nous explorerons davantage de commandes qu'Alice peut utiliser pour étudier les modifications que Bob a effectuées, mais pour l'instant, regardons comment Alice peut intégrer ces modifications dans son arborescence.

La commande update

Alice a besoin d'associer ses modifications avec celles de Bob avant de pouvoir les archiver. La méthode la plus facile est d'utiliser la commande update.

% cd ~/wd

% tla update hello-world-Alice
[....]

Maintenant elle va retrouver les modifications de Bob dans son arborescence :

% cd hello-world-Alice

% cat main.c
/* Copywrong 1998 howdycorp inc.  All rights reversed. */

extern void hello_world (void);

int
main (int argc, char * argv[])
{
  hello_world ();

  /* Exit with status 0
   */
  return 0;
}

/* arch-tag: main module of the hello-world project
 */

Du fait, il ne manque plus rien :

% tla missing
[rien]

La commande commit peut être utilisée joyeusement :

% tla commit
[....]

Note

Si vous avez suivis les exemples jusqu'ici, vous devriez toujours avoir une arborescence hello-world-Bob contenant les modifications de Bob, mais pas ceux d'Alice. Essayez différentes commandes sur ce répertoire par curiosité (missing, update, changes etc.).

Comment ça marche ? -- La commande update

Une explication complète du fonctionnement de la commande update dépasserait le cadre de ce chapitre. Vous serez capable de comprendre en détail la commande update dans les chapitres suivants (« changeset » et « patch-logs »).

Pour l'instant, si vous êtes familier avec diff et patch, vous pouvez considérer cette commande comme cela :

Lorsque update est lancée dans l'arborescence d'Alice, elle constate que l'archive est au niveau de la révision patch-2, mais que l'arborescence a été récupérée à partir d'un get de la révision patch-1. update fonctionne en 3 étapes :

Premièrement, elle utilise une commande appelée mkpatch (qui est une sorte de diff évolué) pour calculer un changeset (une sorte de patch-set) décrivant les modifications effectuées par Alice sur son arborescence.

Deuxièmement, elle récupère une copie de la révision patch-2 et remplace l'arborescence d'Alice avec celle-ci.

Troisièmement, update utilise dopatch (une sorte de patch) pour appliquer le changeset, créé lors de la première étape, à l'arborescence.

Vous vous demandez sûrement comment les conflits sont traités. Les exemples précédents étaient choisis pour éviter les conflits. Ne vous inquiétez pas -- nous allons aborder le sujet bientôt (voir « Problème de patch -- comment les conflits sont traités »).

Introduction aux changesets

Il est souvent utile de pouvoir comparer deux arborescences (généralement du même projet) et voir précisément quelles sont les différences entre elles. L'enregistrement de ces différences est appelé changeset ou delta.

Les changesets représentent un concept central de arch -- la plupart des outils de arch effectuent des opérations avec les changesets.

Si vous avez un changeset entre une « vieille arborescence » et une « nouvelle arborescence », vous pouvez « appliquer un changeset » sur la « vieille arborescence » et obtenir ainsi la « nouvelle arborescence » -- en d'autres termes, vous pouvez appliquer automatiquement les changements décrits dans le changeset. Si vous avez une troisième arborescence vous pouvez également appliquer ce patch et voir ce que donnerait ces changements sur lui.

arch inclut des outils sophistiqués pour créer et appliquer des changesets.

mkpatch

mkpatch génère un changeset décrivant les différences entre deux arborescences. La commande de base est :

% tla mkpatch ORIGINAL MODIFIED DESTINATION

qui compare l'arborescence ORIGINAL et MODIFIED

mkpatch crée un nouveau répertoire, DESTINATION, et enregistre le changeset dedans.

Quand mkpatch compare les deux arborescences, il utilise les identifiants (inventory ids). Par exemple, il considère deux répertoires ou deux fichiers comme étant « le même répertoire (ou fichier) » s'ils ont le même identifiant -- même s'ils sont placés à des endroits différents. (voir « Identifiants d'inventaire pour les sources ».)

Un changeset produit par mkpatch décrit quels fichiers et répertoires ont été ajoutés, déplacés, renommés ou modifiés (et comment ils ont été modifiés), ainsi que les fichiers dont les permissions auraient été changées (et comment). Lorsqu'il s'agit de fichiers textes classiques, mkpatch génère un « context diff » décrivant les différences. mkpatch peut comparer des fichiers binaires (en sauvegardant une copie complète de l'ancienne et de la nouvelle version si elles sont différentes) ainsi que les liens symboliques (en sauvegardant l'ancienne et la nouvelle cible, si elles sont différentes).

Une description détaillée du format d'un changeset est décrit dans l'appendice (voir « Le format arch d'un changeset »)

dopatch

dopatch est utilisé pour appliquer un changeset à une arborescence.

% tla dopatch PATCH-SET TREE

Si l'arborescence TREE est exactement la même que l'arborescence « originale » utilisée par mkpatch, alors TREE sera modifiée pour que l'arborescence devienne strictement identique à l'arborescence « modifiée » utilisée par mkpatch, avec une exception (détaillée plus loin).

« Exactement la même » signifie que la structure de l'arborescence est identique, que les liens symboliques sont identiques, que les fichiers textes sont identiques, et que les permissions des fichiers sont identiques. Les dates de modifications, les fichiers ayant plusieurs liens (en dur), et les propriétaires des fichiers ne sont pas forcément préservés.

L'exception à la règle « exactement la même » est qu'au cas où l'application du patch entraîne des suppressions de fichiers ou répertoires dans l'arborescence TREE, ces fichiers et répertoires seront sauvegardés dans un sous-répertoire de TREE avec un nom particulièrement visible à l'oeil grâce à sa syntaxe :

++removed-by-dopatch-PATCH--DATE

PATCH est le nom complet du patch-set et DATE la date précise.

Problème de patch -- Comment sont gérés les conflits

Que se passe-t-il si l'arborescence à patcher de dopatch n'est pas exactement la même que l'originale utilisée par mkpatch ?

Ci-dessous, une description de ce à quoi on peut s'attendre. La documentation complète du fonctionnement de dopatch est incluse dans le code source.

dopatch fait un inventaire de l'arborescence à patcher. Il utilise les identifiants (inventory ids) pour décider quels fichiers et répertoires attendus sont présents ou manquants de l'arborescence et voir où chaque fichier et répertoire se trouve dans l'arborescence.

Patchs simples

Si le changeset contient un patch classique ou un metadata patch pour un lien, répertoire ou fichier, et que ce fichier est présent dans l'arborescence, dopatch applique le patch de manière habituelle. Si le patch s'applique proprement, le fichier modifié, le lien, ou le répertoire est laissé à sa place.

Si le patch ne peut pas s'appliquer proprement, dopatch va laisser le fichier orignal avec un suffixe .orig (le fichier original de l'arborescence devant être patché, sans aucune modification) et créer un fichier .rej (contenant la partie du patch qui n'a pas pu être appliquée)

Si le conflit concernait un fichier binaire, il n'y aurait pas eu de fichier partiellement patché. À la place nous aurions eu :

.orig -- le fichier original de l'arborescence à patcher,
         sans aucune modification

.rej  -- une copie complète du fichier de l'arborescence
         modifiée, avec les mêmes permissions que le fichier ``.orig``

.patch-orig -- une copie complète du fichier original
               utilisé par ``mkpatch``, avec ses permissions originales.

                -ou-

               le lien symbolique de l'arborescence utilisé
               par ``mkpatch`` avec ses permissions originales.

Si le conflit concernait un lien symbolique, il n'y aurait pas eu de fichier partiellement patché. À la place nous aurions eu :

.orig -- le fichier non modifié de l'arborescence originale

.rej -- un lien symbolique sur la cible attendue par le patch avec
        les mêmes permissions que le fichier ``.orig``

.patch-orig -- une copie complète du fichier original utilisé par
               ``mkpatch``, avec ses permissions originales.

                 -ou-

               le lien symbolique de l'arborescence utilisée
               par ``mkpatch`` avec ses permissions originales.

Patchs sur des fichiers manquants

Tous les patchs à appliquer sur des fichiers ou répertoires manquants sont enregistrés dans un sous-répertoire placé à la racine de l'arborescence à patcher.

==missing-file-patches-PATCH-DATE

PATCH est le nom complet du changeset et DATE la date actuelle.

Réorganisation des répertoires et nouveaux répertoires

Les répertoires sont ajoutés, supprimés, et réorganisés de la manière attendue, même si vous ne savez pas que c'est ce que vous attendriez.

Supposons que lorsque la commande mkpatch a été appelée, l'arborescence ORIGINAL était :

Répertoire ou fichier:      Id:

a/x.c                       id_1
a/bar.c                     id_2

mais l'arborescence MODIFIED était :

a/x.c                       id_1
a/y.c                       id_2

avec une modification sur chaque fichiers. Le patch va renommer le fichier avec l'identifiant id_2` en ``y.c, et modifier le contenu des fichiers avec les identifiants id_1 et id_2.

Supposons, par exemple, que vous ayez cette arborescence :

a/foo.c                     id_1
a/zip.c                     id_2

et que vous appliquiez le patch à cette arborescence. Après le patch, vous aurez :

a/foo.c                     id_1
a/y.c (ancien zip.c)        id_2

avec les modifications sur chacun des fichiers.

Voici un exemple plus subtil et la manière de gérer ces conflits :

Supposons que l'arborescence originale utilisée par mkpatch était :

Répertoires et fichiers:    Id:

./a                         id_a
./a/b                       id_b
./a/b/c                     id_c

Finalement supposons que l'arborescence soit :

./x                         id_a
./x/b                       id_b
./x/c                       id_new_directory
./x/c/b                     id_different_file_named_b
./x/c/q                     id_c

Après l'application du patch nous aurons :

./x                         id_a
      Étant donné que le patch ne fait aucune modification sur le
      répertoire ayant id_a

./x/c.orig                  id_new_directory
./x/c.rej                   id_c
      Étant donné que le patch veut transformer le répertoire id_c
      en un sous-répertoire nommé ``c`` du répertoire ``id_a``, mais que cette
      arborescence a déjà un autre répertoire ici, avec l'identifiant
      ``id_new_directory``.

./x/c.rej/b                 id_b
      Étant donné que le patch veut renommer le répertoire avec
      l'identifiant ``id_b`` en un sous-répertoire nommé ``b`` du répertoire avec l'identifiant
      ``id_c``.

./x/c.orig/b                id_different_file_named_b
      Étant donné que le patch effectue des modifications sur ce fichier,
      il reste dans son répertoire parent.

Exploration des Changesets

Le chapitre précédent introduisait la notion de changeset et des commandes mkpatch et dopatch (variations sur le thème des programmes traditionnels diff et patch).

Dans ce chapitre, nous allons étudier d'une manière plus détaillée comment les changesets sont utilisés dans les archives, comment ils sont utilisés par les commandes commit et update, et ce que cela peut nous apporter pour utiliser arch au mieux.

Comment ça marche ? -- commit enregistre un changeset dans une archive

Supposons que vous ayez récupéré la dernière révision d'un projet (avec get), écrit un message de log, et archivé vos modifications (avec commit). Que s'est-il passé ?

  1. Génère un changeset décrivant les modifications apportées par rapport à la dernière révision ;
  2. Crée un répertoire dans l'archive pour la nouvelle révision ;
  3. Enregistre votre message de log et le changeset dans l'archive.

Sachant cela, vous aurez peut-être envie de revenir en arrière et de revoir la section précédente « Comment ça marche ? -- archiver (commit) une nouvelle révision »

get-changeset récupère un changeset d'une archive

Nous avons appris plus tôt que la commande cat-archive-log récupérait un message de log d'une archive (voir « Étudions pourquoi Alice ne peux pas faire de commit »)

Vous pouvez aussi récupérer un changeset d'une archive.

% cd ~/wd

% tla get-changeset hello-world--mainline--0.1--patch-1 patch-1
[...]

get-changeset récupère le changeset de l'archive et, dans ce cas, l'enregistre dans un répertoire appelé patch-1

(Le format des changesets est décrit dans « Le format arch d'un changeset ».)

Utiliser show-changeset pour examiner un changeset

Le format d'un changeset est optimisé pour être utilisé par des programmes, pas par des personnes. Il est difficile pour un humain d'analyser un changeset. Au lieu de ça, vous pouvez obtenir un rapport du patch au format diff en utilisant :

% tla show-changeset --diffs patch-1

[...]

Si vous avez suivi les exemples précédents, vous reconnaîtrez le format du rapport de show-changeset de la commande changes expliquée plus tôt (voir « Oh mon dieu -- Qu'ai-je fait ? »).

Bien utiliser les commit -- L'idée d'un changeset « propre »

Lorsque vous archivez (commit) un ensemble de modifications, il est généralement « de bon usage » de s'assurer qu'il s'agit d'un changeset « propre ».

Un changeset « propre » ne doit contenir que des modifications concernant un seul dessein. Si, par exemple, vous avez plusieurs bugs à corriger, ou plusieurs fonctionnalités à ajouter, essayer de ne pas les mélanger dans un seul commit.

Relecture facile

Il est plus facile pour quelqu'un de comprendre un changeset s'il ne concerne qu'une seule chose.

Fusion facile

Comme nous le verrons dans les chapitres suivants, dans certaines circonstances, nous allons avoir besoin d'examiner une collection de changesets pour en sélectionner quelques unes. Peut-être voudrez vous récupérer la correction A mais pas la fonctionnalité B. Si un changeset n'a qu'un seul dessein, ce genre de cueillette (cherrypicking) sera plus pratique.

Introduction à replay -- Une alternative à update

update n'est pas la seule manière de mettre à jour un développement. Une autre option est la commande replay :

% cd ~/wd/project-tree
% tla replay
[....]

Que fait cette commande exactement ?

Un update supplémentaire

Supposons que nous avons récupéré une vieille version de hello-world :

% cd ~/wd
% tla get hello-world--mainline--0.1--patch-1 hw-patch-1
[...]

Il est facile de voir que l'arborescence n'est pas à jour :

% cd hw-patch-1
% tla missing
patch-2
patch-3

Maintenant supposons que nous ayons fait quelques changements dans hw-patch-1 et ensuite update. Que se passe-t-il ?

Les changements locaux sont calculés par rapport au patch-1.

En d'autres termes un changeset est créé et correspond aux changements apportés à la copie originale de la révision patch-1 pour obtenir l'arborescence actuelle (hw-patch-1).

Une copie du patch-3 est récupérée.

update démarre avec la copie originale de la révision patch-3.

Le changeset est appliqué sur l'arborescence du patch-3.

Les changements calculés en premier lieu sont appliqués à cette nouvelle arborescence.

Il y a cependant une autre méthode possible :

La commande replay

Nous avons une copie du patch-1, avec éventuellement quelques changements :

% cd hw-patch-1
% tla missing
patch-2
patch-3

Souvenons-nous que les révisions patch-2 et patch-3 correspondent chacune à un changeset spécifique, stocké dans l'archive (voir « Comment ça marche ? -- commit enregistre une nouvelle révision »)

Nous pourrions effectuer les changements à notre arborescence locale en utilisant get-changeset pour récupérer chaque changeset, et utiliser dopatch pour les appliquer (voir : « get-changeset récupère un changeset d'une archive »). C'est un travail assez pénible, alors que arch fournit une solution automatique pour accomplir la même chose :

% cd ~/wd/hw-patch-1
% tla replay
[....]
% tla missing
[no output]

replay va faire exactement ce que nous avons décrit : récupérer les « patchs » de l'archive et les appliquer un par un. Un mot cependant : si un de ces patchs engendre des conflits, replay va s'arrêter là et vous laisser corriger les conflits. Vous pourrez alors reprendre où replay s'était arrêté en relançant replay une seconde fois.

Comment ça marche ? -- replay

Si vous avez suivi tout le tutoriel jusqu'ici, le fonctionnement de replay devrait être tout simplement évident. En fait, c'est exactement comme nous l'avons décrit au dessus. replay utilise missing pour trouver quels sont les changements manquants à votre arborescence, get-changeset pour récupérer ces changesets, et dopatch pour les appliquer. Il y a pas mal « d'écritures » à effectuer pour faire ça -- et ces « écritures » sont automatiquement effectuées pour vous par replay.

Sélection des fichiers à archiver (commit)

Précédemment, vous avez appris à archiver tous les changements d'une arborescence d'un coup (voir: « Archiver les changements »)

Vous avez aussi lu à quel point il est important de faire des changesets « propres » (voir: « Bien archiver (commit) -- L'idée d'un changeset propre »)

Ce chapitre vous montre une petite astuce que vous pouvez utiliser dans une situation bien spécifique mais assez courante.

La petite correction express

Supposons que sur un projet conséquent vous ayez une grande arborescence et que vous êtes en train d'effectuer des changements complexes. Vous avez modifié de nombreux fichiers, mais il y en a beaucoup d'autres qui n'ont pas été touchés.

Subitement, vous vous rendez compte d'un bug trivial sur un fichier non modifié.

Ce que vous aimeriez faire c'est :

  1. Arrêter et réparer ce bug trivial
  2. Archiver cette correction triviale.
  3. Retourner travailler sur les changements complexes.

Comment pouvez-vous faire ?

La solution brutale pour la petite correction express

Il y a une solution « brutale » à ce problème.

Tout simplement :

Récupérer une copie fraîche de la dernière révision

En d'autre termes créer une seconde arborescence sans vos changements.

Réparer le bug trivial dans cette nouvelle arborescence puis archiver

Maintenant vous avez archivé un changement propre avec la correction du bug trivial uniquement.

Utilisez update ou replay pour mettre à jour votre arborescence originale

Ce qui va ajouter la correction du bug trivial à votre arborescence en cours.

Ça fonctionne, mais c'est un petit peu exagéré. Avez-vous réellement besoin de créer une nouvelle arborescence rien que pour réparer ce bug trivial ?

Parfois cette exagération est méritée. Par exemple, si votre projet à comme politique de lancer quelques tests avant chaque archivage. Dans ce cas, oui, vous devez réellement créer une nouvelle arborescence.

Parfois cette exagération est indispensable. Par exemple, si la réparation du bug oblige à modifier des fichiers que vous avez déjà modifié, alors, la solution brutale sera l'approche la plus simple (mais quand même, jetez un oeil à tla undo --help et tla redo --help).

Mais il y a une solution plus simple qui peut parfois être utilisée :

Résoudre la petite correction express avec commit

Comme nous le verrons, commit permet de ne prendre en compte que les changements de quelques fichiers.

Si votre correction ne modifie que les fichiers file-a.c et file-b.c, alors après avoir préparé un message de log, vous pourrez archiver uniquement ces fichiers :

% tla commit -- file-a.c file-b.c

Notez que les fichiers archivés de cette manière ne doivent pas être des nouveaux fichiers, même si ces fichiers ont été renommés, le commit ne va enregistrer que les modifications internes de ces fichiers, pas les renommages.

La correction express -- Il y a plusieurs façons de faire

Dans le texte précédent, nous avons étudié une solution « brutale » au problème de la correction express qui impliquait de récupérer la totalité de l'arborescence du projet.

Deux autres commandes, tla undo et tla redo, fournissent une autre alternative « brutale » avec quelques avantages. (Essayez tla undo --help et tla redo --help)

Branches élémentaires -- Gérer les changements privés

Dans ce chapitre, nous allons commencer à explorer le concept de branche auquel vous êtes peut-être habitué avec d'autres gestionnaire de révisions.

Si vous êtes déjà familiarisé avec ce concept, soyez conscient que le système de branche dans arch va certainement beaucoup plus loin que ce à quoi vous êtes habitué.

Que vous soyez ou non familiarisé avec ce concept, n'ayez crainte -- nous allons démarrer doucement.

Un scénario de branche -- Le besoin de changements privés

Supposons pour le moment que le projet hello-world diffuse ses sources au public, sur un miroir en lecture seule (voir « Archives privées et publiques »).

Précédemment, vous (une personne extérieure au projet hello-world) décidez que vous voulez utiliser leur programme, mais que vous avez besoin d'y apporter quelques modifications localement.

Comme exemple ludique, supposons que vous ayez décidé que dans votre environnement, dire « hello world » n'est pas acceptable -- vous avez réellement besoin d'une ponctuation correcte « hello, world ».

Maintenant, voici le problème : bien sûr, vous pouvez télécharger leurs sources et effectuer cette modification. Mais pendant ce temps, le projet continue. Ils continuent d'effectuer des changements. Vous serez donc perpétuellement dans l'obligation de télécharger les sources les plus récents et d'y appliquer vos modifications.

Ce chapitre va expliquer comment arch vous aidera à automatiser cette tache.

Création d'une branche dans une archive locale, à partir d'un projet extérieur

Dans l'exemple qui suit, vous aller changer de rôle. À la place de « jouer » Alice et Bob, les programmeurs du projet hello-world, vous aller « jouer » le rôle de Candice : une troisième personne.

Commençons par donner à Candice sa propre archive, et en faire son archive par défaut :

% tla make-archive candice@candice.net--2003-candice \
     ~/{archives}/2003-candice

% tla my-default-archive candice@candice.net--2003-candice
default archive set (candice@candice.net--2003-candice)

(Vous pouvez voir ce que ces commandes font en lisant « Création d'une nouvelle archive ».)

Candice a besoin de créer un projet hello-world dans sa propre archive. Elle peut utiliser :

% tla archive-setup  hello-world--candice--0.1

Elle n'a pas besoin d'utiliser le même nom de projet qu'Alice et Bob, en fait, dans notre cas elle choisit un non de branche différent. (Pour revoir ces commandes, voir « Création d'un nouveau projet ».)

Quand Alice et Bob créaient leurs archive, ils utilisaient import pour créer la première révision. Vu que nous allons créer une branche, nous allons utiliser une commande différente:

% tla tag \
    lord@emf.net--2003-example/hello-world--mainline--0.1--patch-1 \
    hello-world--candice--0.1
[....]

Certaines choses méritent d'être notées à propos de cette commande.

Premièrement, notez que nous utilisons un nom de révision complet pour se référer à la révision patch-1 d'Alice et Bob. Du fait que cette révision ne se trouve pas dans l'archive par défaut. (voir « Travailler avec plusieurs archives en même temps ».)

Notez que nous avons spécifié explicitement patch-1 comme révision. Si nous n'avions pas indiqué le suffixe patch-1, la commande tag aurait déduit que nous voulions la dernière révision de l'archive d'Alice et Bob (qui se trouve être le patch-3).

Quel effet a eu tag ?

Après avoir utilisé tag, Candice a maintenant une nouvelle révision dans son archive :

% tla revisions --summary hello-world--candice--0.1
base-0
    tag of lord@emf.net--2003-example/hello-world--mainline--0.1--patch-1

Elle peut récupérer cette révision de la manière habituelle :

% tla get hello-world--candice--0.1 hw-candice
[...]

% ls hw-candice
hw.c                main.c          {arch}

Friandise de arch

Si vous avez bien suivi, vous remarquerez que Candice a créé une branche dans son archive à partir d'une révision stockée dans une autre archive. Dans notre exemple, il se trouve que toutes ces archives sont sur le même système de fichier mais ce n'est pas indispensable : Candice aurait très bien pu créer sa branche même si elle devait accéder à celle d'Alice et Bob à travers le réseau.

Mise en cache d'une révision issue d'un tag

Candice a utilisé tag pour créer une branche à partir de l'archive d'Alice et Bob. Dans ce cas, arch a créé ce que l'on appelle une révision en cache de la révision base-0 du dépôt de Candice (qui, ayant été créée avec tag, est identique à lord@emf.net--2003-example/hello-world--mainline--0.1--patch-1.) C'est le fonctionnement par défaut de tla à présent; cependant l'ancien comportement (pas de mise en cache des révisions) peut être reproduit en spécifiant l'option --no-cacherev de tla tag.

Que ce serait-il passé sans la mise en cache de la révision ?

Lorsque Candice a utilisé get pour récupérer cette révision, arch a pris en compte le fait qu'il s'agissait d'une branche, et donc -- en l'absence de cachedrev -- il serait allé chercher les sources dans l'archive d'Alice et Bob.

la question apparaît : que ce serait-il passé si l'archive d'Alice et Bob « n'était plus » ? En l'occurrence, ce qui se serait passé, c'est que Candice n'aurait pas pu faire de get de sa branche.

Elle aurait pu s'en sortir, à la main en mettant en cache dans son archive toutes les informations nécessaires pour construire sa révision, c'est à dire un cachedrev :

% tla cacherev hello-world--candice--0.1--base-0
[...]

et confirmer que ça a marché avec :

% tla cachedrevs hello-world--candice--0.1
hello-world--candice--0.1--base-0

Ainsi, arch n'aurait plus besoin de compter sur l'archive d'Alice et Bob pour récupérer la révision base-0.

Explorer la nouvelle branche

Précédemment, Candice créait sa branche et utilisait get pour la récupérer. Examinons cette arborescence :

% cd ~/wd/hw-candice

% tla log-versions
candice@candice.net--2003-candice/hello-world--candice--0.1
lord@emf.net--2003-example/hello-world--mainline--0.1

Notez que l'arborescence de Candice contient à la fois les logs de patchs des version d'Alice et Bobs, et à la fois ceux de sa propre branche :

% tla logs --summary \
        lord@emf.net--2003-example/hello-world--mainline--0.1
base-0
    initial import
patch-1
    Fix bugs in the "hello world" string


% tla logs --summary hello-world--candice--0.1
base-0
    tag of \
    lord@emf.net--2003-example/hello-world--mainline--0.1--patch-1

Il n'y a plus de changements sur la branche de Candice :

% tla missing hello-world--candice--0.1
[no output]

mais souvenez vous qu'Alice et Bob en sont déjà au patch-3 :

% tla missing -A lord@emf.net--2003-example \
    hello-world--mainline--0.1
patch-2
patch-3

Effectuer une modification locale

Après le tag initial, Candice peut archiver les changements de sa branche avec la méthode habituelle.

Supposons maintenant qu'elle ait modifié hw.c qui contient donc en partie :

% cat hw.c
[...]
void
hello_world (void)
{
  (void)printf ("hello, world\n");
}
[...]

et qu'elle a préparé un message de log :

% cat ++log.hello-world--candice--0.1--lord@emf.net--2003-candice
Summary: Punctuated the output correctly
Keywords:


This program should say "hello, world" not "hello world".

Maintenant elle peut archiver de la manière habituelle, en créant sa propre révision patch-1 :

% tla commit
[....]

% tla revisions --summary hello-world--candice--0.1
base-0
    tag of \
    lord@emf.net--2003-example/hello-world--mainline--0.1--patch-1
patch-1
    Punctuated the output correctly

Mise à jour à partir d'une version issue d'une branche

Entre temps, Alice et Bob ont créé leurs révisions patch-2 et patch-3. Comment Candice peut-elle appliquer ces changements à sa branche ?

À ce niveau, arch fournit réellement beaucoup de techniques. En utilisant les commandes précédemment étudiées, elle pourrait utiliser soit update soit replay. Dans cet exemple, nous allons montrer l'utilisation de replay.

% cd ~/wd/hw-candice

% tla replay -A lord@emf.net--2003-example \
        hello-world--mainline--0.1
[...]

Notez que nous avons utilisé l'argument -A pour indiquer de quelle archive nous allons récupérer les changements, et le nom de la version pour indiquer quels changements nous voulons. Dans ce cas, replay appliquera les changesets de patch-2 et patch-3 à l'arborescence de Candice.

Cette utilisation de replay est une forme de « fusion » (merging) : Les changements locaux de Candice ont été fusionnés avec les changements d'Alice et Bob sur leur mainline.

Note

Si vous avez suivi les exemples, vous devriez examiner hw.c et noter que les changements de Candice sur la chaîne de printf et l'ajout de la notice copywrong sont toutes les deux incluses.

Note

Vous devriez également récupérer une deuxième copie de la révision patch-1 et expérimenter en effectuant la même fusion en utilisant update au lieu replay. Vous devriez regarder tla update -help et voir ainsi quelles sont les options et arguments adéquats.

Notez également que, jusqu'à présent, nous avons seulement appliqué les changements sur l'arborescence du projet de Candice -- ceux-ci n'ont pas été enregistrés dans l'archive de Candice. Pour enregistrer la fusion dans son archive, elle devra créer un message de log et archiver par la méthode habituelle (voir « Archiver les changements »).

Il y a, cependant, encore une convenance à respecter. Quand Candice écrit son message de log, elle voudra vraisemblablement noter qu'il y a eu une fusion et ce qu'elle a entraîné. Arch comporte une commande dont la sortie est idéale pour ce message de log :

% cd ~/wd/hw-candice

% tla log-for-merge
Patches applied:

  * lord@emf.net--2003-example/hello-world--mainline--0.1--patch-3
     added copywrong statements

  * lord@emf.net--2003-example/hello-world--mainline--0.1--patch-2
     commented return from main

Comment ça marche ? -- tag et les branches élémentaires

Qu'a fait tag ? Regardons l'archive de Candice :

% cd ~/{archives}
% cd 2003-candice
% cd hello-world
% cd hello-world--candice
% cd hello-world--candice--0.1

% ls
+version-lock       base-0          patch-1
patch-2

Ce qui nous intéresse ici, c'est la révision base-0 -- celle créée par le tag:

% cd base-0

% ls
CONTINUATION
hello-world--candice--0.1--base-0.patches.tar.gz
hello-world--candice--0.1--base-0.tar.gz
log

% cat CONTINUATION
lord@emf.net--2003-example/hello-world--mainline--0.1--patch-1

Le fichier CONTINUATION identifie que cette révision provient d'un tag. Son contenu nous indique de quelle révision nous avons créé la branche.

Le changeset de cette révision (...patches.tar.gz) a aussi été créé par le tag. Si vous examinez ce changeset (souvenez-vous de get-changeset et de show-changeset) vous verrez que la seule chose qu'il fait est d'ajouter un log dans la liste des patch-logs.

Le fichier source (...base-0.tar.gz) a été créé par archive-cache-revision. Il contient une copie complète de la révision base-0 de Candice. Étant donné que ce fichier est là, get n'est pas obligé d'aller voir dans l'archive d'Alice et Bob pour construire cette révision.

Patch-logs et l'historique de l'arborescence d'un projet

Dans le chapitre précédent, nous avons commencé à apprendre le système de branche et de fusion. Nous avons vu comment des commandes comme missing, update, et replay pouvaient être utilisées pour surveiller et appliquer les changements des multiples branches d'un projet.

Dans ce chapitre, nous allons étudier quelques aspects des « patch logs » : le mécanisme utilisé pour surveiller l'historique de l'arborescence d'un projet, y compris la partie de l'historique qui est utilisée pour effectuer des fusions de manière intelligente.

Souvenez-vous d'abord lorsque nous avons rencontré les patch-logs dans les précédents chapitres (par exemple, lors de l'initialisation d'un projet, dans « Démarrer un nouveau projet »). Dans ce chapitre, les patch-logs seront expliqués en profondeur.

L'arborescence d'un projet contient des patch-logs

Souvenez vous qu'à chaque importation initiale, révision de tag, et révision de changeset dans une archive, un message de log est associé. Ce message consiste en un entête et un texte que vous envoyez dans des commandes telles que import et commit, en plus d'autres entêtes générés automatiquement par arch.

Lorsqu'un projet est importé pour la première fois dans une archive, le patch-log de cette nouvelle révision est ajouté à l'arborescence. Quand un commit est effectué, lors d'une opération d'archivage, le log de la nouvelle révision est ajouté à l'arborescence. Si vous récupérez (get) une révision créée par la commande tag, vous verrez qu'il contient également un patch-log pour cette révision de tag.

Les patch-logs s'accumulent. Ainsi, par exemple, chaque commit ajoute un nouveau log et tout les logs précédents sont préservés. Chaque révision de tag inclus non seulement le log de ce tag, mais aussi tous les logs hérités de la révision « taggés »

Revenons à nos exemples précédents, regardons la révision patch-2 de Alice et Bob :

% cd ~/wd

[... supprimer les répertoires des exemples précédents ...]

% tla get -A lord@emf.net--2003-example \
            hello-world--mainline--0.1--patch-2 \
            hw-AnB-2

[...]

% cd ~/hw-AnB-2

Premièrement, notons que les patch-logs sont triés par le nom arch de la version. Cette arborescence a des logs pour une version seulement :

% tla log-versions
lord@emf.net--2003-example/hello-world--mainline--0.1

Dans cette version, il y a des logs pour l'importation initiale, et deux changesets :

% tla logs -A lord@emf.net--2003-example \
              --summary \
              hello-world--mainline--0.1
base-0
    initial import
patch-1
    Fix bugs in the "hello world" string
patch-2
    commented return from main

Examinons un de ces logs en particulier :

% tla cat-log -A lord@emf.net--2003-example \
                hello-world--mainline--0.1--patch-2
Revision: hello-world--mainline--0.1--patch-2
Archive: lord@emf.net--2003-example
Creator: Tom (testing) Lord <lord@emf.net>
Date: Wed Jan 29 12:46:50 PST 2003
Standard-date: 2003-01-29 20:46:50 GMT
Summary: commented return from main
Keywords:
New-files: \
  {arch}/[...]/hello-world--mainline--0.1/[...]/patch-log/patch-2
Modified-files: main.c
New-patches: \
  lord@emf.net--2003-example/hello-world--mainline--0.1--patch-2

Added a comment explaining how the return from `main'
relates to the exit status of the program.

nous pouvons voir, par exemple, que le changeset patch-2 modifie le fichier main.c et ajoute un nouveau fichier, le log lui-même (dont le nom est tronqué dans l'exemple affiché ci-dessus).

D'autres exemples méritent d'être étudiés sur l'arborescence de Candice. Souvenez-vous qu'elle a utilisé tag pour créer une branche (« fork ») à partir de la révision patch-1 d'Alice et Bob. Ainsi nous voyons :

% cd ~/wd

% tla get -A candice@candice.net--2003-candice \
            hello-world--candice--0.1--patch-2 \
            hw-C-0

[...]

% cd ~/hw-C-0

% tla log-versions
candice@candice.net--2003-candice/hello-world--candice--0.1
lord@emf.net--2003-example/hello-world--mainline--0.1

% tla logs  -A lord@emf.net--2003-example \
                --summary \
                hello-world--mainline--0.1
base-0
    initial import
patch-1
    Fix bugs in the "hello world" string


% tla logs  -A candice@candice.net--2003-candice \
                --summary \
                hello-world--candice--0.1
base-0
    tag of \
      lord@emf.net--2003-example/hello-world--mainline--0.1--patch-1

Comment ça marche ? -- missing (ce qui manque)

Dans les chapitre précédents, vous avez appris comment la commande missing pouvait vous indiquer les modifications archivées, mais pas encore présentes dans une arborescence donnée (voir « Étudions pourquoi Alice ne peut pas faire de commit (archiver) »).

Il devrait être assez facile de comprendre comment ces commandes fonctionnent. Arch peut trouver la liste de toutes les révisions d'une version donnée en utilisant la commande revisions :

% tla revisions -A lord@emf.net--2003-example \
                  hello-world--mainline--0.1
base-0
patch-1
patch-2
patch-3

Ce sont les logs de l'archive. Arch peut trouver la liste des révisions pour laquelle le projet a des logs avec logs :

% tla logs -A lord@emf.net--2003-example \
               hello-world--mainline--0.1
base-0
patch-1
patch-2

La différence entre ces deux listes est le résultat de missing :

% tla missing -A lord@emf.net--2003-example \
              hello-world--mainline--0.1
patch-3

Le concept d'historique des changements et l'ascendance du projet

Les patch-logs indiquent des informations pertinentes sur l'historique d'une arborescence. Il y a deux visions qui méritent d'être mentionnées : l'« historique des changements », et « l'ascendance d'un projet ».

Historique des changements

Lorsqu'une arborescence a un log pour le commit d'un changeset, cela signifie que les modifications de ce commit ont été appliquées à l'arborescence : le commit de ce changeset fait partie de l'« l'historique des changements » de cette arborescence. Si le changeset était une correction de bogue, par exemple, c'est une indication comme quoi ce bogue a été corrigé dans cette arborescence.

Note

Le fait qu'un changeset donné fasse partie de l'historique des changement de cette arborescence n'est pas une preuve absolue que les modifications de ce changeset sont présentes dans l'arborescence. Par exemple, ces changements ont pu être annulés par un changement ultérieur. Néanmoins, l'historique des changements d'une arborescence est un outil utile pour explorer et comprendre son état.

Ascendance d'un projet

De manière informelle, nous dirons qu'une révision archivée est une « ascendance » d'un projet donné si elle a des patch-logs pour toutes les révisions de la version de cette révision archivée jusqu'à la version archivée elle-même.

Ainsi, par exemple, la révision de Candice issue du tag a la révision patch-1 d'Alice et Bob comme un ascendant puisqu'elle a les logs des révisions d'Alice et Bob :

base-0
patch-1

Et la révision patch-2 de Candice, qui fusionne les changements patch-2 et patch-3 d'Alice et Bob, a l'ensemble de ces révisions comme ascendants (voir « Mise à jour à partir d'une version issue d'une branche »).

Changelogs automatiques

La commande tla changelog génère un ChangeLog dans le style GNU à partir d'un patch-log :

% cd ~/wd

% tla get -A candice@candice.net--2003-candice \
            hello-world--candice--0.1 \
            hw-C-latest
[....]

% cd ~/wd/hw-C-latest

% tla changelog
# do not edit -- automatically generated by arch changelog
# arch-tag: automatic-ChangeLog-- [...]
#

2003-01-30 GMT  Tom (testing) Lord <lord@emf.net>       patch-2

    Summary:
      merge from mainline sources
    Revision:
      hello-world--candice--0.1--patch-2

    Patches applied:

      * lord@emf.net--2003-example/hello-world--mainline--0.1--patch-3
         added copywrong statements

      * lord@emf.net--2003-example/hello-world--mainline--0.1--patch-2
         commented return from main


    new files:
     {arch}/ [...] /hello-world--mainline--0.1 [...] /patch-2
     {arch}/ [...] /hello-world--mainline--0.1 [...] /patch-3

    modified files:
     hw.c main.c

    new patches:
     lord@emf.net--2003-example/hello-world--mainline--0.1--patch-2
     lord@emf.net--2003-example/hello-world--mainline--0.1--patch-3


2003-01-30 GMT  Tom (testing) Lord <lord@emf.net>       patch-1

    Summary:
      Punctuated the output correctly
    Revision:
      hello-world--candice--0.1--patch-1


    This program should say "hello, world" not "hello world".


    modified files:
     hw.c


2003-01-30 GMT  Tom (testing) Lord <lord@emf.net>       base-0

    Summary:
      tag of lord@emf.net--2003-example/hello-world--mainline--0.1--patch-1
    Revision:
      hello-world--candice--0.1--base-0

    (automatically generated log message)


    new patches:
     lord@emf.net--2003-example/hello-world--mainline--0.1--base-0
     lord@emf.net--2003-example/hello-world--mainline--0.1--patch-1

Notez que ce ChangeLog généré inclut un tagline. Si vous sauvegardez la sortie de cette commande changelog dans une arborescence, soit en utilisant un tagline ids ou en lui donnant un identifiant explicite qui correspond au tagline id, une commande telle que commit va automatiquement conserver le ChangeLog à jour.

Développement multi-branches -- La coopération sous forme de fusion en étoile (star-merge)

Dans les chapitres précédents, nous avons développé un exemple sur le projet hello-world.

Alice et Bob, les premiers programmeurs du projet, créaient une archive et quelques révisions.

Candice, un utilisateur du projet, créait sa propre archive, démarrait une branche du projet hello-world, et commençait à maintenir ses propres modifications locales.

Dans ce chapitre, nous allons commencer à étudier une situation plus typique et réaliste des projets libres. Ici, nous considérerons Alice et Bob comme les responsables du projet public, et Candice comme une contributrice importante du projet. Nous allons identifier les besoins en gestion de révisions engendrés par cette organisation, et regarder quelques commandes arch qui pourrons nous aider à les satisfaire.

Passer de branches élémentaires à un développement multi-branches

Jusqu'ici, si vous avez suivis les exemples, Candice a une branche élémentaire. Elle a créé une branche à partir de la branche principale (mainline), effectué quelques modifications, et a gardé sa branche à jour par rapport à la branche principale d'Alice et Bob.

Nous supposons, maintenant, qu'Alice et Bob veulent fusionner les modifications d'Alice dans la branche principale.

Bien, ce travail de fusion a déjà été effectué. La dernière révision de Candice est exactement ce qu'Alice et Bob souhaitent. Ils peuvent incorporer cette fusion dans leur branche principale très simplement, en enregistrant la dernière révision de Candice dans leur propre branche principale :

% tla get -A candice@candice.net--2003-candice \
            hello-world--candice--0.1 \
            hw-C
[...]


% cd hw-C

% tla set-tree-version -A lord@emf.net--2003-example \
            hello-world--mainline--0.1

% tla make-log
++log.hello-world--mainline--0.1--lord@emf.net--2003-example

[... edit log file (consider `tla log-for-merge') ... ]

% cat ++log.hello-world--mainline--0.1--lord@emf.net--2003-example
Summary: merge from Candice's Branch
Keywords:

Patches applied:

  * candice@candice.net--2003-candice/hello-world--candice--0.1--patch-2
     merge from mainline sources

  * candice@candice.net--2003-candice/hello-world--candice--0.1--patch-1
     Punctuated the output correctly

  * candice@candice.net--2003-candice/hello-world--candice--0.1--base-0
     tag of
      lord@emf.net--2003-example/hello-world--mainline--0.1--patch-1

% tla commit
[....]

Note

Notez attentivement l'« astuce » que nous avons utilisée. La dernière révision d'Alice était exactement ce qu'Alice et Bob souhaitaient -- ils ont associés un get avec un set-tree-version pour faire en sorte que l'arborescence de Candice puisse facilement être archivée dans leur branche principale.

Développement multi-branches, simple

Considérons ce qui ce passe lorsqu'un développement se poursuit sur les deux branches. Pour cela, nous allons introduire une nouvelle chose : un système de diagramme composé des branches et des fusions entre elles.

Après nos exemples, nous avons cette situation :

mainline--0.1                    candice--0.1
-------------                    ------------
  base-0             -----------> base-0 (a tag)
  patch-1  ---------'             patch-1
  patch-2             ----------> patch-2
  patch-3  ----------'  --------'
  patch-4  <-----------'

qui nous indique que la branche candice est un tag du patch-1 provenant de la branche principale; qu'au niveau du patch-2 de la branche candice, il y a eu une fusion de tous les patchs de la mainline jusqu'au patch-3; et finalement que le patch-4 fusionne tout jusqu'au patch-2 de la branche candice.

Lorsque nous avons un diagramme dans lequel aucune des lignes de fusion ne se croisent, on considère que c'est un « développement multi-branches, simple ».

La signification d'un développement multi-branches, simple, est qu'il s'agit d'un modèle où deux équipes peuvent travailler d'une manière asynchrone sur un même projet. Dans chaque équipe -- dans chaque branche -- les programmeurs utilisent un style de coopération basé sur update/commit (voir « Le style de coopération update/commit »). Ainsi, les changements dans chaque branches n'ont aucun effet sur les autres jusqu'à la fusion des deux branches.

Introduction au problème de fusion du développement multi-branches

Supposons qu'il y ait beaucoup plus de travaux dans chacune des branches mainline et candice, nous amenant à ça :

mainline--0.1                    candice--0.1
-------------                    ------------
  base-0             -----------> base-0 (a tag)
  patch-1  ---------'             patch-1
  patch-2             ----------> patch-2
  patch-3  ----------'  --------' patch-3
  patch-4  <-----------'          patch-4
  patch-5
  patch-6


  % tla revisions --summary -A candice@candice.net--2003-candice \
                    hello-world--candice--0.1
  base-0
      tag of
      lord@emf.net--2003-example/hello-world--mainline--0.1--patch-1
  patch-1
      Punctuated the output correctly
  patch-2
      merge from mainline sources
  patch-3
      added a period to output string
  patch-4
      capitalized the output string



  % tla revisions --summary -A lord@emf.net--2003-example \
                    hello-world--mainline--0.1
  base-0
      initial import
  patch-1
      Fix bugs in the "hello world" string
  patch-2
      commented return from main
  patch-3
      added copywrong statements
  patch-4
      merge from Candice's Branch
  patch-5
      fixed the copyrwrong for hw.c
  patch-6
      fixed the copyrwrong for main.c

Considérons le scénario suivant dans lequel notre but est de fusionner les nouveaux travaux de la branche mainline dans la branche candice. En d'autres termes, nous voulons arriver à ça :

mainline--0.1                    candice--0.1
-------------                    ------------
  base-0             -----------> base-0 (a tag)
  patch-1  ---------'             patch-1
  patch-2             ----------> patch-2
  patch-3  ----------'  --------' patch-3
  patch-4  <-----------'          patch-4
  patch-5               --------> patch-5
  patch-6  ------------'

Comment pouvons-nous effectuer cette fusion ? Démarrons à la dernière révision de candice avant la fusion avec mainline (patch-4).

% tla get -A candice@candice.net--2003-candice \
               hello-world--candice--0.1--patch-4 \
               hw-C-4
[....]

% cd hw-C-4

Voici deux techniques qui ne marchent pas :

replay ne résout pas le problème de fusion du développement multi-branches

replay va essayer d'appliquer tous les changements qui manquent (missing) de mainline dans l'arborescence candice. La liste des changesets est indiquée :

% tla missing --summary \
              -A candice@candice.net--2003-example \
              hello-world--mainline--0.1
patch-4
    merge from Candice's Branch
patch-5
    fixed the copyrwrong for hw.c
patch-6
    fixed the copyrwrong for main.c

Le problème est que le patch-4 apparaît dans la liste. C'est une fusion qui inclut tous les changements de la branche candice jusqu'au niveau de son patch-2. Mais ces changements sont déjà présents dans la révision patch-4 de la branche candice -- ainsi replay va les appliquer plusieurs fois (ce qui va créer un conflit de patch).

Attention!

La commande replay ne vous empêchera pas d'effectuer plusieurs replay même si l'arborescence n'est plus dans un état cohérent. tla dans son état actuel ne fusionne pas les fichiers de rejet. Cela laisse ouvert la possibilité de perdre des rejets de patchs si un second replay est opéré avant que les rejets ne soit traités. (Un jour tla sera capable de fusionner plusieurs rejets en un seul).

Note

Pour les utilisateurs avancés

La commande replay a une option qui nous permet d'éviter le patch-4 de la branche principale. Cela résoudrait le problème, mais il y a quelques inconvénients. Premièrement, ça signifie que le patch-4 continuera d'être signalé comme manquant par la commande missing de la branche candice. Deuxièmement, rien ne nous garantit que le changeset patch-4 contient seulement la fusion de la branche candice. Si Alice et Bob ont effectués d'autres changements dans patch-4, et que nous évitons ce changeset, ces changements seront perdus.

update ne résout pas le problème de fusion du développement multi-branches

Supposons que nous essayons d'utiliser update à partir de la branche mainline. Souvenez-vous que update va créer un changeset entre le plus jeune ascendant de mainline jusqu'à l'arborescence actuelle, et ensuite appliquer ce changeset à la dernière révision de mainline.

Nous avons une notation pour cela. Un changeset entre X et Y est indiqué :

delta(X, Y)

Dans ce cas, update va démarrer en créant un changeset entre la révision patch-3 de mainline et notre arborescence :

delta(mainline--0.1--patch-3, hw-C-4)

L'arborescence résultante à l'application du changeset de X à Y vers l'arborescence Z est indiquée :

delta(X, Y) [ Z ]

En d'autres termes, le résultat de la commande update dans notre exemple peut être décrite comme cela :

delta(mainline--0.1--patch-3, hw-C-4) [mainline--0.1--patch-6]

Cependant, il y a un problème. La révision patch-3 de mainline n'a pas été fusionnée avec la branche de candice. Ainsi, le changeset

delta(mainline--0.1--patch-3, hw-C-4)

va inclure, en plus des autres changements, les modifications entre patch-1 et patch-2 de la branche candice.

Malheureusement, l'arborescence sur laquelle le changeset sera appliquée, mainline--0.1--patch-6, a déjà été fusionnée avec base-0...patch-2 de la branche candice.

Comme avec replay, update va entraîner des conflits de fusion en effectuant des changements redondants.

Solution d'un cas du problème de développement multi-branches

En utilisant notre notation delta et nos diagrammes de fusions, regardons comment résoudre ce problème de fusion proprement.

Souvenez-vous que nous avons actuellement :

mainline--0.1                    candice--0.1
-------------                    ------------
  base-0             -----------> base-0 (a tag)
  patch-1  ---------'             patch-1
  patch-2             ----------> patch-2
  patch-3  ----------'  --------' patch-3
  patch-4  <-----------'          patch-4
  patch-5
  patch-6

et notre but est de créer une nouvelle fusion, pour le patch-5 de la branche de Candice :

                      --------> patch-5
patch-6  ------------'

Nous pourrions décider de démarrer avec la branche mainline et fusionner les changements de candice manquants, ou démarrer avec l'arborescence candice et fusionner les changements manquants de mainline. Prenons le dernier (fusion dans l'arborescence de candice).

Dans ce cas, la révision patch_6 de mainline-0.1 est « à jour » par rapport à la révision patch-2 de candice-0.1. Nous voulons appliquer tous les changements de cette révision jusqu'à la dernière révision de candice :

avec:
        ascendant := candice--0.1--patch-2
        fusion_dans := mainline--0.1--patch-6
        résultat   := candice--0.1--patch-4

réponse := delta(ascendant, fusion_dans)[résultat]

Les flèches dans le diagramme de fusion sont décisives pour obtenir la bonne réponse. Par exemple, supposons que la flèche du patch-2 de Candice vers la révision patch-4 de mainline ne soit pas là. Dans ce cas la réponse aurait été :

avec:
        ascendant := mainline--0.1--patch-3
        fusion_dans := mainline--0.1--patch-6
        résultat   := candice--0.1--patch-4

réponse := delta(ascendant, fusion_dans)[résultat]

Tracer les flèches pour une fusion donnée est un travail pénible. Il est automatique avec la commande star-merge :

star-merge -- Solution pour le problème de la fusion d'un développement multi-branches en général

Cela dépasserait le cadre de ce tutoriel d'expliquer la solution complète du problème de fusion d'un développement multi-branches en général. Les deux solutions montrées plus haut illustrent deux cas, mais des solutions légèrement différentes sont parfois nécessaires.

Ce que vous devriez savoir c'est que lorsque vous avez un développement multi-branches, simple (voir « Développement multi-branches, simple »), la commande star-merge sait fusionner les branches sans déclencher de faux conflits.

% tla get -A candice@candice.net--2003-candice \
        hello-world--candice--0.1--patch-4 \
        merge-temp

% tla star-merge lord@emf.net--2003/hello-world--mainline--0.1

Étiquettes symboliques

Lorsqu'un projet grossit et devient plus complexe, il est souvent utile de pouvoir donner un nom symbolique à une révision particulière de l'archive.

Par exemple, supposons que le projet hello-world ait de nombreuses révisions :

mainline
--------
base-0
patch-1
patch-2
....
patch-23

Il est possible qu'en cours de développement des publications de « snapshots » soient effectuées à partir de la mainline. Toutes les révisions ne deviennent pas des « snapshots », mais certaines oui.

Il serait intéressant d'indiquer une étiquette aux révisions qui deviennent des « snapshots » :

mainline
--------
base-0
patch-1         snapshot 0
patch-2
....
patch-12        snapshot 2
....
patch-23        snapshot 3

La commande tag introduite précédemment, peut être utilisée à cette fin. (voir « Créer une branche d'un projet distant dans une archive locale »)

La première fois que nous avons rencontré la commande tag, c'était pour créer la révision base_0 d'une branche élémentaire. Elle peut également être utilisée pour créer une branche pour toutes les révisions ayant une étiquette.

Supposons que nous voulions créer une branche appelée hello-world--snapshots--0.1. Sous forme de diagramme, nous aurons :

mainline                        snapshots
--------                        ---------
base-0                --------> base-0 (tag)
patch-1 -------------'  ------> patch-1 (tag)
patch-2                '
....                  '
patch-12 ------------'
....
patch-23

Pour créer l'étiquette snapshot pour le patch-23:

% tla tag hello-world--mainline--0.1--patch-23 \
            hello-world--snapshots--0.1

après quoi nous aurons :

mainline                        snapshots
--------                        ---------
base-0                --------> base-0 (tag)
patch-1 -------------'  ------> patch-1 (tag)
patch-2                ' -----> patch-2 (tag)
....                  ' '
patch-12 ------------' '
....                  '
patch-23 ------------'

En effet, la branche snapshots est une sorte de nom symbolique avec un historique. Nous pouvons récupérer la dernière révision nommée par ce symbole avec :

% tla get hello-world--snapshots--0.1

et les révisions précédentes par le nom spécifique de leurs révisions, ex. :

% tla get hello-world--snapshots--0.1--patch-1

Attention!

En général, vos branches devraient être soit des branches basées sur commit (toutes les révisions après base-0 sont créées par commit), soit des branches basées sur tag (toutes les révisions sont créées par tag). Les commandes telles que replay, update, et star-merge sont basées sur la présomption que vous suivez cette règle. Même s'il peut être tentant, dans d'obscures circonstances, de mélanger commit et tag sur une même branche -- c'est généralement peu recommandable.

Cueillette de changements ( cherrypicking )

Jusqu'à présent nous avons appris à coordonner, d'une manière asynchrone, des projets basés sur des branches élémentaires issues d'une seule branche principale. (voir « Branches élémentaires -- Gérer les changements privés » et « Développement multi-branche -- La coopération sous forme de fusion en étoile »)

Dans ce chapitre, nous évoquerons sommairement une troisième forme de branche utile quand le projet est constitué de multiples branches ( « fork ») de même niveau.

Supposons, d'une manière abstraite, que la branche principale d'Alice et Bob ait pris de l'ampleur :

mainline
--------
base-0
patch-1
....
patch-23
patch-24
patch-25
...
patch-42

À un moment donné, peut-être à cause de controverse dans les choix fait par la branche mainline, un nouveau développeur, Derick, déclare une scission (« fork ») et démarre sa propre branche :

mainline                derick
--------                ------
base-0          ------> base-0
patch-1        '
....          '
patch-23 ----'
patch-24
patch-25
...
patch-42

On sait déjà que Derick peut utiliser update ou replay pour rester à jour avec la branche principale, mais s'il ne veut pas ? Comment faire si Derick veut les changements du patch-25 et patch-42, mais pas les autres patchs postérieurs au patch-23 de mainline ?

Derick peut appliquer des changements spécifiques de mainline en spécifiant la révision exacte qu'il souhaite, plutôt que de spécifier une version :

% cd ~/wd

% tla get hello-world--derick--0.1 derick

% cd derick

% tla replay -A lord@emf.net--2003-example \
         hello-world--mainline--0.1--patch-23

% tla replay -A lord@emf.net--2003-example \
         hello-world--mainline--0.1--patch-42

% tla missing -A lord@emf.net--2003-example \
         hello-world--mainline--0.1
patch-24
patch-25
...
patch-41


% tla logs -A lord@emf.net--2003-example \
         hello-world--mainline--0.1
base-0
patch-1
...
patch-22
patch-23
patch-42

La « cueillette » de changements de cette manière n'est pas nécessairement facile ou même pratique. Cela dépend, par exemple, si les changesets de mainline sont « propres ». (voir « Bien utiliser les commit -- L'idée d'un changeset « propre » »)

Néanmoins, pour certains projets, ceux caractérisés par de nombreuses scissions, cette technique peut être utile.

Note

Plusieurs révisions peuvent être ré-appliquées avec une seule commande, simplement en les indiquant toutes sur la même ligne de commande. La commande replay a également une option --list qui peut être utile pour en cueillir plusieurs à la fois. Si vous ré-appliquez souvent une série de révision, vous devriez regarder l'option --list dans tla replay --help.

Projets multi-arborescence et gestion de configuration

Vous pouvez définir des « méta-projets » composés de plusieurs projets traités séparément par arch. Cela permet de diviser un grand projet en plusieurs petits, plus faciles à gérer, chacun d'eux peut être développé indépendamment des autres, et chacun d'eux peut faire partie d'un ou plusieurs méta-projets.

Cela s'accomplit en écrivant des « spécifs de config », qui définissent le contenu d'un méta-projet et comment ils doivent être organisés dans l'arborescence.

Par exemple, arch lui-même est un méta-projet. L'arborescence contient :

dists/
  dists/src/
    dists/src/arch/
    dists/src/file-utils/
    dists/src/ftp-utils/
    dists/src/hackerlab/
    dists/src/shell-utils/

Chacun de ces répertoires est la racine de l'arborescence d'un projet (qui contient un sous-répertoire nommé « {arch} »).

Le répertoire le plus haut, dist contient également un sous-répertoire nommé configs. Dans ce sous-répertoire se trouve les fichiers de configuration du méta-projet. Par exemple :

dists/
  dists/configs/
    dists/configs/regexps.com/  # Tom's configuration files
      dists/configs/regexps.com/devo.arch
      dists/configs/regexps.com/release-template.arch

Ci-dessous, le contenu de devo.arch:

#
# Check out an arch distribution from the devo branches.
# Latest revisions.
#

./src                   lord@regexps.com--2002/package-framework--devo
./src/arch              lord@regexps.com--2002/arch--devo
./src/file-utils        lord@regexps.com--2002/file-utils--devo
./src/ftp-utils         lord@regexps.com--2002/ftp-utils--devo
./src/hackerlab         lord@regexps.com--2002/hackerlab--devo
./src/shell-utils       lord@regexps.com--2002/shell-utils--devo
./src/text-utils        lord@regexps.com--2002/text-utils--devo

Chaque ligne (ni vide, ni commentaire) est au format :

LOCATION             CONTENTS

ce qui signifie, pour créer le méta-projet, récupère la révision indiquée par CONTENTS et installe-la dans LOCATION. La zone CONTENTS peut être une branche (signifiant, prendre la dernière révision de la dernière version de cette branche), une version (signifiant, prendre la dernière révision de cette version), ou le nom d'une révision (signifiant cette révision, exactement).

Pour récupérer une arborescence de arch complète, je récupère dists à partir de devo, puis j'utilise build-config:

% tla get dists--devo dists
[....]

% cd dists

% tla build-config regexps.com/dists.devo
[....]

Une fois que vous avez l'arborescence d'un méta-projet, voici quelques commandes utiles :

cat-config : affiche les informations de la configuration d'un
             projet-multiple

Cette commande peut être utile pour générer une liste de sous-projets sur lesquels on souhaite réitérer une commande :

% tla cat-config CFGNAME | awk '{print $1}' | xargs ...

De plus, l'option --snap peut être utilisée pour la création d'une configuration qui nomme les sous-projets par leur version plutôt que par leur révision. Elle examine l'arborescence du projet pour voir quelles révisions sont actuellement installées dans chaque LOCATIONs. Ensuite elle écrit une nouvelle configuration qui spécifie ces REVISIONS précisément. C'est utile, par exemple, pour enregistrer les versions spécifiques que vous êtes prêt à utiliser pour une distribution.

Bibliothèque de révision, les bases

Dans de nombreux cas, il est utile d'avoir une bibliothèque contenant l'arborescence d'un grand nombre de révisions -- par exemple, toutes les révisions d'une version particulière. Pour être pratique, cependant, une telle bibliothèque doit être représentée d'une manière efficace.

Les liens Unix sont une solution naturelle pour stocker ce genre de bibliothèque. Chaque révision successive d'une série est une copie de la précédente, mais dont les fichiers non modifiés sont partagés par des liens physiques (hard-link).

Arch fournit des commandes pour aider à construire, maintenir et explorer de telles bibliothèques.

Comme effet de bord sympathique, le traitement de plusieurs commandes arch est accéléré si les révisions dont vous avez besoin se trouvent dans votre bibliothèque de révisions. Vous pourrez lire d'autres informations à ce propos dans le chapitre suivant.

L'emplacement de votre bibliothèque de révisions

Pour démarrer une nouvelle bibliothèque, commencez par créer un nouveau répertoire (DIR) et enregistrer son emplacement :

% tla my-revision-library DIR

Vous pouvez vérifier l'emplacement de votre bibliothèque avec :

% tla my-revision-library

ou effacer son inscription :

% tla my-revision-library -d DIR

Notez que vous pouvez avoir plusieurs bibliothèques de révisions : en fait, vous avez une liste des chemins (path) d'accès de toutes vos bibliothèques.

Format d'une bibliothèque de révision

Une bibliothèque de révision contient des sous-répertoires de la forme :

ARCHIVE-NAME/CATEGORY/BRANCH/VERSION/REVISION/

Chaque répertoire REVISION contient les sources complets d'une révision particulière, ainsi que quelques sous-répertoires et fichiers :

REVISION/,,patch-set/

        Le patch-set qui a créé cette révision à partir de son
        ascendant (sauf s'il s'agit d'une révision de base)

Même si les permissions des fichiers dans la bibliothèque de révision sont déterminées par celles du patch-set, vous ne devez jamais modifier les fichiers d'une bibliothèque de révision. En faisant cela vous pourriez rencontrer de sérieux problèmes avec certaines commandes de arch.

Ajouter manuellement une révision à une bibliothèque

Vous pouvez ajouter une révision donnée à votre bibliothèque avec :

% tla library-add REVISION

library-add ne va pas simplement ajouter REVISION à votre bibliothèque, mais également toutes les révisions précédentes (récursivement) de la version de REVISION.

Si vous voulez ajouter seulement REVISION et aucune autre, utilisez l'option --sparse :

% tla library-add --sparse REVISION

Enlever une révision d'une bibliothèque

Pour enlever une révision particulière d'une bibliothèque, utilisez :

% tla library-remove REVISION

Soyez conscient de quelques limitations dans la version actuelle de arch : supposons que vous ayez ajouté trois révisions successives, A, B et C. Et vous enlevez B, puis remettez B. Maintenant il y a des chances pour que le partage de fichier entre B et C ne soit pas optimal, la bibliothèque sera plus grosse que nécessaire. (Vous pouvez arrangez ça en enlevant et remettant C).

Afficher le contenu d'une bibliothèque

La commande library-archives affiche toutes les archives enregistrées dans la bibliothèque :

% tla library-archives
ARCHIVE-NAME
ARCHIVE-NAME
...

De la même manière, vous pouvez afficher les catégories, branches, versions et révisions :

% tla library-categories [ARCHIVE]
% tla library-branches [ARCHIVE/CATEGORY]
% tla library-versions [ARCHIVE/BRANCH]
% tla library-revisions [ARCHIVE/VERSION]

Fichiers individuels dans une bibliothèque de révisions

Vous pouvez trouver un fichier individuel dans une bibliothèque avec :

% tla library-file FILE [REVISION]
PATH

ou obtenir son contenu avec :

% tla cat-library-file FILE [REVISION]
...file contents...

Ces deux commandes acceptent les options --id et --this. Avec --id, l'argument FILE est interprété comme un identifiant d'inventaire (inventory id), et le fichier ayant cet identifiant est trouvé.

Avec --this, FILE est interprété comme un fichier relatif au répertoire en cours, qui devrait faire parti de l'arborescence d'un projet. L'identifiant d'inventaire de ce fichier est retrouvé et le fichier correspondant sera trouvé dans REVISION.

Déterminer les pré-requis d'un patch-set

% tla touched-files-prereqs REVISION

Cette commande examine le patch-set pour REVISION et tous les patch-sets précédents de la même version (il effectue les recherches dans votre bibliothèque plutôt que dans l'archive). Il affiche la liste des patchs qui recouvrent un ensemble de fichiers et répertoires -- en d'autres termes, il vous indique quels patchs peuvent être appliqués indépendamment des autres. Cette commande a une option pour ne pas tenir compte de fichiers ayant un certain schéma (ex. "=README" ou "ChangeLog"). Il a une option pour exclure de l'affichage la liste des patchs qui ont déjà été appliqués à un projet donné. Il a une option pour afficher les fichiers qui sont recouverts.

Utilisation avancée des bibliothèques de révisions

Par défaut, quand vous récupérez (get) une révision d'une archive, arch enregistre une copie de base (« pristine copy ») de cette révision dans le répertoire {arch}.

Par défaut également, quand vous récupérez une révision (get), arch construit la révision en cherchant l'ascendant import ou l'ascendant le plus récent mis en cache -- puis applique les derniers patchs pour construire la révision que vous souhaitez.

get et les opérations similaires peuvent être accélérées et utiliser moins de place en utilisant les bibliothèques de révisions. Par exemple, si get trouve la révision que vous demandez dans une bibliothèque, il va la copier directement à partir de là (plutôt que de la construire à partir des patchs) et évitera de créer une copie locale (« pristine copy ») dans le répertoire {arch}.

Tout ça est très bien -- mais il peut devenir pénible d'avoir à se souvenir d'ajouter (library-add) pour chaque révisions à votre bibliothèque. Cette section vous montrera comment automatiser ce processus.

Bibliothèque de révision avide (greedy)

Dans le cas d'une « bibliothèque de révision avide », lorsque arch regarde si elle contient une révision donnée, et qu'elle ne la contient pas, arch l'ajoutera automatiquement.

Vous pouvez rendre une bibliothèque de révision avide avec la commande :

% tla library-config --greedy DIR

Bibliothèque de révision clairsemée (sparse)

Quand arch ajoute une révision à une bibliothèque avide, normalement il le fait à la manière habituelle de library-add : il ajoute également toutes les révisions précédentes de la même version.

Si vous ajoutiez une révision, dans une bibliothèque, à la main vous pourriez l'éviter en utilisant l'option --sparse de library-add. Pour obtenir ce comportement pour les révisions ajoutés automatiquement, utilisez :

% tla library-config --sparse DIR

qui signifie que si une révision est automatiquement ajoutée dans la bibliothèque située à DIR, elle sera ajoutée avec l'option --spare de la commande library-add utilisée.

Liens physiques de l'arborescence

Attention!

Pour éviter des confusions, n'utilisez pas le dispositif suivant si vous ne comprenez pas (a) ce qu'est un lien physique (« hard-link ») et (b) ce que signifie pour un éditeur de « casser un lien physique en éditant un fichier ». Si vous comprenez ces termes, et savez que l'éditeur que vous utilisez va effectivement casser le lien physique, utilisez le dispositif à votre aise.

Vous pouvez rapidement récupérer (get) une révision d'une bibliothèque sans la recopier, mais à la place en créant un lien physique vers celle-ci :

% tla get --link REVISION

La commande build-config a une option similaire :

% tla build-config --link REVISION

Cela peut préserver énormément d'espace disque et accélérer l'opération get.

(Lorsque vous utilisez une arborescence liée physiquement il y a bien sûr une petite chance pour que les choses n'aillent pas comme prévu et que vous modifiiez un fichier de la révision de la bibliothèque. Dans ce cas, arch le remarquera et affichera un message d'erreur vous demandant d'enlever et reconstruire la révision dans la bibliothèque).

En résumé

Pour résumer, une configuration pratique et efficace implique :

  1. Créer un ou plusieurs répertoires de bibliothèques de révision.
  2. Rendez au moins quelques unes de ces bibliothèques avides et éventuellement clairsemées.
  3. Utilisez l'option --link pour get et build-config

Lorsque vous travaillez de cette manière, arch va ajouter les révisions dans les bibliothèques automatiquement, il va chercher les bibliothèques à l'emplacement (device) approprié (pour les liens physiques). Parmis ceux-là il va chercher en premier pour une bibliothèque qui contient déjà la même version que la révision que vous souhaitez et, sinon, pour une bibliothèque avide.

Automatiser certaines procédures avec les crochets (hooks)

Dans certaines circonstances, il est très utile d'attacher des actions lors de la détection de changements dans une archive. Par exemple, vous voudrez envoyer un email de notification lorsqu'une nouvelle révision est archivée.

Ce processus est possible avec arch au moyen de crochets. Chaque fois que arch exécute une commande qui modifie une archive, arch va lancer ~/.arch-params/hook, qui doit être exécutable.

Arguments envoyés aux crochets

Lorsque arch exécute une commande qui affecte une archive, il va lancer le crochet avec comme premier argument le nom de l'action effectuée. Si un utilisateur lance une commande (telle que make-archive) le crochet va être appelé plusieurs fois avec de multiples arguments (tels que make-archive, make-category, make-branche, et make-version).

Les arguments susceptibles d'être vus sont :

commit, import, make-archive, make-branch, make-category, make-version,
precommit et tag.

Toutes ces commandes sont appelées après que la commande en question ait été exécutée avec succès -- excepté pour precommit. Le crochet precommit, comme son nom le suggère, est lancé avant chaque commit, et s'il renvoi un non-zéro en sortie, le commit est annulé. Ainsi il peut être utilisé pour accepter les commits sous condition tels que la possibilité de compiler, le succès de tests unitaires, etc.

Variables d'environnement passées aux crochets

tla passe certaines variables aux crochets lorsque c'est approprié. Les variables passées par tla sont préfixées avec ARCH_. Les variables susceptibles d'être passées sont :

Nom Description Vue par Exemple
ARCHIVE Archive involved all lord@emf.net--2003-example
CATEGORY Name of category created make-category hello-world
BRANCH Name of branch created make-branch mainline
VERSION Name of version created make-version 0.1
REVISION Name of revision involved import,tag,commit patch-6
LOCATION Location of archive make-archive ~/{archives}/2003-example
TREE_ROOT Root of working arch tree commit,import ~/wd
TAGGED_ARCHIVE Archive being tagged off tag lord@emf.net--2003-example
TAGGED_REVISION Revision being tagged off tag tla--devo--1.2--patch-1

Crochets spécifiques aux archives

Étant donné que les crochets tels que precommit peuvent être spécifiques aux archives et mis à jour en fonction de chaque archive, il est recommandé de faire un script ~/.arch-params/hook tel que celui-là :

#!/bin/sh
hook="$ARCH_TREE_ROOT/{arch}/=hook"
if [ -x "$hook" ] ;  then
   "$hook" $@
fi

Un exemple d'utilisation de crochets

#!/bin/sh

if [ "$1" == "commit" ]; then
   tla push-mirror lord@emf.net--2003-example \
      lord@emf.net--2003-example-MIRROR;
   fi

Un exemple plus complexe d'utilisation des crochets

#!/bin/sh

case "$1" in
   commit)
      case "$ARCH_CATEGORY" in
         hello-world)
            case "$ARCH_BRANCH" in
              mainline)
                   RELEASETYPE="stable"
              ;;
              devel)
                 RELEASETYPE="unstable"
              ;;
             )

            echo "The $RELEASETYPE version of Hello, World been upgraded. \
               New versions are available at ftp.hello.com" |\
               mailto hello-users@hello.com -s "Hello upgraded"
         ;;
         goodbye-world)
            case "$ARCH_BRANCH" in
              mainline)
                   RELEASETYPE="stable"
              ;;
              devel)
                 RELEASETYPE="unstable"
              ;;
                 RELEASETYPE="[unknown]"
             )
            esac;
            echo "The stable version of Goodbye, Cruel World been upgraded. \
               New versions are available at ftp.hello.com" |\
               mailto goodbye-users@hello.com -s "Goodbye upgraded"
         ;;
       esac
   ;;
esac

Problème de fiabilité avec les crochets

Malheureusement, quelques lois de la physique fondamentale de l'univers font qu'il est impossible à arch de garantir qu'un crochet va être appelé une seule fois seulement pour chaque nouvelle catégorie, branche, version ou révision. Une interruption (normalement rare) au mauvais moment ou un problème du système peut entraîner une notification plusieurs fois pour une même opération sur l'archive.

En conséquence, les actions des crochets doivent être étudiées pour être robustes face à cette éventualité.

De plus, si arch a été lancé plusieurs fois simultanément, les crochets vont être lancés simultanément également. Cela signifie que les projets utilisant des crochets doivent faire attention à ce que ces derniers puissent être lancés simultanément.

Accélérer arch en mettant les révisions des archives en cache

Ce chapitre explique une technique pour accélérer l'accès à une archive arch.

Considérons une version arch qui contient de nombreuses révisions :

mainline
--------
base-0
patch-1
....
patch-23
patch-24
patch-25
...
patch-42

Supposons qu'un utilisateur (sans copie locale) veut récupérer (get) la révision patch-42. get va en premier lieu récupérer et décompresser la révision base-0, et ensuite récupérer chaque changeset patch-<N>, dans l'ordre, et les appliquer à l'arborescence.

Si la liste des changesets à appliquer est longue, ou la somme de leur taille très grande en comparaison de la taille de l'arborescence, alors l'implémentation de get est inutilement inefficace.

Un moyen d'accélérer get est en mettant les révisions en cache -- en stockant des copies « pré-construites » de quelques révisions dans l'archive.

Par exemple, la commande :

% tla cacherev -A lord@emf.net--2003-example \
        hello-world--mainline--0.1--patch-40

va construire la révision patch-40, en faire un paquet avec tar, et stocker une copie de ce paquet dans le répertoire du patch-40 de l'archive.

En conséquence, un get du patch-42 va en premier lieu récupérer la copie mise en cache de la révision patch-40, puis récupérer et appliquer les changesets patch-41 et patch-42 : évitant 40 changesets.

Note

Pour l'instant, c'est à vous de décider quelles révisions mettre en cache ou non. Vous pourriez décider, par exemple, de mettre en cache automatiquement certaines révisions à partir d'une tache cron ou à la main tout simplement lorsque vous constatez que get est trop lent. Dans le futur, nous espérons ajouter un moyen plus automatique pour mettre les révisions en cache.

Le format arch d'un changeset

Un changeset arch est un répertoire contenant un certain nombre de fichiers et répertoires. Ils sont décrit ci-dessous :

Fichiers :

orig-dirs-index
mod-dirs-index
orig-files-index
mod-files-index

Format :

<file path><tab><id>

Tri :

sort -k 2

Ils contiennent un index de tous les fichiers et répertoires ajoutés, déplacés, ou modifiés entre deux arborescences.

Fichiers :

original-only-dir-metadata
modified-only-dir-metadata

Format :

<metadata><tab><name>

Tri :

sort -t '<tab>' -k 2

Le champ <metadata><tab><name> contient la sortie du programme file-metadata avec l'option --permissions. Quelques exemples de sorties :

--permissions 777

Cette sortie peut également être utilisée pour les options et arguments du programme set-file-metadata. Les prochaines versions de arch ajouteront d'autres options (entre autres permissions).

Répertoires :

removed-files-archive
new-files-archive

Chacun de ces répertoires contient une copie complète de tous les fichiers présents seulement dans l'arborescence originale (removed-files-archive) ou dans l'arborescence modifiée (new-files-archive). Chaque fichier sauvegardé est archivé au même emplacement que dans l'arborescence source, avec les permissions (au moins) préservées.

Répertoire :

patches

Ce répertoire contient une arborescence dont la structure des répertoires est la même que la structure des répertoires de l'arborescence modifiée. Il contient les données de modification pour les répertoires et les fichiers communs aux deux arborescences.

Pour un fichier new-name stocké dans l'arborescence modifié, le répertoire patches devrait contenir :

  • new_name.link-orig

    Le fichier original est un lien symbolique. new_name.link-orig est un fichier texte contenant la cible de ce lien terminé par un retour à la ligne.

    Ce fichier n'est présent que si la cible du lien a changé, ou si le lien a été remplacé par un fichier normal.

  • new_name.link-mod

    Le fichier modifié est un lien symbolique et ce fichier est un fichier texte contenant la cible pour le lien terminé par un retour à la ligne.

    Ce fichier n'est présent que si le lien cible a changé, ou si le lien remplace un fichier normal.

  • new_name.original

    C'est une copie complète du fichier de l'arborescence originale, dont les permissions sont (si possible) préservées.

    Ce fichier n'est présent que si le fichier a été remplacé par un lien symbolique, ou si le contenu du fichier ne peut pas être traité par diff(1).

  • new_name.modified

    C'est une copie complète du fichier de l'arborescence modifiée, dont les permissions sont (si possible) préservées.

    Ce fichier n'est présent que si le fichier remplace un lien symbolique, ou si son contenu ne peut pas être traité par diff(1).

  • new_name.patch

    C'est le résultat d'un diff entre le fichier orignal et le fichier modifié. Une version courante de diff (GNU diff) génère un résultat non-standard en oubliant une copie des lignes du résultat qui sont identiques entre le fichier original et le fichier modifié. Ainsi, les fichiers .patch peuvent avoir le même bogue. Heureusement, la version courante de patch (GNU patch) accepte de recevoir un tel résultat.

  • new_name.meta-orig

  • new_name.meta-mod

    Fichier de « metadata » (actuellement uniquement les permissions) modifiées entre deux versions du fichier. Ces fichiers contiennent la sortie du programme file-metadata avec les options --symlink --permissions, utilisable pour comparer deux sorties similaires, et pour être utilisé comme options et arguments à set-file-metadata.

  • new_name/=dir-meta-orig

  • new_name/=dir-meta-mod

    Répertoire « metadata » (actuellement seulement les permissions) des modifications entre deux versions des répertoires contenant ces fichiers. Ces fichiers contiennent la sortie du programme file-metadata avec les options --symlink --permissions, utilisable pour comparer deux sorties similaires, et être utilisé comme options et arguments à set-file-metadata.

Note

Si un fichier normal (ou un lien symbolique) remplace un répertoire, ou vice et versa, il est enregistré en tant que fichier (ou lien) effacé (ou ajouté) dans une arborescence et ajouté (ou effacé) de l'autre.

Adaptation de la convention de nommage dans l'inventaire

Dans « inventaire d'une arborescence », vous avez appris comment la commande tla inventory classait les fichiers dans un projet suivant une convention de nommage. Cette section explique comment vous pouvez adapter cette convention de nommage.

Quand adapter la convention de nommage ?

Il est préférable d'effectuer l'adaptation de la convention de nommage au début : avant l'import de la première révision.

Si vous devez faire des changements plus tard, alors il est impératif que vos changements ne changent pas la classification des fichiers déjà présents dans les dernières révisions de votre projet au moment ou vous faites les changements (sinon, vous risquez d'obtenir un comportement étrange et indésirable).

Comment adapter une convention de nommage ?

Vous devriez commencer par revoir l'algorithme de la convention de nommage dans « La convention de nommage de arch ». Vous pouvez modifier cet algorithme en modifiant les expressions rationnelles (regexp) utilisées pour chaque test de catégorie.

Vous pouvez adapter la convention de nommage en modifiant le fichier ./{arch}/=tagging-method de votre arborescence. Ce fichier est créé et initialisé par la commande id-tagging-method, il contient une ligne qui nomme la méthode d'identification (names, explicit, tagline, (ou implicit, obsolète maintenant, mais utilisé dans quelques vieux projets, y compris arch lui-même)).

En particulier, =tagging-method peut contenir des lignes vides et des commentaires (lignes commençant par « # ») et directives, une par ligne. Les directives permises sont :

tagline
implicit
explicit
names
        spécifie la méthode d'identification utilisée pour
        cette arborescence

exclude RE
junk RE
backup RE
precious RE
unrecognized RE
source RE
        spécifie une expression rationnelle à utiliser pour
        indiquer la catégorie des fichiers

Les expressions rationnelles sont spécifiées dans la syntaxe « Posix ERE » (la même syntaxe utilisée par egrep, grep -E, et awk) et ont comme valeurs par défaut l'implémentation de la convention de nommage décrite dans « La convention de nommage de arch ».

Une directive d'expression rationnelle peut être utilisée plusieurs fois, dans chaque cas les expressions sont concaténées comme alternatives. Ainsi, par exemple :

source  .*\.c$
source  .*\.h$

est équivalent à :

source (.*\.c$)|(.*\.h$)

Expressions rationnelles par répertoire

Le répertoire de l'arborescence peut contenir un fichier .arch-inventory.

Le fichier .arch-inventory peut contenir des déclarations d'expressions rationnelles de la même manière que dans =taging-method (c'est-à-dire, une pour excludes, une pour junk etc.) Appelons les « dir-local ».

Lors du parcours de l'arborescence, chaque fichier est classé par son nom comme cela. Les étapes changées par .arch-inventory sont marquées par [*] :

  1. "." et ".." restent exclues, de toutes façons.
  2. [*] si les fichiers exclus ont été omis de l'inventaire, et soient de dir-local ou des expressions globales, le fichier est exclu.
  3. si le fichier est un fichier de contrôle, c'est un source.
  4. si le fichier tombe dans une des « catégories formelles » (les fichiers ",," et "++") il est classé respectivement comme junk ou precious.
  5. [*] les expressions de dir-local sont testées dans l'ordre habituel : « junk, backup, precious, unrecognized, source ». Si le fichier correspond, il est convenablement classé.
  6. Les expressions globales sont testées dans le même ordre.
  7. Dans les autres cas, le fichier est « unrecognized ».

The GNU General Public License

Arch is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License (GPL) as published by the Free Software Foundation (and reproduced below).

This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License (reproduced below) for more details.

J'ai choisi la licence GPL pour ce logiciel car je crois qu'elle reflète au mieux le devoir des ingénieurs informaticiens envers la société. C'est la meilleure licence pour les utilisateurs, pour mes collègues ingénieurs, et pour la société dans son ensemble. Devenant de plus en plus largement considérée, cette licence est un document essentiel et prépondérant qui mérite d'être étudié en tant que tel.

Pour le moment, dans le contexte commercial qui entoure la plupart des licences propriétaires (celles qui sont loin de protéger les libertés et promouvoir les obligations de la GPL), le choix de cette licence, rend difficile pour moi, de rentabiliser les coûts de développement de Arch et poursuivre ce travail. Ce sont de sérieux problèmes, à mon avis. S'il vous plait, consultez « Uh... un petit peu d'aide ici ? ».

                    GNU GENERAL PUBLIC LICENSE
                       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit
to using it.  (Some other Free Software Foundation software is
covered by the GNU Library General Public License instead.)  You can
apply it to your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and
charge for this service if you wish), that you receive source code
or can get it if you want it, that you can change the software or
use pieces of it in new free programs; and that you know you can do
these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the
rights.  These restrictions translate to certain responsibilities
for you if you distribute copies of the software, or if you modify
it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights
that you have.  You must make sure that they, too, receive or can
get the source code.  And you must show them these terms so they
know their rights.

  We protect your rights with two steps: (1) copyright the software,
and (2) offer you this license which gives you legal permission to
copy, distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make
certain that everyone understands that there is no warranty for this
free software.  If the software is modified by someone else and
passed on, we want its recipients to know that what they have is not
the original, so that any problems introduced by others will not
reflect on the original authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making
the program proprietary.  To prevent this, we have made it clear
that any patent must be licensed for everyone's free use or not
licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.

                    GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which
contains a notice placed by the copyright holder saying it may be
distributed under the terms of this General Public License.  The
"Program", below, refers to any such program or work, and a "work
based on the Program" means either the Program or any derivative
work under copyright law: that is to say, a work containing the
Program or a portion of it, either verbatim or with modifications
and/or translated into another language.  (Hereinafter, translation
is included without limitation in the term "modification".)  Each
licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the
Program is covered only if its contents constitute a work based on
the Program (independent of having been made by running the
Program).  Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any
warranty; and give any other recipients of the Program a copy of
this License along with the Program.

You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for
a fee.

  2. You may modify your copy or copies of the Program or any
portion of it, thus forming a work based on the Program, and copy
and distribute such modifications or work under the terms of Section
1 above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that
    in whole or in part contains or is derived from the Program or
    any part thereof, to be licensed as a whole at no charge to all
    third parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you
    provide a warranty) and that users may redistribute the program
    under these conditions, and telling the user how to view a copy
    of this License.  (Exception: if the Program itself is
    interactive but does not normally print such an announcement,
    your work based on the Program is not required to print an
    announcement.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work
based on the Program, the distribution of the whole must be on the
terms of this License, whose permissions for other licensees extend
to the entire whole, and thus to each and every part regardless of
who wrote it.

Thus, it is not the intent of this section to claim rights or
contest your rights to work written entirely by you; rather, the
intent is to exercise the right to control the distribution of
derivative or collective works based on the Program.

In addition, mere aggregation of another work not based on the
Program with the Program (or with a work based on the Program) on a
volume of a storage or distribution medium does not bring the other
work under the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms
of Sections 1 and 2 above provided that you also do one of the
following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of
    Sections 1 and 2 above on a medium customarily used for software
    interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a
    medium customarily used for software interchange; or,

    c) Accompany it with the information you received as to the
    offer to distribute corresponding source code.  (This
    alternative is allowed only for noncommercial distribution and
    only if you received the program in object code or executable
    form with such an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as
a special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.

  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this
License.  However, parties who have received copies, or rights, from
you under this License will not have their licenses terminated so
long as such parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on
the Program), the recipient automatically receives a license from
the original licensor to copy, distribute or modify the Program
subject to these terms and conditions.  You may not impose any
further restrictions on the recipients' exercise of the rights
granted herein.  You are not responsible for enforcing compliance by
third parties to this License.

  7. If, as a consequence of a court judgment or allegation of
patent infringement or for any other reason (not limited to patent
issues), conditions are imposed on you (whether by court order,
agreement or otherwise) that contradict the conditions of this
License, they do not excuse you from the conditions of this License.
If you cannot distribute so as to satisfy simultaneously your
obligations under this License and any other pertinent obligations,
then as a consequence you may not distribute the Program at all.
For example, if a patent license would not permit royalty-free
redistribution of the Program by all those who receive copies
directly or indirectly through you, then the only way you could
satisfy both it and this License would be to refrain entirely from
distribution of the Program.

If any portion of this section is held invalid or unenforceable
under any particular circumstance, the balance of the section is
intended to apply and the section as a whole is intended to apply in
other circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is
willing to distribute software through any other system and a
licensee cannot impose that choice.

This section is intended to make thoroughly clear what is believed
to be a consequence of the rest of this License.

  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces,
the original copyright holder who places the Program under this
License may add an explicit geographical distribution limitation
excluding those countries, so that distribution is permitted only in
or among countries not thus excluded.  In such case, this License
incorporates the limitation as if written in the body of this
License.

  9. The Free Software Foundation may publish revised and/or new
versions of the General Public License from time to time.  Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.

Each version is given a distinguishing version number.  If the
Program specifies a version number of this License which applies to
it and "any later version", you have the option of following the
terms and conditions either of that version or of any later version
published by the Free Software Foundation.  If the Program does not
specify a version number of this License, you may choose any version
ever published by the Free Software Foundation.

  10. If you wish to incorporate parts of the Program into other
free programs whose distribution conditions are different, write to
the author to ask for permission.  For software which is copyrighted
by the Free Software Foundation, write to the Free Software
Foundation; we sometimes make exceptions for this.  Our decision
will be guided by the two goals of preserving the free status of all
derivatives of our free software and of promoting the sharing and
reuse of software generally.

                            NO WARRANTY

  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND
PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE
DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
CORRECTION.

  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the
greatest possible use to the public, the best way to achieve this is
to make it free software which everyone can redistribute and change
under these terms.

  To do so, attach the following notices to the program.  It is
safest to attach them to the start of each source file to most
effectively convey the exclusion of warranty; and each file should
have at least the "copyright" line and a pointer to where the full
notice is found.

    <one line to give the program's name and a brief idea of what it
    does.>
    Copyright (C) <year> <name of author>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of
    the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public
    License along with this program; if not, write to the Free
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
    MA 02111-1307 USA


Also add information on how to contact you by electronic and paper
mail.

If the program is interactive, make it output a short notice like
this when it starts in an interactive mode:

    Gnomovision version 69, Copyright (C) year name of author
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type
    `show w'.  This is free software, and you are welcome to
    redistribute it under certain conditions; type `show c' for
    details.

The hypothetical commands `show w' and `show c' should show the
appropriate parts of the General Public License.  Of course, the
commands you use may be called something other than `show w' and
`show c'; they could even be mouse-clicks or menu items--whatever
suits your program.

You should also get your employer (if you work as a programmer) or
your school, if any, to sign a "copyright disclaimer" for the
program, if necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the
  program `Gnomovision' (which makes passes at compilers) written by
  James Hacker.

  <signature of Ty Coon>, 1 April 1989
  Ty Coon, President of Vice

This General Public License does not permit incorporating your
program into proprietary programs.  If your program is a subroutine
library, you may consider it more useful to permit linking
proprietary applications with the library.  If this is what you want
to do, use the GNU Library General Public License instead of this
License.

Uh.... un petit peu d'aide ici ?

Arch est un projet supporté par la communauté des logiciels libres (Community Supported Free Software Project). Je compte sur le support financier de la communauté pour pouvoir développer arch et les autres projets libres sur lesquels je travaille.

Si vous pouvez m'aider, même juste un peu, s'il vous plaît faites-le. Je peux accepter les contributions à lord@emf.net sur Paypal. Des arrangements sont possibles pour que les contributions plus importantes que quelques dizaines de dollars soient exonérées de taxes en tant qu'organisation non commerciale (contactez-moi si vous souhaitez le faire).

Et enfin, que vous représentiez une organisation commerciale ou non, je propose un service de souscription aux publications (Release Subscription Service) -- un service facturé formellement, approprié aux transactions commerciales, comme contribution et reconnaissance à mes yeux comme un réel client de mon travail de développement. (Encore une fois, s'il vous plaît, contactez-moi si cela vous intéresse).