<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Git Attitude &#187; Astuces et Outils</title>
	<atom:link href="http://www.git-attitude.fr/category/astuces-et-outils/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.git-attitude.fr</link>
	<description>Parce que Git, c&#039;est bien.</description>
	<lastBuildDate>Wed, 15 Feb 2012 18:57:23 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Git + Subversion : arrêtez d&#8217;ignorer ce que vous devriez ignorer (?!)</title>
		<link>http://www.git-attitude.fr/2010/09/16/git-subversion-arretez-dignorer-ce-que-vous-devriez-ignorer/</link>
		<comments>http://www.git-attitude.fr/2010/09/16/git-subversion-arretez-dignorer-ce-que-vous-devriez-ignorer/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 11:19:42 +0000</pubDate>
		<dc:creator>Christophe</dc:creator>
				<category><![CDATA[Astuces et Outils]]></category>
		<category><![CDATA[.gitignore]]></category>
		<category><![CDATA[git-helpers]]></category>
		<category><![CDATA[outils]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[subversion]]></category>
		<category><![CDATA[svn]]></category>
		<category><![CDATA[svn:ignore]]></category>

		<guid isPermaLink="false">http://www.git-attitude.fr/?p=33</guid>
		<description><![CDATA[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&#8217;abandonner le premier au profit du second (yay !). On est obligé de bosser sur un dépôt Subversion, mais [...]]]></description>
			<content:encoded><![CDATA[<p>Parfois on se retrouve à faire du Git, en local, sur un dépôt distant Subversion. Ça arrive en fait dans deux situations :</p>
<ul>
<li>On est en train de <strong>passer un dépôt de Subversion vers Git</strong>, en vue d&#8217;abandonner le premier au profit du second (yay !).</li>
<li>On est obligé de <strong>bosser sur un dépôt Subversion</strong>, mais on refuse de laisser tomber le confort quotidien de Git en local.</li>
</ul>
<p>Git propose une passerelle au moyen de la commande <tt>git svn</tt> et de ses sous-commandes. Moyennant quelques précautions d&#8217;usage, on peut ainsi travailler avec Git en local et synchroniser vers (et depuis) le dépôt Subversion distant. C&#8217;est un sujet assez vaste et j&#8217;y reviendrai plus en détail dans un prochain billet.</p>
<p>Toutefois, ceux qui rencontrent déjà ces situations ont sans doute remarqué un phénomène irritant : <strong>Git ne prend pas en compte la propriété <tt>svn:ignore</tt></strong>. En fait, il ne prend en compte que <tt>svn:executable</tt> (ce qui est déjà pas mal, vu comme elle est grave utile…).</p>
<p>La propriété <tt>svn:ignore</tt> est similaire au fichier <tt>.gitignore</tt> : elle permet de lister des motifs de fichiers qui ne doivent pas être versionnés. Il est donc dommage qu&#8217;on n&#8217;en bénéficie pas automatiquement sur Git, risquant ainsi de versionner par erreur des fichiers qui devraient être ignorés.</p>
<p>Voilà pourquoi j&#8217;ai développé un petit outil qui va <strong>automatiquement synchroniser vos <tt>svn:ignore</tt> vers vos <tt>.gitignore</tt></strong>, à tout moment, pour votre <tt>master</tt> (c&#8217;est-à-dire votre <tt>trunk</tt> distant), sans écraser d&#8217;éventuelles infos déjà présentes dans vos <tt>.gitignore</tt>… C&#8217;est le premier d&#8217;une série probable de petits scripts du même genre, destinés à faciliter l&#8217;utilisation de Git au quotidien.</p>
<p>Comme mon récent outil <a href="http://github.com/tdd/git-basecamp">git-basecamp</a>, il est disponible en open-source, et documenté, sur GitHub. Je vous invite donc à jeter un œil à mon dépôt <a href="http://github.com/tdd/git-helpers">git-helpers</a>. Notez qu&#8217;il existe aussi une quantité de dépôts nommés « git-tools » sur Github, mais aucun de ceux que j&#8217;ai regardés n&#8217;avait cette fonctionnalité (et la plupart des aides qu&#8217;ils fournissent m&#8217;ont semblé un peu basiques…).</p>
<p>Enjoy !</p>
]]></content:encoded>
			<wfw:commentRss>http://www.git-attitude.fr/2010/09/16/git-subversion-arretez-dignorer-ce-que-vous-devriez-ignorer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Comprendre et maîtriser les clés SSH</title>
		<link>http://www.git-attitude.fr/2010/09/13/comprendre-et-maitriser-les-cles-ssh/</link>
		<comments>http://www.git-attitude.fr/2010/09/13/comprendre-et-maitriser-les-cles-ssh/#comments</comments>
		<pubDate>Mon, 13 Sep 2010 14:42:56 +0000</pubDate>
		<dc:creator>Christophe</dc:creator>
				<category><![CDATA[Astuces et Outils]]></category>
		<category><![CDATA[Didacticiels]]></category>
		<category><![CDATA[authentification]]></category>
		<category><![CDATA[cles]]></category>
		<category><![CDATA[passphrase]]></category>
		<category><![CDATA[ssh]]></category>

		<guid isPermaLink="false">http://www.git-attitude.fr/?p=32</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p>Git base toute sa gestion d’authentification sur le mécanisme des <strong>clés SSH</strong>.  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.</p>
<p>Ce billet tente de vous donner toutes les clés (ahem) pour comprendre et manipuler aisément vos identités SSH.</p>
<p>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 <em>protection</em> de vos clés (tant en termes de <em>passphrase</em> que de gestion des droits d’accès à vos fichiers de clés).</p>
<p>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.</p>
<h2>Principe des clés asymétriques</h2>
<p>Quand vous travaillez avec des clés asymétriques, par principe, vous avez deux clés (on parle de <strong>paire</strong> de clés) : une <strong>clé publique</strong>, que vous pouvez diffuser librement, voire mettre à disposition sur un serveur de clés ; et une <strong>clé privée</strong>, 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.</p>
<p>Comme toujours en cryptographie, on peut faire deux choses avec une clé : <em>chiffrer</em> un contenu (l’encrypter) ou le <em>signer</em> (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.</p>
<p>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 !</p>
<p>Si le sujet vous intéresse, vous trouverez une <a href="http://fr.wikipedia.org/wiki/Cryptographie_asymétrique">tonne d’infos sur Wikipedia</a>.  Mais si j’étais vous, je finirais cet article d’abord histoire de ne pas partir sur une tangente…</p>
<h2>RSA vs. DSA</h2>
<p>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&#8217;RSA était encore breveté.</p>
<p>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).</p>
<h2>Taille de clé</h2>
<p>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 <tt>https://</tt>, 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.</p>
<p>À 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.</p>
<p>Donc on est tranquilles.</p>
<p>Notez qu’en revanche une clé DSA fait obligatoirement 1024 bits (1Ko).  C’est comme ça.</p>
<h2>Passphrase</h2>
<p>Vous avez certainement l’habitude voir le terme <em>password</em>, 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.).</p>
<p>Du coup, tout le monde se retrouve forcé d’utiliser des mots de passe genre <tt>&amp;dF@8^Xy+</tt>, 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, <em>vous</em> l’avez déjà fait) (gredin(e) que vous êtes).</p>
<p>Par contraste, une <em>passphrase</em> (pas d’équivalent français satisfaisant à ma connaissance, aussi essayez de le prononcer correctement, genre <em>passfrayz</em>) 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.</p>
<p>« Mais on m’a toujours dit que des vrais mots Saymal™ ! », me hurlez-vous avec consternation, le sourcil vengeur.</p>
<p>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.</p>
<p>Je suis assez fan de <a href="http://www.baekdal.com/tips/password-security-usability">cet excellent article</a> 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 » (<em>secure for life</em>).  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 :</p>
<ul>
<li>this is fun (sérieux ! Il faudrait au moins 25 siècles…)</li>
<li>j’aime les noix de cajou (le système solaire aura déjà imposé d&#8217;ici qu&#8217;on casse ça…)</li>
<li>des filles à la vanille</li>
<li>san pellegrino enterre badoit</li>
<li>i love to boogie</li>
<li>tu fais du vb dommage eliane</li>
<li>entre git et svn j’ai choisi</li>
<li>plutot crever qu’installer vista</li>
<li>…</li>
</ul>
<p>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 <em>carrément plus facile à mémoriser !</em></p>
<p>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 <em>agents SSH</em>, 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 <em>mot de passe maître</em>, à 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.</p>
<p>Parce que ne vous avisez <strong>surtout pas</strong> de « résoudre » le pseudo-problème de la longueur du texte en utilisant une passphrase <em>vide</em>.  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.</p>
<h2>Vérifier ce qu’on a comme clé</h2>
<p>Bon, il est l’heure de vérifier si vous avez déjà une paire de clés du bon type (DSA)…</p>
<p>Sur tous les systèmes Linux et Unix, vos clés SSH sont normalement stockées dans un dossier <tt>.ssh</tt> à la racine de votre profil.  Ouvrez donc un terminal et tapez la commande suivante :</p>
<pre class="brush: plain; title: ; notranslate">
ls -lAF ~/.ssh
</pre>
<p>Si vous avez un message d’erreur (genre « je ne connais pas ce dossier ») ou un listing ne contenant que des fichiers style <tt>authorized_keys</tt>, <tt>config</tt> ou <tt>known_hosts</tt>, vous n’avez pas encore de clé exploitable.  Ce que vous cherchez, ce sont des fichiers qui, classiquement, s’appellent <tt>id_dsa</tt> (la clé privée) et <tt>id_dsa.pub</tt> (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 :</p>
<pre class="brush: plain; title: ; notranslate">
$ 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
</pre>
<p>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 (<tt>id_dsa_git</tt>), 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.</p>
<p>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 !</p>
<h2>Créer une clé</h2>
<p>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 <em>de facto</em>.  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 <tt>ssh-keygen</tt>.</p>
<p>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 <tt>id_dsa_ga</tt> (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.</p>
<pre class="brush: plain; title: ; notranslate">
$ 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     |
+-----------------+
</pre>
<p>Suivant votre version de <tt>ssh-keygen</tt>, vous n’aurez pas forcément le <em>randomart</em> à 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.</p>
<p>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 :)</p>
<pre class="brush: plain; title: ; notranslate">
$ 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
</pre>
<p>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 <tt>~/.ssh/authorized_keys</tt>, qui liste les clés publiques dont les titulaires peuvent accéder à votre compte <em>via</em> 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é.</p>
<p>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 :</p>
<pre class="brush: plain; title: ; notranslate">
$ ssh-keygen -p -f ~/.ssh/le_fichier_de_cle
</pre>
<p>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), <em>ne changez pas la passphrase</em> (ça ne servira à rien) : <strong>changez de clé !</strong></p>
<h2>Agents SSH</h2>
<p>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).</p>
<p><strong>OS X</strong> intègre cette fonction dans son outil plus général de Trousseau d’Accès (<em>Keyring</em>) depuis Leopard (10.5).  Avant cela (par exemple Tiger, la 10.4), il fallait <a href="http://matt.simerson.net/2007/07/28/ssh-agent-and-mac-os-x">ruser comme décrit dans cet article</a>.  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.</p>
<p><strong>Ubuntu</strong> 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.</p>
<p>Pour <strong>les autres distributions</strong> 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 :</p>
<pre class="brush: plain; title: ; notranslate">
$ set | grep SSH_AUTH_SOCK
</pre>
<p>Si vous ne voyez rien s’afficher, vous n’avez pas d’agent actif ; si vous voyez quelque chose (probablement du genre <tt>/var/run/….sock</tt>), alors vous en avez un.</p>
<p>Si vous n’avez pas d’agent actif, vous pouvez en lancer un manuellement à l’aide de la bien-nommée commande <tt>ssh-agent</tt>.  Celle-ci crée un processus résident (un <em>daemon</em>) 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 <tt>SSH_AUTH_SOCK</tt> et <tt>SSH_AGENT_PID</tt>.  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 :</p>
<pre class="brush: plain; title: ; notranslate">
$ eval `ssh-agent`
Agent pid 23038
</pre>
<p>Évidemment, vous verrez un autre numéro de processus (<em>pid</em>), mais le principe est le même.</p>
<p>À 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 <tt>ssh-add</tt>.  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 :</p>
<pre class="brush: plain; title: ; notranslate">
$ 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)
</pre>
<p>Après ça, la passphrase est automatiquement exploitée pendant toute la durée de vie de l’agent.</p>
<p>Ce type de manip’ est notamment utile quand on se connecte sur un serveur de production où on va faire une série de <tt>git pull</tt>, <tt>git submodule update</tt>, 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.</p>
<p>Enfin, pour ce qui est de <strong>Windows</strong>, avec msysGit spécifiquement, vous trouverez quelques instructions pour lancer automatiquement <tt>ssh-agent</tt> sur <a href="http://help.github.com/working-with-key-passphrases/">cette documentation chez GitHub</a>.</p>
<h2>Publier sa clé publique ?</h2>
<p>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.</p>
<p>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).</p>
<p>Dans un tel contexte, il est important de pouvoir facilement récupérer la <em>clé publique</em> 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).</p>
<p>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 <strong>serveurs de clés</strong>.  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 :</p>
<ul>
<li><a href="https://keyserver.pgp.com">keyserver.pgp.com</a></li>
<li><a href="http://pgpkeys.mit.edu">pgpkeys.mit.edu</a></li>
<li><a href="https://pgp.webtru.st/">pgp.webtru.st/</a></li>
</ul>
<h2>Et Git dans tout ça ?</h2>
<p>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 <tt>git://…</tt> ou <tt>git@…</tt>, 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.</p>
<p>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 <img src='http://www.git-attitude.fr/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>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 !</p>
]]></content:encoded>
			<wfw:commentRss>http://www.git-attitude.fr/2010/09/13/comprendre-et-maitriser-les-cles-ssh/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Git, Basecamp, et un peu de magie</title>
		<link>http://www.git-attitude.fr/2010/09/08/git-basecamp-et-un-peu-de-magie/</link>
		<comments>http://www.git-attitude.fr/2010/09/08/git-basecamp-et-un-peu-de-magie/#comments</comments>
		<pubDate>Wed, 08 Sep 2010 07:23:06 +0000</pubDate>
		<dc:creator>Christophe</dc:creator>
				<category><![CDATA[Astuces et Outils]]></category>
		<category><![CDATA[basecamp]]></category>

		<guid isPermaLink="false">http://www.git-attitude.fr/?p=28</guid>
		<description><![CDATA[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&#8217;utilisez pas Basecamp ! Mais c&#8217;est pas bien, ça ! Allez donc voir comme c&#8217;est top. L&#8217;idée est d&#8217;analyser vos messages de commit à la recherche d&#8217;un petit tag [...]]]></description>
			<content:encoded><![CDATA[<p>Je viens de sortir un petit outil open-source qui facilite énormément le suivi de temps sur <a href="http://basecamphq.com/">Basecamp</a> relatif à vos travaux sur Git.</p>
<p>Quoi ?! Vous n&#8217;utilisez pas Basecamp ! Mais c&#8217;est pas bien, ça ! <a href="http://basecamphq.com/tour">Allez donc voir comme c&#8217;est top</a>.</p>
<p>L&#8217;idée est d&#8217;analyser vos messages de commit à la recherche d&#8217;un petit tag spécifique sur la fin, qui va permettre à un script post-commit de déterminer le temps de travail, l&#8217;éventuelle tâche spécifique associée, et de loguer le temps qui va bien. C&#8217;est super pratique et je m&#8217;en sers déjà sur plusieurs projets, toute la journée.</p>
<p><a href="http://github.com/tdd/git-basecamp">Ça se passe ici</a>, et y&#8217;a une doc détaillée. Enjoy !</p>
]]></content:encoded>
			<wfw:commentRss>http://www.git-attitude.fr/2010/09/08/git-basecamp-et-un-peu-de-magie/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Installer un Git récent</title>
		<link>http://www.git-attitude.fr/2010/08/05/installer-un-git-recent/</link>
		<comments>http://www.git-attitude.fr/2010/08/05/installer-un-git-recent/#comments</comments>
		<pubDate>Thu, 05 Aug 2010 21:16:05 +0000</pubDate>
		<dc:creator>Christophe</dc:creator>
				<category><![CDATA[Astuces et Outils]]></category>
		<category><![CDATA[Didacticiels]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[completion]]></category>
		<category><![CDATA[installation]]></category>
		<category><![CDATA[prompt]]></category>

		<guid isPermaLink="false">http://www.git-attitude.fr/?p=23</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p>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 <em>staging</em>, etc.  Cet article essaie de vous donner toutes les clés pour faire cela aussi rapidement et facilement que possible.</p>
<h2>Récent… c’est-à-dire ?</h2>
<p>À l’heure où j’écris ceci, la <a href="http://git-scm.com/download">dernière version stable de Git</a> 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…</p>
<p>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.</p>
<p>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).</p>
<p>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.</p>
<h2>Un mot sur la doc</h2>
<p>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, <strong>leur documentation est un atout précieux</strong>.</p>
<p>En effet, je trouve que les auteurs et mainteneurs de Git ont fait <strong>un boulot exceptionnel sur la documentation des commandes</strong>, à laquelle on peut accéder soit en tapant <tt>git help COMMANDE</tt> soit, lorsqu’on a la commande <tt>man</tt>, avec un <tt>man git-COMMANDE</tt> (les deux sont équivalents mais je préfère personnellement la première syntaxe).</p>
<p>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 <tt>git-doc</tt>) ou d’appeler les bonnes commandes de compilation et d’installation.  Nous y reviendrons.</p>
<h2>Installer Git sur OSX</h2>
<p>Sur OSX, je ne saurais trop vous recommander de passer par <a href="http://code.google.com/p/git-osx-installer/downloads/list?can=3">l’installeur binaire hébergé sur Google Code</a>, le projet <strong>git-osx-installer</strong>. 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 <tt>/usr/local/git</tt> par défaut.</p>
<p>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…</p>
<h2>Installer Git sur Linux</h2>
<h3>Approche 1 : utiliser des paquets</h3>
<p>Il existe généralement plusieurs paquets se répartissant les fonctionnalités et documentations de Git, paquets aux noms raisonnablement explicites, typiquement <tt>git</tt> comme « paquet chapeau » (paquet virtuel entraînant l’installation des autres), <tt>git-core</tt> (la quasi-totalité des commandes), <tt>git-doc</tt>, <tt>git-gui</tt>, <tt>gitk</tt> et <tt>gitweb</tt> (interfaces graphiques et frontal web de navigation de dépôt), <tt>git-svn</tt> et <tt>git-cvs</tt> (passerelles avec d’autres SCM)…</p>
<p>Sur <strong>Ubuntu</strong> et ses dérivés, les paquets sont assez récents (1.7.0 sur <em>Lucid Lynx</em> à l’heure où j’écris ceci) ; il est toutefois possible d’avoir des versions très à jour en passant par un PPA (<em>Personal Package Archive</em>, dépôt Ubuntu officieux maintenu par une entité quelconque, un particulier par exemple), le plus connu dans le cas qui nous occupe étant <a href="https://launchpad.net/~voronov84/+archive/andreyv">celui d’Andrey Voronov</a>, 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.</p>
<p><strong>Debian</strong> dispose de paquets raisonnablement récents, avec la 1.7.1 (si vous êtes en <em>stable/lenny</em>, vous aurez cependant besoin des dépôts « backports »).</p>
<p>Pour les <strong>distributions basées RPM</strong>, telles que Red Hat, SuSE et Mandriva, le site officiel de Git maintient <a href="http://kernel.org/pub/software/scm/git/RPMS/">des paquets RPM très à jour</a>.  Gentoo a un paquet <tt>dev-vcs/git</tt> en <em>unstable</em>, 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 <tt>git</tt> en 1.7.2.1 qui n’a que peu de dépendances.</p>
<p>Enfin, sachez qu’on peut avoir un Git récent sur <strong>Solaris</strong> en passant par <a href="http://sunfreeware.com/programlistsparc10.html#git">Sun Freeware</a>.</p>
<h3>Approche 2 : compiler le code source</h3>
<p>Commencez par récupérer <a href="http://git-scm.com/download">l’archive du code source complet</a> (préfixe <tt>git-</tt>) au format de votre choix.  Par exemple pour la 1.7.2.1, l’une des deux suivantes :</p>
<ul>
<li><a href="http://www.kernel.org/pub/software/scm/git/git-1.7.2.1.tar.bz2">http://www.kernel.org/pub/software/scm/git/git-1.7.2.1.tar.bz2</a></li>
<li><a href="http://www.kernel.org/pub/software/scm/git/git-1.7.2.1.tar.gz">http://www.kernel.org/pub/software/scm/git/git-1.7.2.1.tar.gz</a></li>
</ul>
<p>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 <tt>build-essential</tt>, 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 <em>vous les voulez, faites-moi confiance…</em>) 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 :</p>
<pre class="brush: plain; title: ; notranslate">
$ apt-get install -q -y build-essential libcurl4-openssl-dev curl perl expat tk asciidoc docbook2x xmlto
</pre>
<p>Allez donc prendre un café…  Quand ce sera fini, c’est en revanche enfantin. Décompressez votre archive quelque part (par exemple dans <tt>/tmp/sources</tt>), allez dans le répertoire ainsi créé, puis :</p>
<pre class="brush: plain; title: ; notranslate">
$ ./configure
…
$ make all man
…
$ sudo make install install-man
…
</pre>
<p>La clé ici est de bien penser à préciser les cibles <tt>man</tt> à la compilation (par défaut on n’a que <tt>all</tt>) et <tt>install-man</tt> ensuite.  Si vous aimez utiliser l’outil de consultations de docs <tt>info</tt>, vous pouvez ajouter les cibles <tt>info</tt> et <tt>install-info</tt>, respectivement.</p>
<p>Une petite vérif’ ?</p>
<pre class="brush: plain; title: ; notranslate">
$ git --version
git version 1.7.2.1
</pre>
<p>Bravo !</p>
<h2>Installer Git sur Windows</h2>
<p>Bon, déjà, soyons clair : <strong>ça sera largement moins bien que sur Linux ou OSX</strong>. 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.</p>
<p>Règle numéro 1 : <strong>tu ne te baseras par sur Cygwin</strong>. 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 !</p>
<p>Cela nous laisse les optionss suivantes :</p>
<ul>
<li><strong>msysgit</strong> (également appelé « Git for Windows »). Cet outil propose un <a href="http://code.google.com/p/msysgit/downloads/list">installeur exécutable</a> 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.</li>
<li><strong>SmartGit</strong>. C’est un enrobage Java, donc multi-plateformes en fait, autour de Git.  On le trouve <a href="http://www.syntevo.com/smartgit/download.html?all=true">chez Syntevo</a>, 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…</li>
</ul>
<h2>Complétion et prompt</h2>
<p>Git fournit, dans son archive de code source (sa <em>tarball</em>), un script de complétion Bash tout simplement génial.</p>
<p>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 <em>prompt</em> que j’avais déjà présentée dans <a href="http://www.git-attitude.fr/2010/07/14/le-prompt-bash-qui-change-la-vie-avec-git/">Le prompt Bash qui change la vie avec Git</a> (inutile donc de le garder dans votre fichier d’initialisation, ça ferait doublon pour rien).</p>
<p>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’<em>upstream</em>, 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).</p>
<p>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 :</p>
<pre class="brush: plain; title: ; notranslate">
curl https://github.com/git/git/raw/master/contrib/completion/git-completion.bash -o ~/.git-completion
</pre>
<p>Ensuite, dans votre <tt>.bashrc</tt> (Linux) ou <tt>.profile</tt> (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) :</p>
<pre class="brush: plain; title: ; notranslate">
source ~/.git-completion
export GIT_PS1_SHOWDIRTYSTATE=1 GIT_PS1_SHOWSTASHSTATE=1 GIT_PS1_SHOWUNTRACKEDFILES=1
export PS1='\[&#92;&#48;33[35m\u@\h:&#92;&#48;33[36m\W\[&#92;&#48;33[0m&#92;&#48;33[33m$(__git_ps1 &quot; (%s)&quot;)&#92;&#48;33[0m\$ '
</pre>
<p>Démonstration :</p>
<pre class="brush: plain; title: ; notranslate">
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' &gt; toto
tdd@CodeMagic:sprockets-rails (master %)$ git add toto
tdd@CodeMagic:sprockets-rails (master +)$ echo 'tutu' &gt;&gt; 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 &lt;TAB&gt;&lt;TAB&gt;
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 &lt;TAB&gt;&lt;TAB&gt;
HEAD            master          origin/HEAD     origin/master
tdd@CodeMagic:sprockets-rails (master)$ git merge origin/master --&lt;TAB&gt;&lt;TAB&gt;
--commit      --ff-only     --no-commit   --no-log      --no-stat     --stat
--ff          --log         --no-ff       --no-squash   --squash      --strategy
…
</pre>
<p>Whoooohooooo !</p>
<h2>Conclusion</h2>
<p>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 !</p>
]]></content:encoded>
			<wfw:commentRss>http://www.git-attitude.fr/2010/08/05/installer-un-git-recent/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Héberger un serveur Git avec Gitosis (Linux / OSX)</title>
		<link>http://www.git-attitude.fr/2010/07/18/heberger-un-serveur-git-avec-gitosis-linux-osx/</link>
		<comments>http://www.git-attitude.fr/2010/07/18/heberger-un-serveur-git-avec-gitosis-linux-osx/#comments</comments>
		<pubDate>Sun, 18 Jul 2010 11:20:09 +0000</pubDate>
		<dc:creator>Christophe</dc:creator>
				<category><![CDATA[Astuces et Outils]]></category>
		<category><![CDATA[Didacticiels]]></category>
		<category><![CDATA[gitosis]]></category>
		<category><![CDATA[hebergement]]></category>
		<category><![CDATA[install]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[osx]]></category>
		<category><![CDATA[serveur]]></category>

		<guid isPermaLink="false">http://www.git-attitude.fr/?p=17</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p>Il y a plusieurs raisons pour vouloir disposer d’un hébergement Git. Les trois principales sont :</p>
<ul>
<li>disposer d’un <strong>backup</strong> distant de son travail,</li>
<li>mettre son travail à la disposition d’<strong>autrui</strong>,</li>
<li><strong>collaborer</strong> avec d’autres sur un projet.</li>
</ul>
<h3>Hébergement public ou privé ?</h3>
<p>Lorsque le projet est libre, ou qu’en tout cas <strong>son contenu est public</strong>, le plus simple consiste à exploiter un bon <strong>service d’hébergement Git</strong> 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 <a href="http://www.github.com">GitHub</a>.</p>
<p>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 <strong>son propre hébergement Git</strong>, 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).</p>
<p>Ce billet vise à explorer en détail l’option technique favorite pour héberger son propre serveur Git : <strong>Gitosis</strong>.</p>
<p>Quand on connaît la procédure, récupérer, installer et configurer Git, qu’on soit sur <span class="caps">OSX</span> ou Linux, est l’affaire de <em>10 à 15 minutes</em>. En lisant ce billet et les explications, ce sera naturellement un peu plus long. Mais ça reste rapide et facile !</p>
<p><span id="more-17"></span></p>
<h3>Principes de fonctionnement de Gitosis</h3>
<p>Comme GitHub, Gitosis base sa gestion d’accès sur le protocole <strong><span class="caps">SSH</span></strong> et des <strong>clés asymétriques</strong>.</p>
<p>Chaque utilisateur reconnu par le système est identifié au moyen d’une paire de clés asymétriques dont le serveur connaît la partie publique : côté client, il faut donc disposer de la clé privée correspondante dans son « portefeuille de clés » <span class="caps">SSH</span>. Un <strong>même utilisateur logique</strong> dans Gitosis peut être associé à un <strong>nombre quelconque de clés</strong> (par exemple une depuis sa machine au boulot, une depuis son laptop, une par compte sur un serveur où du code est déployé…).</p>
<p>C’est à mon sens une excellente façon de procéder. En effet, révoquer l’accès peut se faire de façon très granulaire si on utilise une clé par couple Utilisateur + Machine : il devient alors possible de révoquer les accès depuis une machine quelconque, ou pour un utilisateur à travers toutes les machines, ou pour un cas Utilisateur + Machine précis.</p>
<p>Un autre aspect de Gitosis que j’aime particulièrement est que <strong>toute sa configuration est dans un… dépôt Git</strong>, ce qui fait qu’on la met à jour avec un <tt>git push</tt>. C’est délicieusement récursif, j’adore !</p>
<h3>Installer le serveur</h3>
<p>Allez, c’est parti, on va se coller un p’tit Gitosis perso.</p>
<h4>Récupérer les dépendances éventuelles</h4>
<p>Déjà, il vous faut Git. Mais si vous lisez ce blog, je suppose que vous l’avez déjà…</p>
<p>Il faut aussi Python et son module <tt>setup-tools</tt>. Sur <span class="caps">OSX</span> on a déjà l’équivalent, mais sur un Linux il faudra installer le paquet correspondant.  Par exemple, sur Debian/Ubuntu&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
$ apt-get install python-setuptools
</pre>
<p>À partir de là, on récupère Gitosis depuis son dépôt et procéder à l’installation&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
cd /tmp
git clone git://eagain.net/gitosis.git
cd gitosis
sudo python setup.py install
</pre>
<p>Cette installation nous fournit une série de binaires (programmes) pour Gitosis, au premier rang desquels <tt>gitosis-serve</tt>, qui va servir de «&nbsp;shell&nbsp;» à l’utilisateur système <tt>git</tt> que nous allons créer.  Ce binaire fournit toutes les fonctions du serveur Git, ainsi que le mécanisme d’authentification, de gestion des droits, etc.</p>
<h4>Créer et configurer l’utilisateur « git »</h4>
<p>Vous avez sans doute déjà remarqué que les URLs «&nbsp;lecture-écriture&nbsp;» d’un dépôt distant Git sont généralement de la forme <tt>git@le-serveur.tld:le-depot.git</tt> (ou plus rarement <tt>ssh://git@le-serveur.tld:le-depot.git</tt>, ce qui revient au même). La convention veut en effet qu’on configure un utilisateur système <tt>git</tt> sur le serveur, seul moyen d’accéder au serveur Git.</p>
<p>Cet utilisateur n’a pas de mot de passe, mais au lieu de fournir un shell classique (ce qui, vu le manque de mot de passe frontal, serait assez dangereux…), il exécute uniquement votre serveur Git, lequel se charge alors de l’authentification.</p>
<p>En revanche, le <em>home directory</em> (répertoire personnel) de ce compte constituera le dossier racine de vos dépôts Git sur le serveur.  Du coup, plutôt que d’utiliser la convention usuelle (<tt>/home/login</tt> sur Linux, <tt>/Users/login</tt> sur <span class="caps">OSX</span>), on aura tendance à préciser un dossier plus conforme à ce type d’usage, typiquement <tt>/var/lib/git</tt>.  Vous pouvez en fait mettre ce que vous voulez, mais je précise le raisonnement ici histoire que vous ne soyez pas surpris dans les lignes de commande qui vont suivre.</p>
<p>Il nous faut donc configurer cet utilisateur. C’est là que la procédure diverge entre les Linux (qui ont tous les binaires système <tt>adduser</tt> et/ou <tt>useradd</tt>) et <span class="caps">OSX</span> (dont la gestion des utilisateurs repose directement sur son mécanisme d’annuaire, c’est-à-dire sa couche <span class="caps">LDAP</span>).</p>
<p>Commençons par la version Linux.  Selon la commande que vous voulez employer, les options ne sont pas exactement les mêmes.  Voici les deux variantes&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
sudo adduser --system --shell /bin/sh --gecos 'git version control' \
  --group --disabled-password --home /var/lib/git git
</pre>
<p>ou</p>
<pre class="brush: bash; title: ; notranslate">
sudo useradd --system --shell /bin/sh --comment 'git version control' \
  --user-group --home-dir /var/lib/git git
</pre>
<p>Passons rapidement en revue la signification de ces arguments&nbsp;:</p>
<ul>
<li><tt>&#8212;system</tt> précise qu’il s’agit d’un utilisateur système&nbsp;: entre autres choses, son <em>home directory</em> ne sera pas initialisé avec les <em>squelettes</em> (fichiers initiaux d’un compte, présents en général dans <tt>/etc/skel</tt>).</li>
<li><tt>&#8212;shell</tt> précise le shell par défaut de l’utilisateur.  Vu que l’accès <span class="caps">SSH</span> sur ce compte ne l’exploitera pas, ce n’est pas une source de danger, en revanche il peut être pratique de disposer d’un shell pour une authentification locale (avec <tt>su</tt> ou <tt>sudo -s</tt>) histoire de triturer le compte sous son identité directe en cas de besoin majeur.</li>
<li><tt>--gecos</tt> ou <tt>--comment</tt> fournissent le descriptif utilisateur qui sera associé dans l’annuaire des comptes locaux.</li>
<li><tt>--group</tt> ou <tt>--user-group</tt> spécifie que le seul groupe qui doit être associé à l’utilisateur est son groupe propre&nbsp;: il ne fera partie d’aucun des groupes utilisateurs par défaut qui pourraient être configurés sur le système, et n’aura donc pas d’accès indû à certains programmes ou emplacements du système de fichiers.</li>
<li><tt>&#8212;disabled-password</tt> indique que le compte n’a pas de mot de passe associé (vu qu’il n’est pas conçu pour faire l’objet d’une authentification). Dans <tt>useradd</tt>, qui n’est pas une commande interactive, le simple fait de ne pas passer de mot de passe dans les arguments a le même effet.</li>
<li><tt>--home</tt> ou <tt>--home-dir</tt> fournit le <em>home directory</em> du compte.</li>
<li>On termine avec le nom du compte&nbsp;: <tt>git</tt></li>
</ul>
<p>La commande crée automatiquement le <em>home directory</em> et lui affecte les bons propriétaire et groupe. Ce ne sera pas le cas sous <span class="caps">OSX</span>, où on se contente de manipuler l’annuaire, ce qui n’impacte jamais le reste du système de fichiers.  Voyons justement comment procéder&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
sudo dscl . create groups/git gid 405
sudo dscl . create users/git uid 405
sudo dscl . create users/git NFSHomeDirectory /var/lib/git
sudo dscl . create users/git gid 405
sudo dscl . create users/git UserShell /bin/bash
sudo dscl . create users/git Password '*'
sudo mkdir /var/lib/git
sudo chown git:git /var/lib/git
</pre>
<p>Le binaire <tt>dscl</tt> (<em>Directory Services Command Line</em>) est l’interface en ligne de commande fournie par <span class="caps">OSX</span> pour manipuler son annuaire interne. Il nous faut d’abord créer le groupe, puis l’utilisateur à proprement parler.  Attention, vous ne pouvez pas regrouper les <tt>dscl . create</tt> dans une seule et même commande, comme on pourrait être tenté de le déduire de la documentation pour cette commande&nbsp;: il est impératif que chaque couple clé+valeur ait sa propre commande.</p>
<p>Notez comme on termine en créant explicitement le <em>home directory</em> et en calant son propriétaire et son groupe.</p>
<p>Sur un <span class="caps">OSX</span> classique, les identifiants groupe et utilisateur 405 sont normalement libres.  Vous pouvez toutefois le vérifier en amont avec les commandes suivantes, et si besoin prendre d’autres IDs qui, eux, seraient libres (ils n’ont pas besoin d’être identiques, mais c’est plus conventionnel)&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
dscl . list groups gid
dscl . list users uid
</pre>
<h4>Un petit détour au pays des clés…</h4>
<p>Il nous faut à présenter définir comment cet utilisateur va se comporter en cas de connexion <span class="caps">SSH</span> utilisant son compte.  Le boulot correspondant, ainsi que l’initialisation finale de Gitosis, sont fait par la même commande.  Celle-ci a toutefois besoin de votre clé publique <span class="caps">SSH</span> afin de vous autoriser, notamment, à manipuler le serveur et le compte Git à votre guise.</p>
<p>Peut-être n’avez-vous pas de clé pour le moment&nbsp;?  Vérifiez avec la commande suivante&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
ls -la ~/.ssh
</pre>
<p>Si vous voyez que le répertoire n’existe pas, ou que vous n’y voyez pas de paire de fichiers <tt>id_dsa</tt>/<tt>id_dsa.pub</tt> (ou <tt>id_rsa</tt>/<tt>id_rsa.pub</tt>), vous n’avez pas encore de clé.  Et d’ailleurs, même si vous en avez déjà une, vous voulez peut-être en créer une seconde, spécifique pour votre exploitation de Git.</p>
<p>Pour générer une paire de clés asymétriques, on utilise la commande <tt>ssh-keygen</tt>.  Je vous conseille d’exploiter l’algorithme <span class="caps">DSA</span> plutôt que le <span class="caps">RSA</span>, utilisé par défaut, qui est un peu moins sécurisé.  Le chemin proposé par défaut pour votre clé sera <tt>~/.ssh/id_dsa</tt>&nbsp;; si vous avez déjà une telle clé mais en voulez une supplémentaire, pensez à changer le nom vers quelque chose de plus spécifique (par exemple <tt>~/.ssh/id_dsa_git</tt>) pour ne pas écraser la clé existante.</p>
<p>Voici ce que ça donne sur mon <span class="caps">OSX</span> Snow Leopard&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
$ 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_git
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/tdd/.ssh/id_dsa_git.
Your public key has been saved in /Users/tdd/.ssh/id_dsa_git.pub.
The key fingerprint is:
9d:ab:3c:56:ef:ad:06:e1:da:13:d5:1f:74:4e:a9:46 tdd@CodeMagic.local
The key's randomart image is:
+--[ DSA 1024]----+
|                .|
|             E oo|
|            ..oo.|
|         ....o...|
|        S.oo.  ..|
|          =.    .|
|         +.+     |
|       .+.o o.   |
|       .o. +o..  |
+-----------------+
</pre>
<p>(Naturellement, vous n’aurez pas la même empreinte (<em>fingerprint</em>) et donc pas le même <em>randomart</em>&nbsp;; c’est normal, le contraire serait d’ailleurs inquiétant.)</p>
<p>Utilisez ce que vous voulez comme <em>passphrase</em> pour la clé, mais évitez un truc bateau, encore plus du vide.  Inutile de rendre votre clé utilisable par tout le monde…</p>
<p>Une fois la génération terminée, vous devriez voir deux nouvelles clés, la privée et la publique (celle dont le nom finit en <tt>.pub</tt>) dans votre dossier <span class="caps">SSH</span>&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
$ ls -l ~/.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 23286 jul 16 12:20 known_hosts
</pre>
<h4>Installer Gitosis à proprement parler</h4>
<p>OK, cette parenthèse refermée, nous pouvons lancer la commande d’initialisation de Gitosis&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
sudo -H -u git gitosis-init &lt; ~/.ssh/id_dsa_git.pub
</pre>
<p>(Si vous voulez utiliser une autre clé publique, ajustez simplement le chemin indiqué)</p>
<p>L’option <tt>-H</tt> s’assure que la commande <tt>gitosis-init</tt> (installée tout à l’heure par notre <tt>python setup.py install</tt>) s’exécutera depuis le <em>home directory</em> de l’utilisateur indiqué par <tt>-u git</tt>, et non depuis le répertoire courant.</p>
<p>La commande <tt>gitosis-init</tt> requiert sur son entrée standard la clé publique de l’utilisateur susceptible de triturer le compte manuellement.</p>
<p>Sur <span class="caps">OSX</span>, il va aussi nous falloir contourner un problème de <span class="caps">PATH</span> (liste des endroits où le système cherche les binaires qu’on lui demande d’exécuter), en ajoutant la commande suivante&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
sudo su git; echo &quot;export PATH=$(git --exec-path):$PATH&quot; &gt; ~/.bashrc; exit
</pre>
<p>De cette façon, on est certain que l’utilisateur <tt>git</tt>, pour exécuter ses binaires, aura bien tous les bons chemins sous la main. Encore une fois, pas besoin de ça sous Linux&nbsp;: juste <span class="caps">OSX</span>.</p>
<p>Ultime étape de l’installation&nbsp;: activer le <em>post-update hook</em> de Gitosis afin que toute mise à jour de configuration soit bien prise en compte&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
sudo chmod u+x /var/lib/git/repositories/gitosis-admin.git/hooks/post-update
</pre>
<p>Les serveurs Git proposent en effet tous un mécanisme de <em>hooks</em> (points d’ancrage) qui permet de faire exécuter au serveur une ou plusieurs tâches, de façon automatique, à divers moments.  Le <em>post-update hook</em>, équivalent du <em>commit hook</em> de Subversion, est le plus employé, puisqu’il se déclenche après toute mise à jour d’un dépôt sur le serveur, et permet donc, par exemple, de déclencher la suite de tests dans le cadre d’une démarche d’intégration continue, ou encore de signaler le <em>push</em> sur divers canaux (e-mail, messagerie instantanée, <span class="caps">IRC</span>…).</p>
<p>Dans le cadre de Gitosis, le <em>post-update hook</em> du dépôt de configuration (<tt>gitosis-admin</tt>) s’emploie à refléter les changements du dépôt dans la configuration concrète du serveur (notamment en ce qui concerne les utilisateurs, leurs clés, et les dépôts reconnus).</p>
<p>Ce qui nous fait une excellente transition vers la section suivante…</p>
<h3>Configurer Gitosis… avec Git</h3>
<p>Eh oui, Gitosis se configure en accédant au dépôt pré-installé <tt>gitosis-admin</tt>.  On le récupère comme suit&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
# cd où ça vous semble bien, puis…
git clone git@localhost:gitosis-admin.git
cd gitosis-admin
</pre>
<p>(Si vous avez installé Gitosis sur une autre machine que celle où vous faites le <tt>git clone</tt>, remplacez <tt>localhost</tt> par le nom ou l’IP du serveur).</p>
<p>Le dépôt est constitué principalement de deux choses&nbsp;:</p>
<ul>
<li>Un fichier de configuration <tt>gitosis.conf</tt>, qui définit les dépôts, comptes utilisateurs, groupes d’utilisateurs et droits d’accès aux dépôts.</li>
<li>Un répertoire <tt>keydir/</tt> contenant, pour chaque nom d’utilisateur présent dans <tt>gitosis.conf</tt>, un fichier avec le même nom et l’extension <tt>.pub</tt>, qui liste les clés publiques associées à cet utilisateur.</li>
</ul>
<h4>Définir les utilisateurs</h4>
<p>Le fichier de configuration <tt>gitosis.conf</tt> a une syntaxe très simple, similaire aux bons vieux fichiers <tt>.ini</tt>.  Voici le début de mon <tt>gitosis.conf</tt> pour la première session des Ateliers Git Attitude&nbsp;:</p>
<pre class="brush: plain; title: ; notranslate">
[gitosis]

[group gitosis-admin]
writable = gitosis-admin
members = tdd

[group git-attitude]
writable = prems
members = tdd xavier olivier hugo maurice nicolas kaelig francois mickael jonathan thierry
</pre>
<p>Notez qu&#8217;on peut aussi fournir un accès en lecture seule dans un groupe, en utilisant la clé <tt>readonly</tt> au lieu de la clé <tt>writable</tt>. Toutefois, on passe quand même par le protocole SSH, pas par un accès anonyme de type <tt>git://</tt> voire <tt>http://</tt>. Pour ces types d&#8217;accès, le mieux est d&#8217;utiliser <tt>git-daemon</tt>, qui est fourni avec Git lui-même. J&#8217;en parlerai un de ces jours…</p>
<p>Il existe de multiples façons de définir les dépôts, groupes, utilisateurs et droits.  Ma préférence personnelle va au choix qu’on retrouve ci-dessus&nbsp;:</p>
<ul>
<li>Définir un <tt>[group]</tt> par «&nbsp;groupe de projets&nbsp;» (le nom du groupe est sans importance mais doit être unique)</li>
<li>Y placer le ou les noms des dépôts accessibles en lecture/écriture dans la clé <tt>writable</tt></li>
<li>Y placer le ou les noms des dépôts accessibles en lecture dans la clé <tt>readonly</tt></li>
<li>Y placer le ou les noms des utilisateurs concernés dans la clé <tt>members</tt></li>
</ul>
<p>Il existe d’autres manières de procéder, mais quoi qu’on fasse, <strong>les noms des utilisateurs sont à votre convenance</strong>. En effet, ils ne seront jamais utilisés par l’extérieur (notamment dans les URLs de dépôts distants), ce sont des «&nbsp;noms logiques&nbsp;» internes à Gitosis.  La seule contrainte, c’est que le fichier recensant les clés publiques associées à un utilisateur soit nommé <tt>keydir/<em>nom-logique-utilisateur</em>.pub</tt>.</p>
<p>Ainsi, mon dossier <tt>keydir/</tt> a l’aspect suivant&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
$ ls -l keydir/
total 40
-rw-r--r-- 1 tdd tdd 610 jul 10 18:28 francois.pub
-rw-r--r-- 1 tdd tdd 618 jul 10 18:30 hugo.pub
-rw-r--r-- 1 tdd tdd 433 jul 10 18:28 jonathan.pub
-rw-r--r-- 1 tdd tdd 609 jul 10 18:28 kaelig.pub
-rw-r--r-- 1 tdd tdd 422 jul 10 18:29 maurice.pub
-rw-r--r-- 1 tdd tdd 604 jul 10 18:27 mickael.pub
-rw-r--r-- 1 tdd tdd 606 jul 10 18:30 nicolas.pub
-rw-r--r-- 1 tdd tdd 603 jul 10 18:29 olivier.pub
-rw-r--r-- 1 tdd tdd 609 jul  7 23:29 tdd.pub
-rw-r--r-- 1 tdd tdd 609 jul 10 18:30 thierry.pub
</pre>
<p>Chaque fichier recense la ou les <strong>clés publiques</strong> associées au compte, <strong>à raison d’une par ligne</strong>. Par exemple, <tt>keydir/tdd.pub</tt> contient la clé publique de mon compte sur mon laptop (je l’ai découpée ici en plusieurs lignes pour qu’elle soit lisible d’entrée sur le blog, mais encore une fois, en temps normal tout serait sur <em>une seule ligne</em>)&nbsp;:</p>
<pre>ssh-dss AAAAB3NzaC1kc3MAAACBALsvVpQOjngftILkQYHMiztcmPq9jHJbmsM
rBiAuxG/6tLhd8n1q8tEP5D8dwcXI6KjsWZxJNfv2rW9f5wz+Pc9Ahxo+Ru9gCv
oFV3a5igMLdaWq/eaNCDn9HtZyBxHf6uXMtPekKroLqTn6lxTKHnve1HcVUgxqr
4cNBiUkEZyjAAAAFQC2ypQSwpy5+XNqHj4lesk39FXsnwAAAIAkqehiHDbd9x0H
cfRIwIGt1hwxUIIzljMfJPsvanI7VgP7e8LveP+ZI8ZE9/swlS9dmYDJlxJ12dI
w93fC7dpi6OWSZy2Bcr1JMNXqR1MSyt2LlcUk7G2hVvN3ThfC0D02Un/lUI/uYH
ciFjVTKttMG92aXy/y1EV/rUwdiW1NaQAAAIBWKFrXAu5hiheDuyL9m1LXPiU9K
ruoQ4AJXBaAKMY45R4rKckJPir4nha8z1lVtXt7MhWbLMendS2pZzkMS5xImxym
bK5i9SQgoXUjawvNiDUvgh0mHUkONkAkS8xl+NAPnUKxSj4l3cszvLhiPlp9m6U
30dMomUHe+M9CIgZrZg== tdd@CodeMagic.local</pre>
<p>Si vous utilisez une clé <span class="caps">RSA</span>, vous aurez quelque chose d’un peu plus court, et démarrant par <tt>ssh-rsa</tt> au lieu de <tt>ssh-dss</tt>, comme c’est par exemple le case de Mauriz&nbsp;:</p>
<pre>ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA7XwkkW4nDqT1r668SFgTfadtOuI
afNhe7dTRllM76rIfsjEc07nQovQLTU9t24whQr3HS0sEzPJ6Sz+F1SbjtfTCul
iNNinmcizswDJbXcwr6Pe6kDeb+ulB2tnmQ76janpWDpxYFZdYxqFqggHSc+Un+
ubenlENTUOB+sy7PVRn54lfe0Pjlk5HsmCLNNA81VV6O82/77XYTR+7VYMPEmj8
J4GYmpYiuNG5bM7aUnXPxJ73fG0eQXtCsZ9fGCah9eaxubfTQ8UvO+t+2aKc0a0
+unaFEvEndo/17uGIhVdZhIQzop9ygsi/hGQDp8IDLgxDGPhYuO/N8ozjWrPOYw
== mauricesvay@Macbook-Pro-de-Maurice.local</pre>
<h4>Définir des dépôts</h4>
<p>Les dépôts sont définis par la simple présence de leur nom dans une clé <tt>readonly</tt> ou <tt>writable</tt>.  Toutefois, un dépôt qui ne serait présent dans aucun <tt>writable</tt> ne pourra être rempli par personne et, du coup, ne servirait pas à grand chose…</p>
<h3>Test : votre premier dépôt sur Gitosis</h3>
<p>OK, calons ensemble le nécessaire à votre premier dépôt distant.</p>
<h4>Paramétrer Gitosis</h4>
<p>Primo, définissons l’accès.  Supposons que votre nom d’utilisateur au sein de Gitosis sera <tt>the-boss</tt>, et votre dépôt <tt>hot-project</tt>.  Ajoutez les éléments suivants à votre <tt>gitosis.conf</tt>&nbsp;:</p>
<pre class="brush: plain; title: ; notranslate">
[group my-projects]
writable = hot-project
members = the-boss
</pre>
<p>Ensuite, puisque Gitosis ne connaît pas encore votre compte, copiez votre clé publique au bon endroit et ajoutez-la dans l’index&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
cp ~/.ssh/id_dsa_git.pub keydir/the-boss.pub
git add keydir/the-boss.pub
</pre>
<p>Il ne vous reste plus qu’à faire un commit puis un <em>push</em> vers Gitosis&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
$ git commit -am &quot;Ajout dépôt hot-project et utilisateur the-boss&quot;
[master e46c687] Ajout dépôt hot-project et utilisateur the-boss
2 files changed, 5 insertions(+), 0 deletions(-)
create mode 100644 keydir/the-boss.git
$ git push
Counting objects: 8, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 984 bytes, done.
Total 5 (delta 2), reused 0 (delta 0)
To git@localhost:gitosis-admin.git
 ac757b7..e46c687  master -&gt; master
</pre>
<p>Le <em>post-update hook</em> fait alors son travail, et votre configuration <span class="caps">SSH</span> pour l’utilisateur <tt>git</tt> est mise à jour. En effet, si vous êtes curieux, vous pouvez jetez un œil au fichier <tt>.ssh/authorized_keys</tt> de ce compte, et vous y verrez votre utilisateur <tt>the-boss</tt> et ses réglages dédiés (j’ai ajouté quelques passages à la ligne, et tronqué la clé publique, pour la lisibilité de cet article)&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
$ sudo cat /var/lib/git/.ssh/authorized_keys
### autogenerated by gitosis, DO NOT EDIT
command=&quot;gitosis-serve the-boss&quot;,no-port-forwarding,
no-X11-forwarding,no-agent-forwarding,no-pty
ssh-dss AAAAB3NzaC1kc3MAAACBALs…gZrZg== tdd@CodeMagic.local
</pre>
<p>C’est grâce à ces lignes que Gitosis sait automatiquement, sur la base des clés privées dont vous disposez et qui correspondent à ses clés publiques recensées, quel utilisateur logique vous êtes et quels traitements <span class="caps">SSH</span> vous autoriser.  La main passe immédiatement à <tt>gitosis-serve</tt> (dans un contexte très contrôlé), qui exploite la configuration Gitosis pour les droits d’accès.</p>
<h4>Tester le dépôt</h4>
<p>Comme toujours avec un dépôt distant, il existe deux cas de figure&nbsp;:</p>
<ul>
<li>Vous avez déjà des travaux locaux, qu’il s’agit alors d’envoyer sur le dépôt distant.  Dans ce cas, nous allons simplement ajouter un <em>remote</em> et faire un <em>premier push explicite</em> (ainsi qu’une configuration pour pouvoir, par la suite, utiliser des <em>pulls implicites</em>).</li>
<li>Vous n’avez pas encore de travaux locaux, auquel cas le plus simple est de démarrer avec un <em>clone</em> histoire de paramétrer d’un seul coup le <em>remote</em>, le <em>push</em> et le <em>pull</em>.</li>
</ul>
<p>Voyons déjà le second cas, qui est le plus simple.</p>
<h5>Rien dans les poches&nbsp;: on démarre avec <tt>git clone</tt></h5>
<p>Il vous suffit en effet de vous placer dans le dossier parent de votre futur dossier projet, et de faire un <em>git clone</em>, exactement comme si vous récupériez un projet existant&nbsp;; la seule différence, c’est que là, le projet sera vide&nbsp;:</p>
<pre class="brush: bash; highlight: [4,5]; title: ; notranslate">
# cd où ça vous semble bien, puis…
$ git clone git@localhost:hot-project.git
Initialized empty Git repository in /Users/tdd/tmp/hot-project/.git/
Initialized empty Git repository in /private/var/lib/git/repositories/hot-project.git/
warning: You appear to have cloned an empty repository.
</pre>
<p>Notez les deux dernières lignes…</p>
<p>«&nbsp;Initialized empty Git repository in /private/var/lib/git/repositories/hot-project.git/&nbsp;» (le chemin initial ne sera pas forcément le même, ça dépend du <em>home directory</em> que vous aurez donné à l’utilisateur système <tt>git</tt>, et sur <span class="caps">OSX</span> <tt>/var</tt> est en fait <tt>/private/var</tt>) indique que le serveur distant a bien connaissance de ce projet mais n’avait pas encore la moindre donnée pour lui&nbsp;: il a donc initialisé le dépôt distant (pour les curieux, il a juste créé le dossier et y a fait un <tt>git init --bare</tt>).</p>
<p>Sur la dernière ligne, avec «&nbsp;warning: You appear to have cloned an empty repository.&nbsp;», Git vous prévient que vous venez de cloner un dépôt vide, ce qui n’est pas en soi un problème mais reste une situation suffisamment atypique pour être signalée.</p>
<p>L’avantage de cette méthode, lorsque vous n’avez encore aucun travail local existant, est qu’elle configure d’entrée de jeu le <em>remote</em> et les éléments nécessaires pour faire des <em>git push</em> et <em>git pull</em> implicites (c’est-à-dire n’ayant pas besoin de préciser le <em>remote</em> et la branche). Pour vous en convaincre, jetez un œil à la configuration du projet ainsi clôné&nbsp;:</p>
<pre class="brush: bash; highlight: [9,10,11,12,13,14]; title: ; notranslate">
$ cat hot-project/.git/config
# (ou, pour un autre format, git config -f hot-project/.git/config --list)
[core]
  repositoryformatversion = 0
  filemode = true
  bare = false
  logallrefupdates = true
  ignorecase = true
[remote &quot;origin&quot;]
  fetch = +refs/heads/*:refs/remotes/origin/*
  url = git@localhost:hot-project.git
[branch &quot;master&quot;]
  remote = origin
  merge = refs/heads/master
</pre>
<p>Notez la section <tt>[remote &#8220;origin&#8221;]</tt>, qui définit le <em>remote</em>, et <tt>[branch &#8220;master&#8221;]</tt>, qui définit la configuration distante de la branche <tt>master</tt> locale. Grâce à cette dernière section notamment, nous n’avons pas besoin de préciser quel <em>remote</em> et quelle branche distante exploiter pour un <em>push</em> ou un <em>pull</em>&nbsp;: on dit que la branche locale <tt>master</tt> est configurée pour <em>tracker</em> la branche distante <tt>origin/master</tt>.</p>
<h5>Déjà du boulot en local&nbsp;: <em>remote</em> + <em>push</em> initial explicite + tracking</h5>
<p>Bon, ça, c’était le cas simple.  Imaginons maintenant que vous aviez déjà du boulot en cours.  Simulons ça avec un dépôt local créé vite fait&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
$ cd /tmp
$ mkdir existing-hot-project
$ cd existing-hot-project
$ git init
Initialized empty Git repository in /private/tmp/existing-hot-project/.git/
$ echo 'toto' &gt; toto
$ git add toto
$ git commit -am &quot;Du boulot local existant&quot;
[master (root-commit) dbcb4c7] Du boulot local existant
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 toto
</pre>
<p>Il nous faut maintenant définir notre premier (et généralement notre seul) <em>remote</em> explicitement. Nous allons garder le nom conventionnel pour le <em>remote</em> principal&nbsp;: <em>origin</em>.</p>
<pre class="brush: bash; title: ; notranslate">
$ git remote add origin git@localhost:hot-project.git
</pre>
<p>À présent, il faut faire un premier <em>push</em>.  Faute d’info de <em>tracking</em> résultant d’un <em>clone</em> ou d’une configuration manuelle, nous devons préciser le <em>remote</em> et la branche distante. Il n’y a pas de raison ici (et la plupart du temps) de nommer la distante autrement que la locale, donc on l’appellera aussi <em>master</em>.</p>
<pre class="brush: bash; title: ; notranslate">
$ git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 229 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@localhost:hot-project.git
* [new branch]      master -&gt; master
</pre>
<p>On y est presque (et manifestement Gitosis marche très bien). En effet, le <em>tracking</em> n’est pas défini automatiquement par notre <em>push</em> explicite tel que nous l’avons fait&nbsp;:</p>
<pre class="brush: plain; title: ; notranslate">
$ git pull
You asked me to pull without telling me which branch you
want to merge with, and 'branch.master.merge' in
your configuration file does not tell me, either. Please
specify which branch you want to use on the command line and
try again (e.g. 'git pull &lt;repository&gt; &lt;refspec&gt;').
See git-pull(1) for details.

If you often merge with the same branch, you may want to
use something like the following in your configuration file:

  [branch &quot;master&quot;]
  remote = &lt;nickname&gt;
  merge = &lt;remote-ref&gt;

  [remote &quot;&lt;nickname&gt;&quot;]
  url = &lt;url&gt;
  fetch = &lt;refspec&gt;

See git-config(1) for details.
</pre>
<p>Une première approche consisterait à ajouter la configuration correspondante à la main&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
$ git config --add branch.master.remote origin
$ git config --add branch.master.merge refs/heads/master
$ git pull
Already up-to-date.
</pre>
<p>Je vous montre ça pour des <em>pushes</em> que vous pourriez déjà avoir fait, et où ces réglages pourraient s’avérer utiles. Mais en fait, la meilleure manière dans ces cas-là est d’ajouter une petite option au <em>push</em> explicite&nbsp;: <tt>-u</tt> (ou sa version longue, <tt>--set-upstream</tt>). Cette option va réaliser nos configurations pour nous. Essayons en virant le <em>remote</em> et en le rajoutant&nbsp;:</p>
<pre class="brush: bash; title: ; notranslate">
$ git remote rm origin
$ git remote add origin git@localhost:hot-project.git
$ git push origin master -u
Branch master set up to track remote branch master from origin.
Everything up-to-date
$ git pull
Already up-to-date.
</pre>
<p>Bon, vu qu’on avait déjà fait un <em>push</em> de notre travail local tout-à-l’heure, naturellement au nouveau <em>push</em>, «&nbsp;Everything up-to-date&nbsp;». En revanche, notez le message «&nbsp;Branch master set up to track remote branch master from origin.&nbsp;», qui montre bien que Git a configuré pour nous le <em>tracking</em> entre branches locale et distante. Et de fait, un <em>pull</em> implicite juste après trouve ses petits.</p>
<h3>En conclusion</h3>
<p>Voilà, je crois que vous avez désormais toutes les billes pour mettre en place votre propre hébergement Git (et peut-être avez-vous appris au passage une ou deux choses sur la gestion des dépôts distants).</p>
<p>Il est vrai que nous n’avons pas vu comment installer un serveur Git sous Windows, mais au risque de troller, un <em>serveur sous Windows</em>…  Soyons sérieux deux minutes !  Plus pragmatiquement, cela est principalement dû au fait que les serveurs Git reposent fortement sur <span class="caps">SSH</span> et des configurations avancées d’utilisateurs, toutes choses qui sont ardues à transposer sous Windows, et quand bien même on y arriverait finalement, seraient fortement ralenties par la nécessaire couche intermédiaire basée Cygwin.  Sans parler des problématiques de correspondance d’attributs, de gestion de casse <span class="caps">MAJ</span>/min et d’horodatage des fichiers entre les univers Linux, <span class="caps">OSX</span> et Windows.  Du coup, rendez-vous service et si vous hébergez du Git, faites-le sur Linux ou <span class="caps">OSX</span>. D’où ce billet.</p>
<p>Les commentaires sont ouverts, aussi n’hésitez pas à me faire part de vos retours, questions et suggestions.</p>
<p>Bon hébergement Git à tous&nbsp;!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.git-attitude.fr/2010/07/18/heberger-un-serveur-git-avec-gitosis-linux-osx/feed/</wfw:commentRss>
		<slash:comments>53</slash:comments>
		</item>
		<item>
		<title>Le prompt Bash qui change la vie avec Git</title>
		<link>http://www.git-attitude.fr/2010/07/14/le-prompt-bash-qui-change-la-vie-avec-git/</link>
		<comments>http://www.git-attitude.fr/2010/07/14/le-prompt-bash-qui-change-la-vie-avec-git/#comments</comments>
		<pubDate>Wed, 14 Jul 2010 09:15:47 +0000</pubDate>
		<dc:creator>Christophe</dc:creator>
				<category><![CDATA[Astuces et Outils]]></category>

		<guid isPermaLink="false">http://www.git-attitude.fr/?p=10</guid>
		<description><![CDATA[Lors de l&#8217;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 &#171;&#160;high-level&#160;&#187; est appelée à chaque prompt. Elle permet de voir immédiatement : Dans quelle branche on est Si on a des modifs en working tree [...]]]></description>
			<content:encoded><![CDATA[<p>Lors de l&#8217;atelier de samedi je vous ai promis un <strong>prompt Bash qui déboîte</strong> quand on fait du Git.</p>
<p>Celui-ci repose sur une série de fonctions Bash dont la plus &laquo;&nbsp;high-level&nbsp;&raquo; est appelée à chaque prompt. Elle permet de voir immédiatement :</p>
<ul>
<li>Dans quelle branche on est</li>
<li>Si on a des modifs en <em>working tree</em></li>
<li>Si on a des modifs en <em>stage</em></li>
<li>Si on a des fichiers <em>untracked</em></li>
<li>Si on a du <em>stash</em></li>
</ul>
<p>Toutes choses fort utiles au moment de faire son commit, histoire de ne rien oublier…</p>
<p>Voici le code source avec quelques commentaires. Vous pouvez aussi <a href="http://gist.github.com/473838">aller piocher le Gist</a> directement.</p>
<div class="codecolorer-container bash blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:615px;height:615px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br />78<br />79<br />80<br />81<br />82<br />83<br />84<br />85<br />86<br />87<br />88<br />89<br />90<br />91<br />92<br />93<br />94<br />95<br />96<br />97<br />98<br />99<br />100<br />101<br />102<br />103<br />104<br />105<br />106<br />107<br />108<br />109<br />110<br />111<br />112<br />113<br />114<br />115<br />116<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;"># Scavenged from Git 1.6.5.x contrib/completion/git_completion.bash</span><br />
<span style="color: #666666; font-style: italic;"># __git_ps1 accepts 0 or 1 arguments (i.e., format string)</span><br />
<span style="color: #666666; font-style: italic;"># returns text to add to bash PS1 prompt (includes branch name)</span><br />
__gitdir <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
<span style="color: #7a0874; font-weight: bold;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-z</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">${1-}</span>&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">${__git_dir-}</span>&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$__git_dir</span>&quot;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">elif</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-d</span> .git <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #7a0874; font-weight: bold;">echo</span> .git<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">else</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #c20cb9; font-weight: bold;">git rev-parse</span> <span style="color: #660033;">--git-dir</span> <span style="color: #000000;">2</span><span style="color: #000000; font-weight: bold;">&gt;/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">fi</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">elif</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">&quot;$1/.git&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;$1/.git&quot;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">else</span><br />
&nbsp; &nbsp; <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;$1&quot;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">fi</span><br />
<span style="color: #7a0874; font-weight: bold;">&#125;</span><br />
__git_ps1 <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
<span style="color: #7a0874; font-weight: bold;">&#123;</span><br />
&nbsp; <span style="color: #7a0874; font-weight: bold;">local</span> <span style="color: #007800;">g</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$(__gitdir)</span>&quot;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$g</span>&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; <span style="color: #7a0874; font-weight: bold;">local</span> r<br />
&nbsp; &nbsp; <span style="color: #7a0874; font-weight: bold;">local</span> b<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-f</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$g</span>/rebase-merge/interactive&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #007800;">r</span>=<span style="color: #ff0000;">&quot;|REBASE-i&quot;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #007800;">b</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$(cat &quot;$g/rebase-merge/head-name&quot;)</span>&quot;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">elif</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$g</span>/rebase-merge&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #007800;">r</span>=<span style="color: #ff0000;">&quot;|REBASE-m&quot;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #007800;">b</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$(cat &quot;$g/rebase-merge/head-name&quot;)</span>&quot;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">else</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$g</span>/rebase-apply&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-f</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$g</span>/rebase-apply/rebasing&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #007800;">r</span>=<span style="color: #ff0000;">&quot;|REBASE&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">elif</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-f</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$g</span>/rebase-apply/applying&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #007800;">r</span>=<span style="color: #ff0000;">&quot;|AM&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #007800;">r</span>=<span style="color: #ff0000;">&quot;|AM/REBASE&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">fi</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">elif</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-f</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$g</span>/MERGE_HEAD&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #007800;">r</span>=<span style="color: #ff0000;">&quot;|MERGING&quot;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">elif</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-f</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$g</span>/BISECT_LOG&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #007800;">r</span>=<span style="color: #ff0000;">&quot;|BISECTING&quot;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">fi</span><br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color: #007800;">b</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$(git symbolic-ref HEAD 2&gt;/dev/null)</span>&quot;</span> <span style="color: #000000; font-weight: bold;">||</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #007800;">b</span>=<span style="color: #ff0000;">&quot;$(<br />
&nbsp; &nbsp; &nbsp; &nbsp; case &quot;</span><span style="color: #800000;">${GIT_PS1_DESCRIBE_STYLE-}</span><span style="color: #ff0000;">&quot; in<br />
&nbsp; &nbsp; &nbsp; &nbsp; (contains)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; git describe --contains HEAD ;;<br />
&nbsp; &nbsp; &nbsp; &nbsp; (branch)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; git describe --contains --all HEAD ;;<br />
&nbsp; &nbsp; &nbsp; &nbsp; (describe)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; git describe HEAD ;;<br />
&nbsp; &nbsp; &nbsp; &nbsp; (* | default)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; git describe --exact-match HEAD ;;<br />
&nbsp; &nbsp; &nbsp; &nbsp; esac 2&gt;/dev/null)&quot;</span> <span style="color: #000000; font-weight: bold;">||</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #007800;">b</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$(cut -c1-7 &quot;$g/HEAD&quot; 2&gt;/dev/null)</span>...&quot;</span> <span style="color: #000000; font-weight: bold;">||</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #007800;">b</span>=<span style="color: #ff0000;">&quot;unknown&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #007800;">b</span>=<span style="color: #ff0000;">&quot;(<span style="color: #007800;">$b</span>)&quot;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #7a0874; font-weight: bold;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">fi</span><br />
<br />
&nbsp; &nbsp; <span style="color: #7a0874; font-weight: bold;">local</span> <span style="color: #c20cb9; font-weight: bold;">w</span><br />
&nbsp; &nbsp; <span style="color: #7a0874; font-weight: bold;">local</span> i<br />
&nbsp; &nbsp; <span style="color: #7a0874; font-weight: bold;">local</span> s<br />
&nbsp; &nbsp; <span style="color: #7a0874; font-weight: bold;">local</span> u<br />
&nbsp; &nbsp; <span style="color: #7a0874; font-weight: bold;">local</span> c<br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #ff0000;">&quot;true&quot;</span> = <span style="color: #ff0000;">&quot;<span style="color: #007800;">$(git rev-parse --is-inside-git-dir 2&gt;/dev/null)</span>&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #ff0000;">&quot;true&quot;</span> = <span style="color: #ff0000;">&quot;<span style="color: #007800;">$(git rev-parse --is-bare-repository 2&gt;/dev/null)</span>&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #007800;">c</span>=<span style="color: #ff0000;">&quot;BARE:&quot;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #007800;">b</span>=<span style="color: #ff0000;">&quot;GIT_DIR!&quot;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">fi</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">elif</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #ff0000;">&quot;true&quot;</span> = <span style="color: #ff0000;">&quot;<span style="color: #007800;">$(git rev-parse --is-inside-work-tree 2&gt;/dev/null)</span>&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">${GIT_PS1_SHOWDIRTYSTATE-}</span>&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$(git config --bool bash.showDirtyState)</span>&quot;</span> <span style="color: #000000; font-weight: bold;">!</span>= <span style="color: #ff0000;">&quot;false&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #c20cb9; font-weight: bold;">git diff</span> <span style="color: #660033;">--no-ext-diff</span> <span style="color: #660033;">--ignore-submodules</span> \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #660033;">--quiet</span> <span style="color: #660033;">--exit-code</span> <span style="color: #000000; font-weight: bold;">||</span> <span style="color: #007800;">w</span>=<span style="color: #ff0000;">&quot;*&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #c20cb9; font-weight: bold;">git rev-parse</span> <span style="color: #660033;">--quiet</span> <span style="color: #660033;">--verify</span> HEAD <span style="color: #000000; font-weight: bold;">&gt;/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #c20cb9; font-weight: bold;">git diff-index</span> <span style="color: #660033;">--cached</span> <span style="color: #660033;">--quiet</span> \<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #660033;">--ignore-submodules</span> HEAD <span style="color: #660033;">--</span> <span style="color: #000000; font-weight: bold;">||</span> <span style="color: #007800;">i</span>=<span style="color: #ff0000;">&quot;+&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #007800;">i</span>=<span style="color: #ff0000;">&quot;#&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">fi</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">fi</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">fi</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">${GIT_PS1_SHOWSTASHSTATE-}</span>&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #c20cb9; font-weight: bold;">git rev-parse</span> <span style="color: #660033;">--verify</span> refs<span style="color: #000000; font-weight: bold;">/</span>stash <span style="color: #000000; font-weight: bold;">&gt;/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null <span style="color: #000000;">2</span><span style="color: #000000; font-weight: bold;">&gt;&amp;</span><span style="color: #000000;">1</span> <span style="color: #000000; font-weight: bold;">&amp;&amp;</span> <span style="color: #007800;">s</span>=<span style="color: #ff0000;">&quot;$&quot;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">fi</span><br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">${GIT_PS1_SHOWUNTRACKEDFILES-}</span>&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$(git ls-files --others --exclude-standard)</span>&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #007800;">u</span>=<span style="color: #ff0000;">&quot;%&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000000; font-weight: bold;">fi</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">fi</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">fi</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">${1-}</span>&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">&quot;$1&quot;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$c</span><span style="color: #007800;">${b##refs/heads/}</span><span style="color: #007800;">$w</span><span style="color: #007800;">$i</span><span style="color: #007800;">$s</span><span style="color: #007800;">$u</span><span style="color: #007800;">$r</span>&quot;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">else</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #7a0874; font-weight: bold;">printf</span> <span style="color: #ff0000;">&quot; (%s)&quot;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$c</span><span style="color: #007800;">${b##refs/heads/}</span><span style="color: #007800;">$w</span><span style="color: #007800;">$i</span><span style="color: #007800;">$s</span><span style="color: #007800;">$u</span><span style="color: #007800;">$r</span>&quot;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">fi</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">fi</span><br />
<span style="color: #7a0874; font-weight: bold;">&#125;</span><br />
<br />
<span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">GIT_PS1_SHOWDIRTYSTATE</span>=<span style="color: #000000;">1</span> <span style="color: #007800;">GIT_PS1_SHOWUNTRACKEDFILES</span>=<span style="color: #000000;">1</span> <span style="color: #007800;">GIT_PS1_SHOWSTASHSTATE</span>=<span style="color: #000000;">1</span><br />
<br />
<span style="color: #666666; font-style: italic;"># Basique…</span><br />
<span style="color: #666666; font-style: italic;"># export PS1='\u@\h:\W$(__git_ps1) \$ '</span><br />
<span style="color: #666666; font-style: italic;"># Avec plein de couleurs…</span><br />
<span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">PS1</span>=<span style="color: #ff0000;">'\[\033[0;37m\]\u@\h:\[\033[0;33m\]\W\[\033[0m\]\[\033[1;32m\]$(__git_ps1)\[\033[0m\] \$ '</span></div></td></tr></tbody></table></div>
<p>Notez les variables qui configurent ce qui est affiché :</p>
<ul>
<li>GIT_PS1_SHOWDIRTYSTATE fait remonter les modifs en <em>working tree</em> (symbole *) et en <em>stage</em> (symbole +)</li>
<li>GIT_PS1_SHOWUNTRACKED_FILES fait remonter les fichiers non présents dans l&#8217;index (non pris en compte jusqu&#8217;à ajout explicite) (symbole %)</li>
<li>GIT_PS1_SHOWSTASHSTATE indique qu&#8217;on a des trucs dans le stash (symbole $)</li>
</ul>
<p>Ç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&#8217;accès à l&#8217;index et à l&#8217;historique… Ensuite c&#8217;est instantané.</p>
<p>Je ne pourrais pas vivre sans !</p>
<p><em>Enjoy!</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.git-attitude.fr/2010/07/14/le-prompt-bash-qui-change-la-vie-avec-git/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

