Archives de la catégorie Astuces et Outils

Git + Subversion : arrêtez d’ignorer ce que vous devriez ignorer (?!)

Parfois on se retrouve à faire du Git, en local, sur un dépôt distant Subversion. Ça arrive en fait dans deux situations :

  • On est en train de passer un dépôt de Subversion vers Git, en vue d’abandonner le premier au profit du second (yay !).
  • On est obligé de bosser sur un dépôt Subversion, mais on refuse de laisser tomber le confort quotidien de Git en local.

Git propose une passerelle au moyen de la commande git svn et de ses sous-commandes. Moyennant quelques précautions d’usage, on peut ainsi travailler avec Git en local et synchroniser vers (et depuis) le dépôt Subversion distant. C’est un sujet assez vaste et j’y reviendrai plus en détail dans un prochain billet.

Toutefois, ceux qui rencontrent déjà ces situations ont sans doute remarqué un phénomène irritant : Git ne prend pas en compte la propriété svn:ignore. En fait, il ne prend en compte que svn:executable (ce qui est déjà pas mal, vu comme elle est grave utile…).

La propriété svn:ignore est similaire au fichier .gitignore : elle permet de lister des motifs de fichiers qui ne doivent pas être versionnés. Il est donc dommage qu’on n’en bénéficie pas automatiquement sur Git, risquant ainsi de versionner par erreur des fichiers qui devraient être ignorés.

Voilà pourquoi j’ai développé un petit outil qui va automatiquement synchroniser vos svn:ignore vers vos .gitignore, à tout moment, pour votre master (c’est-à-dire votre trunk distant), sans écraser d’éventuelles infos déjà présentes dans vos .gitignore… C’est le premier d’une série probable de petits scripts du même genre, destinés à faciliter l’utilisation de Git au quotidien.

Comme mon récent outil git-basecamp, il est disponible en open-source, et documenté, sur GitHub. Je vous invite donc à jeter un œil à mon dépôt git-helpers. Notez qu’il existe aussi une quantité de dépôts nommés « git-tools » sur Github, mais aucun de ceux que j’ai regardés n’avait cette fonctionnalité (et la plupart des aides qu’ils fournissent m’ont semblé un peu basiques…).

Enjoy !

, , , , , ,

Pas de commentaire

Comprendre et maîtriser les clés SSH

Git base toute sa gestion d’authentification sur le mécanisme des clés SSH. Ce système est d’ailleurs immensément utile de façon générale sous Linux, Unix et OSX, dès qu’il s’agit de s’authentifier sur une machine tierce. Afin d’avoir un maximum de confort lorsqu’on accède à un dépôt nécessitant une identification (lecture de dépôts privés ou écriture dans le cas général), il est donc important de bien maîtriser les clés SSH.

Ce billet tente de vous donner toutes les clés (ahem) pour comprendre et manipuler aisément vos identités SSH.

Après un topo rapide sur le principe des clés asymétriques, nous verrons rapidement quels algorithmes sont à favoriser, quelles tailles de clé sont acceptables, et les meilleures pratiques de protection de vos clés (tant en termes de passphrase que de gestion des droits d’accès à vos fichiers de clés).

Ces fondamentaux étant assimilés, nous pourrons vérifier si vous avez déjà des clés, comment en créer de nouvelles, et comment vous en servir efficacement et confortablement pour vos accès à des dépôts Git.

Principe des clés asymétriques

Quand vous travaillez avec des clés asymétriques, par principe, vous avez deux clés (on parle de paire de clés) : une clé publique, que vous pouvez diffuser librement, voire mettre à disposition sur un serveur de clés ; et une clé privée, qui constitue véritablement votre « identité », et ne doit jamais être diffusée : elle reste simplement présente dans votre dépôt de clés personnel.

Comme toujours en cryptographie, on peut faire deux choses avec une clé : chiffrer un contenu (l’encrypter) ou le signer (calculer une valeur unique, reposant sur le contenu concerné et sur votre clé privée, pour obtenir une valeur de signature, comme un cachet spécifique). Seule la clé « d’en face » (la publique si vous avez utilisé la privée, et inversement) permet de déchiffrer ou de vérifier la signature. Notez au passage que signer un contenu permet non seulement d’attester que vous êtes bien l’envoyeur (ou l’auteur, etc.), mais aussi que le contenu n’a pas été modifié après signature.

Une paire de clé permet donc de vous représenter vis-à-vis d’un système tiers, en lui fournissant à l’avance votre clé publique, pour ensuite communiquer avec lui à l’aide de votre clé privée ; puisque seules les clés d’une même paire peuvent se comprendre, le système distant est à même non seulement de vérifier que vous êtes bien celui (ou celle) que vous prétendez être, mais aussi que ce qu’il reçoit est bien ce que vous envoyé. Pas mal !

Si le sujet vous intéresse, vous trouverez une tonne d’infos sur Wikipedia. Mais si j’étais vous, je finirais cet article d’abord histoire de ne pas partir sur une tangente…

RSA vs. DSA

Il existe de nombreux algorithmes de chiffrement basés sur des clés asymétriques, mais les deux dominants, et de loin, son RSA et DSA, d’après les initiales de leurs auteurs respectifs. RSA est historiquement le premier, et DSA a été développé plus récemment, comme une alternative alors qu’RSA était encore breveté.

De nombreux didacticiels, articles et documentations exploitent RSA, mais vous pouvez choisir librement RSA ou DSA pour vos clés, du moment que vous utilisez une taille suffisante (voir ci-après).

Taille de clé

Une clé a une taille, exprimée en nombre de bits. Par exemple, les clés exploitées par les certificats de chiffrement des sites web utilisant la protection SSL (vous savez, ces URLs qui démarrent en https://, par exemple votre gestion de compte bancaire en ligne) sont généralement limitées, pour des raisons légales d’origine honteuse, à 256 bits. En revanche, vos propres clés ne font pas (ou plus, suivant le pays où vous vivez) l’objet d’une telle limitation.

À ce jour, une taille de 2Ko, c’est-à-dire 2048 bits (oui, 8 fois plus qu’un certificat bancaire !) est considérée raisonnablement sécurisée pour RSA, en tout cas pour un particulier. En gros, même si la toute-puissante NSA avait envie de casser votre chiffrage pour jeter un œil à ces données, il leur faudrait quelques heures pour y parvenir. Et pour qu’ils daignent vous allouer quelques heures de leur système, vous devez en gros être un très, très gros poisson.

Donc on est tranquilles.

Notez qu’en revanche une clé DSA fait obligatoirement 1024 bits (1Ko). C’est comme ça.

Passphrase

Vous avez certainement l’habitude voir le terme password, c’est-à-dire mot de passe. Et vous avez sûrement déjà rencontré des tas de systèmes, services et outils qui vous demandent de saisir un mot de passe, en lui imposant une taille minimum (ce qui est bien) et maximum (ce qui est parfaitement stupide et contre-productif). À cause de ce maximum, justement, ces systèmes insistent pour que vous mélangiez à loisir majuscules, minuscules, chiffres et symboles, et n’utilisiez pas de termes trop évidents (dates de naissances, prénoms, noms de vos animaux, mots basiques, segments de touches du clavier, etc.).

Du coup, tout le monde se retrouve forcé d’utiliser des mots de passe genre &dF@8^Xy+, qui sont tellement tordus qu’on s’empresse de les noter sur un papier, massacrant instantanément l’utilité du mot de passe en le rendant facile à découvrir en cas de besoin (surtout quand ledit papier est un Post-It™ collé sous le clavier, voire sur l’écran) (ne rigolez pas, je l’ai déjà vu) (plusieurs fois) (en fait, si ça se trouve, vous l’avez déjà fait) (gredin(e) que vous êtes).

Par contraste, une passphrase (pas d’équivalent français satisfaisant à ma connaissance, aussi essayez de le prononcer correctement, genre passfrayz) est une petite phrase, ou tout au moins un morceau de phrase, donc plusieurs mots. Et je dis bien mots, parce qu’en l’occurrence, utiliser de vrais mots et noms ne pose plus guère de problème, dès lors qu’on en a au moins 3 ou 4, surtout s’ils n’ont aucun rapport.

« Mais on m’a toujours dit que des vrais mots Saymal™ ! », me hurlez-vous avec consternation, le sourcil vengeur.

Oui, sauf dans des jolies passphrases. Pourquoi donc ? Parce que le niveau de complexité augmente de façon plus qu’exponentielle au fil des caractères, en particulier quand on commence à découper en mots. En cryptographie, on considère qu’un mot de passe, ou une passphrase, peuvent appartenir à plusieurs niveaux de sécurité, qui correspondent à la difficulté qu’on rencontre pour les casser. La recherche sur le sujet abonde est se met à jour chaque année, notamment au sein de conférences spécialisées comme la célèbre DEFCON.

Je suis assez fan de cet excellent article de Thomas Baekdal, qui illustre bien le sujet. Imaginons une passphrase qu’il faudrait des centaines d’années, voire des millénaires, dans l’état actuel de la technologie la plus avancée, pour casser par un moyen technologique. On qualifie une telle passphrase de « sécurisée à vie » (secure for life). Eh bien, pour obtenir une telle passphrase, il suffit de combiner au moins 3 mots, pas nécessairement sans rapport, pour un total d’au moins une dizaine de caractères. Voici quelques exemples de telles passphrases :

  • this is fun (sérieux ! Il faudrait au moins 25 siècles…)
  • j’aime les noix de cajou (le système solaire aura déjà imposé d’ici qu’on casse ça…)
  • des filles à la vanille
  • san pellegrino enterre badoit
  • i love to boogie
  • tu fais du vb dommage eliane
  • entre git et svn j’ai choisi
  • plutot crever qu’installer vista

Vous avez immédiatement perçu l’avantage monstrueux d’une bonne passphrase, lecteurs fûtés que vous êtes : non seulement c’est sécurisé à vie, mais en plus c’est carrément plus facile à mémoriser !

Bon, vous allez me rétorquer que c’est vachement plus long à taper, et là je vous répondrais que oui, mais qu’il existe des tas d’outils de type agents SSH, trousseaux de clés et systèmes de mémorisation de mot de passe (dans votre navigateur par exemple), qui sont de manière générale une bonne idée (surtout si vous leur mettez un mot de passe maître, à taper une seule fois par session, qui les déverrouille explicitement). Puisque nous parlons ici spécifiquement de clés SSH, nous aborderons plus loin comment éviter la saisie systématique de sa passphrase.

Parce que ne vous avisez surtout pas de « résoudre » le pseudo-problème de la longueur du texte en utilisant une passphrase vide. Ce serait complètement stupide, parce que ça reviendrait à ne pas du tout protéger votre clé ! Donc assurez-vous d’utiliser une bonne passphrase bien solide, et préférez les agents SSH (que ne vous verrons plus bas, je le répète) pour vous éviter des saisies multiples.

Vérifier ce qu’on a comme clé

Bon, il est l’heure de vérifier si vous avez déjà une paire de clés du bon type (DSA)…

Sur tous les systèmes Linux et Unix, vos clés SSH sont normalement stockées dans un dossier .ssh à la racine de votre profil. Ouvrez donc un terminal et tapez la commande suivante :

ls -lAF ~/.ssh

Si vous avez un message d’erreur (genre « je ne connais pas ce dossier ») ou un listing ne contenant que des fichiers style authorized_keys, config ou known_hosts, vous n’avez pas encore de clé exploitable. Ce que vous cherchez, ce sont des fichiers qui, classiquement, s’appellent id_dsa (la clé privée) et id_dsa.pub (la clé publique). Ce sont de bêtes fichiers texte, avec un peu d’enrobage autour de votre clé représentée dans un format appelé Base64. Par exemple, sur mon portable, le listing donne ça :

$ ls -lAF ~/.ssh
total 48
-rw------- 1 tdd tdd    90 déc 11  2009 config
-rw------- 1 tdd tdd   736 aoû 23  2007 id_dsa
-rw------- 1 tdd tdd   609 aoû 23  2007 id_dsa.pub
-rw------- 1 tdd tdd   736 jul 17 09:17 id_dsa_git
-rw-r--r-- 1 tdd tdd   609 jul 17 09:17 id_dsa_git.pub
-rw------- 1 tdd tdd   668 avr  6 22:53 id_dsa_sips
-rw-r--r-- 1 tdd tdd 23696 jul 24 11:07 known_hosts

Comme vous pouvez le constater, ma clé fondamentale date un peu (23 août 2007), et j’ai une deuxième paire dédiée pour Git (id_dsa_git), ce qui n’a rien d’obligatoire, ainsi qu’une troisième, dont je n’ai ici que la clé privée, et qui me sert encore à autre chose.

Vous n’avez pas de clé DSA, ou vous en avez une dont vous ignorez la passphrase pour quelque raison que ce soit ? Ou peut-être en voulez-vous une dédiée pour Git ? Pas de souci, on va en créer une nouvelle !

Créer une clé

L’outil de prédilection pour créer des clés (et un peu tout ce qui touche à la crypto) est le système OpenSSL. C’est un ensemble de bibliothèques et outils en ligne de commande, présent sur tous les Linux et Unix (entre autres), qui constitue le standard de facto. Dommage qu’il soit si mal documenté… Ici, on peut passer par une surcouche spécialisée dans les clés SSH, au travers de l’outil en ligne de commande ssh-keygen.

Pour créer une paire de clés DSA, on procède comme suit. Je suppose ici que vous allez changer le nom par défaut vers id_dsa_ga (pour Git Attitude), mais si vous laissez le nom par défaut, il suffit de taper Entrée à la question correspondante. Évidemment, utilisez votre propre chemin.

$ ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/Users/tdd/.ssh/id_dsa): /Users/tdd/.ssh/id_dsa_ga
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/tdd/.ssh/id_dsa_ga.
Your public key has been saved in /Users/tdd/.ssh/id_dsa_ga.pub.
The key fingerprint is:
65:31:7e:ee:49:3a:66:cd:92:7b:02:2b:bf:b3:1a:79 tdd@CodeMagic.local
The key’s randomart image is:
+--[ DSA 1024]----+
|          o      |
|         . o     |
|          + .    |
|         o o     |
|        S   o    |
|       ..  B .   |
|      o EoB =    |
|      .ooo.+.    |
|      .+++.o     |
+-----------------+

Suivant votre version de ssh-keygen, vous n’aurez pas forcément le randomart à la fin (et en vrai, on s’en fout), et la ligne qui suit « The key fingerprint is: » sera totalement spécifique à votre propre exécution de la commande. Chaque paire de clé a une empreinte unique.

Et de fait, regardez un peu vos clés toutes neuves (vous aurez naturellement des valeurs différentes de celles présentées ici, celle de la privée étant d’ailleurs tronquée par mes soins :)

$ cat ~/.ssh/id_dsa_ga
-----BEGIN DSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,6ED59B013D8A361F

pB5eHHpvXxoz6i1jFzlKANv9W6SeHw664PV/1A90acR/Mw/ERQvTQKo3TaLaFhkb
…
NwhQFyxZZty2hn6xrv5UIAGTpjk+P2+waRmSno1Vg1x0epCp45kvFRv9AiXsOpt4
RgzPC5+a6kjPf8EtyozGoQ==
-----END DSA PRIVATE KEY-----
$ cat ~/.ssh/id_dsa_ga.pub
ssh-dss AAAAB3NzaC1kc3MAAACBAJhbQcZK8lFMvpw7trbFj51Sqjd9nKBu2xkw/kvUAQlPQPaIRLOiq92fxp+jzp97xDqpwFnvU++ptUiB1nQQ8oq8l5t5QuHwfMMnSDMXhWf2235i4Lw2DtRTbxs0UQJ1l+QxO/AjlV/POcFpq6Z0PKMosi8TslqqPaqAbQtiEX2DAAAAFQDaK1EZY12itrt0lomTAOT0QATilwAAAIAK9C0YTR0T82r7TFheo/+vU6dS9KCypEjR7rEVf7MxCJLd9MQNkVTJe7XCFnYeT9oz7h8NbYHGyDQr7EZGIchtiju6EPFWuQWEAJAHq7z9s9ygoVqyWSQo0y/6riihJk5bo+Etj//OdwndlfKg0c6UGBFg8T2i6nKsbmMMEAI+XAAAAIA+bPjEeoZhwLuCp3Bv0+B4mWgGqnb2IhRSVDQNYeHIofhiSY7prVB+O1iQhrN/EJlygkaFWNaVlPmxrXa+8i+ZGWeVlAaKJdSAsDawNjOaHTi6/Cfqm7NTrLIIeOcjjxwrPLPZ3v0tP8MFjhYFdgjooYjTDzqQmpCGVSA4hXtqhg== tdd@CodeMagic.local

Notez que les clés publiques sont généralement formatées sur une seule ligne ; dans une liste de clés (par exemple le fichier ~/.ssh/authorized_keys, qui liste les clés publiques dont les titulaires peuvent accéder à votre compte via SSH), on a donc en général une clé par ligne. La fin de la clé publique est son commentaire, qui vaut par défaut « identifiant@machine », mais peut être changé.

Dernière info sur la manipulation des fichiers de clé : on peut changer la passphrase d’une clé SSH avec la ligne de commande suivante :

$ ssh-keygen -p -f ~/.ssh/le_fichier_de_cle

La commande vous demandera votre ancienne passphrase, puis la nouvelle avec une double saisie (initiale puis de confirmation). Pratique si vous aviez saisi une passphrase un peu pourrie, par exemple. En revanche, si votre clé est compromise (vous avez des raisons de penser qu’un tiers s’est approprié votre clé privée), ne changez pas la passphrase (ça ne servira à rien) : changez de clé !

Agents SSH

Un agent SSH est un outil intégré à votre système d’exploitation qui vous permet de ne saisir la passphrase d’une clé qu’une seule fois (pendant la durée de vie de l’agent, généralement limitée à votre session, entre connexion et déconnexion).

OS X intègre cette fonction dans son outil plus général de Trousseau d’Accès (Keyring) depuis Leopard (10.5). Avant cela (par exemple Tiger, la 10.4), il fallait ruser comme décrit dans cet article. La première utilisation d’une clé entraîne l’affichage d’une demande de passphrase, et la possibilité de stocker celle-ci dans le trousseau d’accès pour éviter des saisies supplémentaires durant la session.

Ubuntu et ses variantes intègrent cette fonction aux principaux gestionnaires de fenêtre (Gnome, KDE, etc.). Le workflow est similaire à celui d’OS X : la première utilisation entraîne une demande de passphrase avec persistence dans l’agent.

Pour les autres distributions Linux et gestionnaires de fenêtre, je ne sais pas trop si un agent est déjà disponible ou pas. Vous pouvez le vérifier en ouvrant un terminal puis en tapant :

$ set | grep SSH_AUTH_SOCK

Si vous ne voyez rien s’afficher, vous n’avez pas d’agent actif ; si vous voyez quelque chose (probablement du genre /var/run/….sock), alors vous en avez un.

Si vous n’avez pas d’agent actif, vous pouvez en lancer un manuellement à l’aide de la bien-nommée commande ssh-agent. Celle-ci crée un processus résident (un daemon) et affiche la série de commandes à balancer dans l’environnement (ou dans chaque terminal) pour qu’il soit au courant que l’agent existe, et donc qu’il essaie de s’en servir. Ces commandes consistent généralement juste à définir les variables d’environnement SSH_AUTH_SOCK et SSH_AGENT_PID. Du coup quand on lance un agent à la main dans le shell courant, on récupère généralement son affichage pour l’exécuter aussi sec, comme ceci :

$ eval `ssh-agent`
Agent pid 23038

Évidemment, vous verrez un autre numéro de processus (pid), mais le principe est le même.

À partir de là, à vous de tester le comportement lors de la première utilisation d’une clé SSH : si vous voyez une interception globale vous demandant de saisir la passphrase et proposant de la stocker dans l’agent, tout baigne. Si ce n’est pas le cas, vous allez devoir ajouter la passphrase à l’agent manuellement, en utilisant la commande ssh-add. Dans ce cas, soit vous avez une seule clé, et vous n’avez pas besoin de la préciser, soit vous en avez plusieurs et il faut indiquer laquelle :

$ ssh-add ~/.ssh/id_dsa_ga
Enter passphrase for /Users/tdd/.ssh/id_dsa_ga:
Identity added: /Users/tdd/.ssh/id_dsa_ga (/Users/tdd/.ssh/id_dsa_ga)

Après ça, la passphrase est automatiquement exploitée pendant toute la durée de vie de l’agent.

Ce type de manip’ est notamment utile quand on se connecte sur un serveur de production où on va faire une série de git pull, git submodule update, etc. et où on veut éviter de taper sa passphrase une tonne de fois. On commence par configurer l’agent, ajouter sa clé, et hop ! On est prêt à rouler.

Enfin, pour ce qui est de Windows, avec msysGit spécifiquement, vous trouverez quelques instructions pour lancer automatiquement ssh-agent sur cette documentation chez GitHub.

Publier sa clé publique ?

Les clés asymétriques ne sont pas seulement utiles pour SSH et les systèmes se greffant par-dessus. Elles sont aussi, par exemple, le moyen privilégié pour (dé)crypter ou signer numériquement (ou les deux) les e-mails. Je rêve du jour où tout le monde saura utiliser correctement le medium e-mail : pas de pièces jointes énormes ou débiles, pas de liste d’e-mails destinataires visible par tout le monde, pas de HTML pourri rempli de Comic Sans MS… et l’habitude de signer les e-mails importants. Ce dernier point, notamment, ouvrira le chemin des e-mails comme moyen valide de communication à valeur légale, par exemple avec votre banquier, votre notaire, votre avocat, etc.

Si le sujet vous intéresse, jetez par exemple un œil au client de messagerie Thunderbird et à son extension Enigmail, basée sur l’outil libre GnuPG (naturellement, il existe d’autres possibilités techniques autour d’Apple Mail, de GMail et j’en passe).

Dans un tel contexte, il est important de pouvoir facilement récupérer la clé publique de quelqu’un, soit parce qu’on veut lui envoyer un contenu confidentiel (on va donc le chiffrer avec la clé publique du destinataire, dont seule la clé privée pourra déchiffrer), soit parce qu’on a reçu un e-mail signé numériquement de cette personne (grâce à sa clé privée), et qu’on veut vérifier que ça vient bien d’elle, et que le contenu n’a pas été altéré (ce qu’on peut faire uniquement à l’aide de sa clé publique).

Bien entendu, la personne en question peut nous avoir, au préalable, transmis sa clé publique. Encore faut-il pouvoir faire confiance au mécanisme qui a fait cette transmission (il existe des moyens, dont l’empreinte de la clé, mais ce n’est pas le sujet de cet article). Un autre moyen plus général est, pour la personne, de publier sa clé publique aux yeux de tous. Pour cela, il existe des serveurs de clés. La plupart sont gratuits, et les plus connus sont répertoriés par les principaux systèmes exploitant des clés. En voici quelques-uns :

Et Git dans tout ça ?

La plupart des hébergements de dépôt Git reposent sur des clés SSH publiques pour identifier les personnes ayant un accès aux dépôts. Lorsque vous accédez à un dépôt authentifié, que ce soit en protocole git://… ou git@…, le système SSH sous-jacent va passer en revue vos clés privées au regard des clés publiques qu’il connaît, et s’il trouve une correspondance, vous demander la passphrase (à moins qu’un agent ne la lui fournisse tout seul) puis engager la suite des opérations.

Dans le cadre des ateliers Git Attitude, lorsque nous étudions l’interaction avec des dépôts distants, j’ai besoin de disposer de clés publiques dont vous avez l’homologue privée, afin de configurer vos accès au serveur Gitosis que nous utilisons. Vous recevez dans vos convocations une demande pour me fournir cette clé à l’avance, avec un lien vers cet article si vous vous sentez déboussolés :-)

J’espère que cet article vous a été utile, et vous a permis de mieux comprendre les clés SSH et leurs meilleures pratiques d’utilisation. Si vous avez des questions, commentaires ou corrections, les commentaires sont là pour ça !

, , ,

4 commentaires

Git, Basecamp, et un peu de magie

Je viens de sortir un petit outil open-source qui facilite énormément le suivi de temps sur Basecamp relatif à vos travaux sur Git.

Quoi ?! Vous n’utilisez pas Basecamp ! Mais c’est pas bien, ça ! Allez donc voir comme c’est top.

L’idée est d’analyser vos messages de commit à la recherche d’un petit tag spécifique sur la fin, qui va permettre à un script post-commit de déterminer le temps de travail, l’éventuelle tâche spécifique associée, et de loguer le temps qui va bien. C’est super pratique et je m’en sers déjà sur plusieurs projets, toute la journée.

Ça se passe ici, et y’a une doc détaillée. Enjoy !

Pas de commentaire

Installer un Git récent

Vous aimez déjà Git, ou vous souhaitez le découvrir ? Vous allez participer à un Atelier Git Attitude ? Il vous faut alors installer une version récente sur votre poste de travail, et sans doute aussi sur vos machines de déploiement, de staging, etc. Cet article essaie de vous donner toutes les clés pour faire cela aussi rapidement et facilement que possible.

Récent… c’est-à-dire ?

À l’heure où j’écris ceci, la dernière version stable de Git est la 1.7.2.1. La plupart des systèmes pré-packagés sont encore sur la précédente, la 1.7.1.1 (qui est très récente aussi), mais ça va vite se mettre à jour…

Concrètement, les différences avec des versions plus anciennes (jusqu’à 1.5.0, qui a introduit les derniers changements en date de structure du dépôt) sont quelque peu mineures et focalisées sur des détails d’options et de raffinement dans les décorations des logs, l’exécution d’outils externes (on pense notamment aux outils de diff), quelques fonctionnalités de confort, etc.

En termes de compatibilité sur le dépôt et d’opérations courantes, tout Git au moins 1.5.0 saura manipuler un dépôt plus récent, par exemple (ce qui peut avoir son importance si, par exemple, vous déployez sur un hébergement mutualisé dont les versions seraient un peu rances).

Je vous recommande d’avoir au moins une 1.6.6, mais compiler le code source sur votre plate-forme reste la meilleure façon d’avoir une version à jour, optimisée pour votre situation et dotée de tout le dernier confort proposé, notamment pour les usages avancés.

Un mot sur la doc

Git est un outil extrêmement puissant et riche, avec ses quelque 75 commandes de haut niveau (dites « porcelain ») et près de 60 commandes de bas niveau, à usage surtout interne (dites « plumbing »). Même les commandes principales, utiles pratiquement au quotidien, qui sont à peu près 20, recèlent une puissance insoupçonnée ; à ce titre, leur documentation est un atout précieux.

En effet, je trouve que les auteurs et mainteneurs de Git ont fait un boulot exceptionnel sur la documentation des commandes, à laquelle on peut accéder soit en tapant git help COMMANDE soit, lorsqu’on a la commande man, avec un man git-COMMANDE (les deux sont équivalents mais je préfère personnellement la première syntaxe).

Cependant, les méthodes d’installation par source ou par paquets ne l’installeront pas toujours par défaut : il vous appartient d’installer les bons paquets auxiliaires (typiquement git-doc) ou d’appeler les bonnes commandes de compilation et d’installation. Nous y reviendrons.

Installer Git sur OSX

Sur OSX, je ne saurais trop vous recommander de passer par l’installeur binaire hébergé sur Google Code, le projet git-osx-installer. Il est calé (là tout de suite) sur la 1.7.2 et installe les docs au passage, donc aucune raison de se priver ! Tout est installé dans /usr/local/git par défaut.

C’est de loin l’option la plus simple : compiler à partir des sources sur OSX exige une kyrielle de pré-requis qui peuvent être pénibles à obtenir, qu’on passe par Macports, Fink, Homebrew ou d’autres voies…

Installer Git sur Linux

Approche 1 : utiliser des paquets

Il existe généralement plusieurs paquets se répartissant les fonctionnalités et documentations de Git, paquets aux noms raisonnablement explicites, typiquement git comme « paquet chapeau » (paquet virtuel entraînant l’installation des autres), git-core (la quasi-totalité des commandes), git-doc, git-gui, gitk et gitweb (interfaces graphiques et frontal web de navigation de dépôt), git-svn et git-cvs (passerelles avec d’autres SCM)…

Sur Ubuntu et ses dérivés, les paquets sont assez récents (1.7.0 sur Lucid Lynx à l’heure où j’écris ceci) ; il est toutefois possible d’avoir des versions très à jour en passant par un PPA (Personal Package Archive, dépôt Ubuntu officieux maintenu par une entité quelconque, un particulier par exemple), le plus connu dans le cas qui nous occupe étant celui d’Andrey Voronov, qui propose des paquets tout frais (donc 1.7.2) pour Ubuntu 8.04 (Hardy Heron) et 10.04 (Lucid Lynx). Si vous avez une 9.x, vous pouvez tester ces dépôts quand même, utiliser le paquet fourni (Git 1.6.0 en 9.04, Git 1.6.3 en 9.10) ou compiler la source.

Debian dispose de paquets raisonnablement récents, avec la 1.7.1 (si vous êtes en stable/lenny, vous aurez cependant besoin des dépôts « backports »).

Pour les distributions basées RPM, telles que Red Hat, SuSE et Mandriva, le site officiel de Git maintient des paquets RPM très à jour. Gentoo a un paquet dev-vcs/git en unstable, et comme c’est Gentoo, on est basés sur sources donc assez récent (1.7.2 semble-t-il). ArchLinux est, comme souvent, très à jour avec un paquet git en 1.7.2.1 qui n’a que peu de dépendances.

Enfin, sachez qu’on peut avoir un Git récent sur Solaris en passant par Sun Freeware.

Approche 2 : compiler le code source

Commencez par récupérer l’archive du code source complet (préfixe git-) au format de votre choix. Par exemple pour la 1.7.2.1, l’une des deux suivantes :

D’une distribution à l’autre, les dépendances ne seront pas toujours les mêmes. Bon, vous allez faire une compil’, il vous faut donc naturellement build-essential, le paquet universel des distributions Linux pour pouvoir compiler des trucs. Je sais aussi qu’il vous faut généralement au moins Curl, Perl et Expat, mais si vous voulez les docs (et vous les voulez, faites-moi confiance…) vous aurez sans doute aussi besoin des paquets pour TCL/TK, xmlto et AsciiDoc. Sur une Debian/Ubuntu, ça donne une installation de paquets qui va durer un petit moment :

$ apt-get install -q -y build-essential libcurl4-openssl-dev curl perl expat tk asciidoc docbook2x xmlto

Allez donc prendre un café… Quand ce sera fini, c’est en revanche enfantin. Décompressez votre archive quelque part (par exemple dans /tmp/sources), allez dans le répertoire ainsi créé, puis :

$ ./configure
…
$ make all man
…
$ sudo make install install-man
…

La clé ici est de bien penser à préciser les cibles man à la compilation (par défaut on n’a que all) et install-man ensuite. Si vous aimez utiliser l’outil de consultations de docs info, vous pouvez ajouter les cibles info et install-info, respectivement.

Une petite vérif’ ?

$ git --version
git version 1.7.2.1

Bravo !

Installer Git sur Windows

Bon, déjà, soyons clair : ça sera largement moins bien que sur Linux ou OSX. Vous n’aurez pas les docs (pas de façon intégrée en tout cas), l’accès en ligne de commande (donc à toutes les commandes) n’est pas 100% automatique, et j’en passe. Mais bon.

Règle numéro 1 : tu ne te baseras par sur Cygwin. Car tu n’as pas une heure à perdre par commande, et la sous-couche Cygwin est horriblement lente en générale, et pour Git en particulier. Ouste !

Cela nous laisse les optionss suivantes :

  • msysgit (également appelé « Git for Windows »). Cet outil propose un installeur exécutable hébergé sur Google Code, qui est assez bien maintenu (il est actuellement en 1.7.1). Il propose une interface graphique pour les opérations usuelles.
  • SmartGit. C’est un enrobage Java, donc multi-plateformes en fait, autour de Git. On le trouve chez Syntevo, qui nous a déjà filé SmartSVN. Ça fournit une interface graphique pour les non-experts, notamment les non-développeurs, mais on n’y trouve, fatalement, aucune commande avancée. Pratique par exemple si vous voulez que vos graphistes / designers versionnent leurs fichiers au même titre que les développeurs. La version actuelle est la 1.5.4, je ne sais pas à quel Git ça correspond mais elle est sortie à peu près au moment de Git 1.7.1.1…

Complétion et prompt

Git fournit, dans son archive de code source (sa tarball), un script de complétion Bash tout simplement génial.

Il permet de compléter les commandes en profondeur (commandes, sous-commandes, arguments appropriés, y compris pour les aliases configurés dans Git), et fournit de surcroît la fonction de personnalisation avancée du prompt que j’avais déjà présentée dans Le prompt Bash qui change la vie avec Git (inutile donc de le garder dans votre fichier d’initialisation, ça ferait doublon pour rien).

D’ailleurs sa version ne cesse de s’améliorer (on a désormais une variable qui indique dans le prompt si on est en avance ou en retard par rapport à l’upstream, par exemple, et l’initialisation—qui a lieu la première fois d’une session qu’on arrive dans un dépôt—est de plus en plus rapide).

Que du bonheur ! Si vous ne voulez pas vous galérer à récupérer l’archive, la décompresser et piocher le bon fichier, faites donc juste la commande qui suit :

curl https://github.com/git/git/raw/master/contrib/completion/git-completion.bash -o ~/.git-completion

Ensuite, dans votre .bashrc (Linux) ou .profile (OSX), retirez si besoin vos fonctions de prompt existantes, et terminez en chargeant le script de complétion Git et en personnalisant votre prompt (ici avec plein de jolies couleurs) :

source ~/.git-completion
export GIT_PS1_SHOWDIRTYSTATE=1 GIT_PS1_SHOWSTASHSTATE=1 GIT_PS1_SHOWUNTRACKEDFILES=1
export PS1='\[\033[35m\u@\h:\033[36m\W\[\033[0m\033[33m$(__git_ps1 " (%s)")\033[0m\$ '

Démonstration :

tdd@CodeMagic:~$ cd /tmp
tdd@CodeMagic:tmp$ git clone git://github.com/tdd/sprockets-rails.git
tdd@CodeMagic:tmp$ cd sprockets-rails
tdd@CodeMagic:sprockets-rails (master)$ echo 'toto' > toto
tdd@CodeMagic:sprockets-rails (master %)$ git add toto
tdd@CodeMagic:sprockets-rails (master +)$ echo 'tutu' >> toto
tdd@CodeMagic:sprockets-rails (master *+)$ git stash
tdd@CodeMagic:sprockets-rails (master $)$ git stash pop
tdd@CodeMagic:sprockets-rails (master *)$ git reset --hard HEAD
tdd@CodeMagic:sprockets-rails (master)$ git <TAB><TAB>
add                 commit              instaweb            revert
am                  config              lg                  rm
annotate            describe            log                 send-email
apply               diff                merge               shortlog
archive             difftool            mergetool           show
bisect              fetch               mv                  show-branch
blame               filter-branch       name-rev            st
branch              format-patch        notes               stage
bundle              fp                  pull                stash
checkout            fsck                push                status
cherry              gc                  rebase              submodule
cherry-pick         get-tar-commit-id   relink              svn
ci                  grep                remote              tag
citool              gui                 repack              whatchanged
clean               help                replace
clone               imap-send           request-pull
co                  init                reset
tdd@CodeMagic:sprockets-rails (master)$ git merge <TAB><TAB>
HEAD            master          origin/HEAD     origin/master
tdd@CodeMagic:sprockets-rails (master)$ git merge origin/master --<TAB><TAB>
--commit      --ff-only     --no-commit   --no-log      --no-stat     --stat
--ff          --log         --no-ff       --no-squash   --squash      --strategy
…

Whoooohooooo !

Conclusion

Comme vous pouvez le voir, installer un Git récent n’a rien de sorcier, et disposer d’un Git complet, avec documentation intégrée, et doté d’une complétion et d’un prompt idoines, change tout simplement la vie… Alors bonne gestion de versions !

, , ,

3 commentaires

Héberger un serveur Git avec Gitosis (Linux / OSX)

Il y a plusieurs raisons pour vouloir disposer d’un hébergement Git. Les trois principales sont :

  • disposer d’un backup distant de son travail,
  • mettre son travail à la disposition d’autrui,
  • collaborer avec d’autres sur un projet.

Hébergement public ou privé ?

Lorsque le projet est libre, ou qu’en tout cas son contenu est public, le plus simple consiste à exploiter un bon service d’hébergement Git qui serait gratuit pour les dépôts publics. Dans ce domaine, l’acteur désormais incontournable (et particulièrement bien foutu) est le célèbre GitHub.

En revanche, pour les dépôts privés, soit on reste sur GitHub, mais dès lors, c’est payant (pas cher ceci dit : à partir de $9/mois, ce qui permet de bénéficier de l’infrastructure massive du service, notamment en termes de fiabilité de stockage). Soit on crée son propre hébergement Git, ce qui a notamment l’intérêt éventuel de le rendre interne à sa société (et donc, potentiellement, très rapide d’accès sur un réseau local performant).

Ce billet vise à explorer en détail l’option technique favorite pour héberger son propre serveur Git : Gitosis.

Quand on connaît la procédure, récupérer, installer et configurer Git, qu’on soit sur OSX ou Linux, est l’affaire de 10 à 15 minutes. En lisant ce billet et les explications, ce sera naturellement un peu plus long. Mais ça reste rapide et facile !

Lire la suite »

, , , , ,

53 commentaires

Le prompt Bash qui change la vie avec Git

Lors de l’atelier de samedi je vous ai promis un prompt Bash qui déboîte quand on fait du Git.

Celui-ci repose sur une série de fonctions Bash dont la plus « high-level » est appelée à chaque prompt. Elle permet de voir immédiatement :

  • Dans quelle branche on est
  • Si on a des modifs en working tree
  • Si on a des modifs en stage
  • Si on a des fichiers untracked
  • Si on a du stash

Toutes choses fort utiles au moment de faire son commit, histoire de ne rien oublier…

Voici le code source avec quelques commentaires. Vous pouvez aussi aller piocher le Gist directement.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# Scavenged from Git 1.6.5.x contrib/completion/git_completion.bash
# __git_ps1 accepts 0 or 1 arguments (i.e., format string)
# returns text to add to bash PS1 prompt (includes branch name)
__gitdir ()
{
  if [ -z "${1-}" ]; then
    if [ -n "${__git_dir-}" ]; then
      echo "$__git_dir"
    elif [ -d .git ]; then
      echo .git
    else
      git rev-parse --git-dir 2>/dev/null
    fi
  elif [ -d "$1/.git" ]; then
    echo "$1/.git"
  else
    echo "$1"
  fi
}
__git_ps1 ()
{
  local g="$(__gitdir)"
  if [ -n "$g" ]; then
    local r
    local b
    if [ -f "$g/rebase-merge/interactive" ]; then
      r="|REBASE-i"
      b="$(cat "$g/rebase-merge/head-name")"
    elif [ -d "$g/rebase-merge" ]; then
      r="|REBASE-m"
      b="$(cat "$g/rebase-merge/head-name")"
    else
      if [ -d "$g/rebase-apply" ]; then
        if [ -f "$g/rebase-apply/rebasing" ]; then
          r="|REBASE"
        elif [ -f "$g/rebase-apply/applying" ]; then
          r="|AM"
        else
          r="|AM/REBASE"
        fi
      elif [ -f "$g/MERGE_HEAD" ]; then
        r="|MERGING"
      elif [ -f "$g/BISECT_LOG" ]; then
        r="|BISECTING"
      fi

      b="$(git symbolic-ref HEAD 2>/dev/null)" || {

        b="$(
        case "
${GIT_PS1_DESCRIBE_STYLE-}" in
        (contains)
          git describe --contains HEAD ;;
        (branch)
          git describe --contains --all HEAD ;;
        (describe)
          git describe HEAD ;;
        (* | default)
          git describe --exact-match HEAD ;;
        esac 2>/dev/null)"
||

        b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
        b="unknown"
        b="($b)"
      }
    fi

    local w
    local i
    local s
    local u
    local c

    if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
      if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
        c="BARE:"
      else
        b="GIT_DIR!"
      fi
    elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
      if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then
        if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then
          git diff --no-ext-diff --ignore-submodules \
            --quiet --exit-code || w="*"
          if git rev-parse --quiet --verify HEAD >/dev/null; then
            git diff-index --cached --quiet \
              --ignore-submodules HEAD -- || i="+"
          else
            i="#"
          fi
        fi
      fi
      if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then
              git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$"
      fi

      if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then
         if [ -n "$(git ls-files --others --exclude-standard)" ]; then
            u="%"
         fi
      fi
    fi

    if [ -n "${1-}" ]; then
      printf "$1" "$c${b##refs/heads/}$w$i$s$u$r"
    else
      printf " (%s)" "$c${b##refs/heads/}$w$i$s$u$r"
    fi
  fi
}

export GIT_PS1_SHOWDIRTYSTATE=1 GIT_PS1_SHOWUNTRACKEDFILES=1 GIT_PS1_SHOWSTASHSTATE=1

# Basique…
# export PS1='\u@\h:\W$(__git_ps1) \$ '
# Avec plein de couleurs…
export PS1='\[\033[0;37m\]\u@\h:\[\033[0;33m\]\W\[\033[0m\]\[\033[1;32m\]$(__git_ps1)\[\033[0m\] \$ '

Notez les variables qui configurent ce qui est affiché :

  • GIT_PS1_SHOWDIRTYSTATE fait remonter les modifs en working tree (symbole *) et en stage (symbole +)
  • GIT_PS1_SHOWUNTRACKED_FILES fait remonter les fichiers non présents dans l’index (non pris en compte jusqu’à ajout explicite) (symbole %)
  • GIT_PS1_SHOWSTASHSTATE indique qu’on a des trucs dans le stash (symbole $)

Ça ralentit un tout petit peu le premier prompt de votre session dans un dépôt non trivial, le temps pour les commandes Git internes de construire les caches d’accès à l’index et à l’historique… Ensuite c’est instantané.

Je ne pourrais pas vivre sans !

Enjoy!

5 commentaires