Professional Documents
Culture Documents
Scott Chacon*
2011-07-13
*Ce chier PDF est la traduction franaise du livre Pro Git. Il est publi sous license Creative Commons
Aribution-Non Commercial-Share Alike 3.0. Jespre que vous lapprcierez, quil vous permera dapprendre
utiliser Git et que vous aiderez Apress en achetant le livre original sur Amazon : http://tinyurl.com/
amazonprogit
Dmarrage rapide
1.1
1.1.1
1.1.2
1.1.3
1.2
1.3
Rudiments de Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.3.1
1.3.2
1.3.3
1.3.4
1.3.5
Installation de Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.4.1
1.4.2
1.4.3
1.4.4
1.4
1.5
1.5.1
Votre identit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
1.5.2
10
1.5.3
11
1.5.4
11
1.6
Obtenir de laide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
1.7
Rsum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
13
2.1
13
2.1.1
13
2.1.2
14
14
2.2.1
15
2.2.2
16
2.2.3
16
2.2.4
18
2.2.5
19
2.2.6
21
2.2
iii
2.3
2.4
2.5
2.6
2.7
2.8
3
23
2.2.8
23
2.2.9
24
25
2.3.1
29
2.3.2
30
31
2.4.1
31
2.4.2
32
2.4.3
33
34
2.5.1
34
2.5.2
35
2.5.3
35
2.5.4
36
2.5.5
36
2.5.6
37
Balisage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
2.6.1
38
2.6.2
38
2.6.3
39
2.6.4
39
2.6.5
40
2.6.6
41
2.6.7
41
2.6.8
42
Trucs et astuces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
2.7.1
Auto-Compltion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
2.7.2
44
Rsum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
45
47
3.1
47
3.2
52
3.2.1
Le branchement de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
52
3.2.2
55
3.2.3
Conits de fusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
57
3.3
Gestion de branches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
59
3.4
61
3.4.1
61
3.4.2
62
63
3.5.1
65
3.5.2
67
3.5.3
68
Rebaser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
68
3.5
3.6
iv
2.2.7
3.7
4
3.6.1
Les bases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
68
3.6.2
70
3.6.3
72
Rsum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
74
75
4.1
Protocoles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
75
4.1.1
Protocole local . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
76
Avantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
76
Inconvnients . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
77
Protocole SSH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
77
Avantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
77
Inconvnients . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
78
Protocole Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
78
Avantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
78
Inconvnients . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
78
Protocole HTTP/S . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
78
Avantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79
Inconvnients . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
80
80
4.2.1
80
4.2.2
Petites installations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
81
Accs SSH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
81
4.3
82
4.4
83
4.5
Accs public . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
85
4.6
GitWeb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
86
4.7
Gitosis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
88
4.8
Le daemon Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
93
4.9
Git hberg . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
95
4.9.1
GitHub . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
95
4.9.2
95
4.9.3
96
4.9.4
98
4.9.5
98
4.9.6
Votre projet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
99
4.9.7
4.9.8
4.1.2
4.1.3
4.1.4
4.2
Git distribu
5.1
5.2
103
5.1.2
5.1.3
5.3
5.2.1
5.2.2
5.2.3
5.2.4
5.2.5
5.2.6
Rsum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
5.3.2
5.3.3
5.3.4
5.3.5
5.4
6
5.3.6
5.3.7
5.3.8
5.3.9
Shortlog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Rsum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Utilitaires Git
6.1
139
6.1.2
6.1.3
6.1.4
6.1.5
6.1.6
6.1.7
6.2
6.3
6.4
vi
6.2.2
La remise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
6.3.1
6.3.2
6.4.2
6.4.3
6.4.4
6.4.5
6.4.6
6.5
6.6
6.5.2
Sous-modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
6.6.1
6.6.2
6.6.3
Superprojects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
6.6.4
6.7
6.8
Rsum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
Personnalisation de Git
7.1
173
7.1.2
7.1.3
7.1.4
7.1.5
7.2
7.2.2
7.2.3
7.2.4
7.3
7.3.1
7.3.2
7.3.3
7.4
7.4.2
7.5
8
Rsum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
203
8.1.2
Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
8.1.3
Dmarrage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
8.1.4
8.1.5
8.1.6
8.1.7
8.1.8
8.1.9
8.1.10
8.2
8.3
9
viii
Importer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
8.2.2
Subversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
8.2.3
Perforce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
8.2.4
Rsum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
225
9.1
9.2
9.2.2
9.2.3
9.3
9.3.2
tiquees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
9.3.3
9.4
9.5
9.6
9.5.1
9.5.2
9.6.2
9.7
9.8
Maintenance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
9.7.2
9.7.3
Rsum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
ix
Chapitre 1
Dmarrage rapide
Ce chapitre traite du dmarrage rapide avec Git. Nous commencerons par expliquer les bases
de la gestion de version, puis nous parlerons de linstallation de Git sur votre systme et nalement
comment le paramtrer pour commencer lutiliser. la n de ce chapitre vous devriez en savoir
assez pour comprendre pourquoi on parle beaucoup de Git, pourquoi vous devriez lutiliser et vous
devriez en avoir une installation prte lemploi.
1-1).
Un des systmes les plus populaires tait RCS, qui est encore distribu avec de nombreux systmes dexploitation aujourdhui. Mme le systme dexploitation populaire Mac OS X inclut le
programme rcs lorsquon installe les outils de dveloppement logiciel. Cet outil fonctionne en conservant des ensembles de patch (cest--dire la dirence entre les chiers) dune version lautre
dans un format spcial sur disque ; il peut alors restituer ltat de nimporte quel chier nimporte
quel instant en ajoutant toutes les dirences.
Ce schma ore de nombreux avantages par rapport la gestion de version locale. Par exemple,
2
chacun sait jusqu un certain point ce que tout les autres sont en train de faire sur le projet. Les
administrateurs ont un contrle n des permissions et il est beaucoup plus facile dadministrer un
CVCS que de grer des bases de donnes locales.
Cependant ce systme a aussi de nombreux dfauts. Le plus visible est le point unique de panne
que le serveur centralis reprsente. Si ce serveur est en panne pendant une heure, alors durant
cee heure, aucun client ne peut collaborer ou enregistrer les modications issues de son travail.
Si le disque dur du serveur central se corrompt, et sil ny a pas eu de sauvegarde, vous perdez
absolument tout de lhistorique dun projet en dehors des sauvegardes locales que les gens auraient
pu raliser sur leur machines locales. Les systmes de gestion de version locaux sourent du mme
problme - ds quon a tout lhistorique dun projet sauvegard un endroit unique, on prend le
risque de tout perdre.
De plus, un grand nombre de ces systmes gre particulirement bien le fait davoir plusieurs
dpts avec lesquels travailler, vous permeant de collaborer avec dirents groupes de personnes
de manire direntes simultanment dans le mme projet. Cela permet la mise en place de diffrentes chanes de traitement qui ne sont pas ralisables avec les systmes centraliss, tels que les
modles hirarchiques.
3
Figure 1.4: Dautres systmes sauvent linformation comme des modications sur des iers.
chiers nont pas chang, Git ne stocke pas le chier nouveau, juste une rfrence vers le chier
original qui na pas t modi. Git pense ses donnes plus la manire de la gure 1-5.
Figure 1.5: Git stoe les donnes comme des instantans du projet au cours du temps
Cest une distinction importante entre Git et quasiment tous les autres VCSs. Git a reconsidr quasiment tous les aspects de la gestion de version que la plupart des autres systme ont copi
des gnrations prcdentes. Cela fait quasiment de Git un mini systme de chiers avec des outils
incroyablement puissants construits au-dessus, plutt quun simple VCS. Nous explorerons les bnces quil y a penser les donnes de cee manire quand nous aborderons la gestion de branches
au chapitre 3.
connecter pour partager votre travail. Si vous tes chez vous et ne pouvez avoir une liaison VPN
avec votre entreprise, vous pouvez tout de mme travailler. Pour de nombreux autres systmes, faire
de mme est impossible ou au mieux trs contraignant. Avec Perforce par exemple, vous ne pouvez
pas faire grandchose tant que vous ntes pas connect au serveur. Avec Subversion ou CVS, vous
pouvez diter les chiers, mais vous ne pourrez pas soumere des modications votre base de
donnes (car celle-ci est sur le serveur non accessible). Cela peut sembler peu important priori,
mais vous seriez tonn de dcouvrir quelle grande dirence cela peut constituer lusage.
24b9da6552252987aa493b52f8696cd6d3b00373
Vous trouverez ces valeurs peu prs partout dans Git car il les utilise pour tout. En fait, Git
stocke tout non pas avec des noms de chier, mais dans la base de donnes Git indexe par ces
valeurs.
quil na pas encore t commit en base. Index signie que vous avez marqu un chier modi
dans sa version actuelle pour quil fasse partie du prochain instantan du projet.
Ceci nous mne aux trois sections principales dun projet Git : le rpertoire Git, le rpertoire
de travail et la zone dindex.
Le rpertoire Git est lendroit o Git stocke les mta-donnes et la base de donnes des objets
de votre projet. Cest la partie la plus importante de Git, et cest ce qui est copi lorsque vous clonez
un dpt depuis un autre ordinateur.
Le rpertoire de travail est une extraction unique dune version du projet. Ces chiers sont
extraits depuis la base de donnes compresse dans le rpertoire Git et placs sur le disque pour
pouvoir tre utiliss ou modis.
La zone dindex est un simple chier, gnralement situ dans le rpertoire Git, qui stocke les
informations concernant ce qui fera partie du prochain instantan.
Lutilisation standard de Git se passe comme suit :
1. Vous modiez des chiers dans votre rpertoire de travail
2. Vous indexez les chiers modis, ce qui ajoute des instantans de ces chiers dans la zone
dindex
3. Vous ralisez un commit, ce qui a pour eet de basculer les instantans des chiers de lindex
dans la base de donne du rpertoire Git.
Si une version particulire dun chier est dans le rpertoire Git, il est considr comme commit.
Sil est modi mais a t ajout dans la zone dindex, il est index. Sil a t modi depuis le dernier
instantan mais na pas t index, il est modi. Dans le chapitre 2, vous en apprendrez plus sur
ces tats et comment vous pouvez en tirer parti ou compltement les occulter.
and vous avez toutes les dpendances ncessaires, vous pouvez poursuivre et tlcharger la
dernire version de Git depuis le site :
http://git-scm.com/download
Puis, compiler et installer :
Aprs ceci, vous pouvez obtenir Git par Git lui-mme pour les mises jour :
Si vous tes sur un systme bas sur Debian, tel quUbuntu, essayez apt-get :
Vous navez pas ajouter tous les extras, mais vous souhaiterez srement inclure +svn si vous
tes amen utiliser Git avec des dpts Subversion (voir chapitre 8).
des mises jour. Vous pouvez aussi les changer tout instant en relanant les mmes commandes.
Git contient un outil appel git cong pour vous permere de voir et modier les variables
de conguration qui contrlent tous les aspects de lapparence et du comportement de Git. Ces
variables peuvent tre stockes dans trois endroits dirents :
Fichier /etc/gitconfig : Contient les valeurs pour tous les utilisateurs et tous les dpts
du systme. Si vous passez loption --system git config, il lit et crit ce chier spciquement.
Fichier ~/.gitconfig : Spcique votre utilisateur. Vous pouvez forcer Git lire et crire
ce chier en passant loption --global.
Fichier config dans le rpertoire Git (cest dire .git/config) du dpt en cours dutilisation :
spcique au seul dpt en cours. Chaque niveau surcharge le niveau prcdent, donc les
valeurs dans .git/config surchargent celles de /etc/gitconfig.
Sur les systmes Windows, Git recherche le chier .gitconfig dans le rpertoire $HOME (C:
\Documents and Settings\$USER la plupart du temps). Il recherche tout de mme /etc/
gitconfig, bien quil soit relatif la racine MSys, qui se trouve o vous aurez dcid dinstaller
Git sur votre systme Windows.
Encore une fois, cee tape nest ncessaire quune fois si vous passez loption --global,
parce que Git utilisera toujours cee information pour tout ce que votre utilisateur fera sur ce
systme. Si vous souhaitez surcharger ces valeurs avec un nom ou une adresse e-mail dirents
pour un projet spcique, vous pouvez lancer ces commandes sans option --global lorsque vous
tes dans ce projet.
10
Git accepte kdi3, tkdi, meld, xxdi, emerge, vimdi, gvimdi, ecmerge, et opendi comme
outils valides de fusion. Vous pouvez aussi paramtrer un outil personnalis ; rfrez-vous au chapitre
7 pour plus dinformation sur cee procdure.
Vous pourrez voir certains paramtres apparatre plusieurs fois, car Git lit les mmes paramtres
depuis plusieurs chiers (/etc/gitconfig et ~/.gitconfig, par exemple). Git utilise la
dernire valeur pour chaque paramtre.
Vous pouvez aussi vrier la valeur eective dun paramtre particulier en tapant git config <paramtre> :
Par exemple, vous pouvez obtenir la page de manuel pour la commande cong en lanant :
11
Ces commandes sont vraiment sympathiques car vous pouvez y accder depuis partout, y compris hors connexion. Si les pages de manuel et ce livre ne sont pas susants, vous pouvez essayer
les canaux #git ou #github sur le serveur IRC Freenode (irc.freenode.net). Ces canaux sont
rgulirement peupls de centaines de personnes qui ont une bonne connaissance de Git et sont
souvent prtes aider.
1.7 Rsum
Vous devriez avoir prsent une comprhension initiale de ce que Git est et en quoi il est diffrent des CVCS que vous pourriez dj avoir utiliss. Vous devriez aussi avoir une version de Git en
tat de fonctionnement sur votre systme, paramtre avec votre identit. Il est temps dapprendre
les bases dutilisation de Git.
12
Chapitre 2
$ git init
Cela cre un nouveau sous-rpertoire nomm .git qui contient tous les chiers ncessaire au
dpt un squelee de dpt Git. Pour linstant, rien nest encore suivi en version. (Cf. chapitre 9
pour plus dinformation sur les chiers contenus dans le rpertoire .git que vous venez de crer.)
Si vous souhaitez commencer suivre en version des chiers existants (contrairement un
rpertoire vide), vous devriez probablement commencer par indexer ces chiers et faire une validation initiale. Vous pouvez raliser ceci avec une poigne de commandes Git qui spcient les chiers
que vous souhaitez suivre, suivi dun commit :
13
Nous allons passer en revue ce que ces commandes font dans une petite minute. Pour linstant,
vous avez un dpt git avec des chiers sous gestion de version et un commit initial.
Ceci cre un rpertoire nomm grit , initialise un rpertoire .git lintrieur, rcupre
toutes les donnes de ce dpt, et extrait une copie de travail de la dernire version. Si vous examinez
le nouveau rpertoire grit, vous y verrez les chiers du projet, prt tre modis ou utiliss. Si
vous souhaitez cloner le dpt dans un rpertoire nomm diremment, vous pouvez spcier le
nom dans une option supplmentaire de la ligne de commande :
Cee commande ralise la mme chose que la prcdente, mais le rpertoire cible sappelle
mygrit.
Git dispose de dirents protocoles de transfert que vous pouvez utiliser. Lexemple prcdent
utilise le protocole git://, mais vous pouvez aussi voir http(s):// ou utilisateur@serveur:/
chemin.git, qui utilise le protocole de transfert SSH. Le chapitre 4 introduit toutes les options
disponibles pour mere en place un serveur Git, ainsi que leurs avantages et inconvnients.
Souvenez-vous que chaque chier de votre copie de travail peut avoir deux tats : sous suivi de
version ou non suivi. Les chiers suivis sont les chiers qui appartenait dj au dernier instantan ;
ils peuvent tre inchangs, modis ou indexs. Tous les autres chiers sont non suivis tout chier
de votre copie de travail qui nappartenait pas votre dernier instantan et na pas t index. and
vous clonez un dpt pour la premire fois, tous les chiers seront sous suivi de version et inchangs
car vous venez tout juste de les enregistrer sans les avoir encore dits.
Au fur et mesure que vous ditez des chiers, Git les considre comme modis, car vous les
avez modis depuis le dernier instantan. Vous indexez ces chiers modis et vous enregistrez
toutes les modications indexes, puis ce cycle se rpte. Ce cycle de vie est illustr par la gure
2-1.
$ git status
# On branch master
nothing to commit (working directory clean)
Ce message signie que votre copie de travail est propre, en dautres mots, aucun chier suivi
na t modi. Git ne voit pas non plus de chiers non-suivis, sinon ils seraient lists ici. Enn,
la commande vous indique sur quelle branche vous tes. Pour linstant, cest toujours master, qui
correspond la valeur par dfaut ; nous ne nous en soucierons pas maintenant. Dans le chapitre
suivant, nous parlerons plus en dtail des branches et des rfrences.
Supposons que vous ajoutiez un nouveau chier votre projet, un simple chier LISEZMOI.
Si ce chier nexistait pas auparavant, et que vous lancez la commande git status, vous verrez
votre chier non suivi comme ceci :
$ vim LISEZMOI
$ git status
# On branch master
15
# Untracked files:
#
#
# LISEZMOI
nothing added to commit but untracked files present (use "git add" to track)
Vous pouvez constater que votre nouveau chier LISEZMOI nest pas en suivi de version, car
il apparat dans la section Untracked les de ltat de la copie de travail. Untracked signie
simplement que Git dtecte un chier qui ntait pas prsent dans le dernier instantan ; Git ne le
placera sous suivi en version que quand vous lui indiquerez de le faire. Ce comportement permet de
ne pas placer accidentellement sous suivi de version des chiers binaires gnrs ou dautres chiers
que vous ne voulez pas inclure. Mais vous voulez inclure le chier LISEZMOI dans linstantan, alors
commenons suivre ce chier.
Si vous lancez nouveau le commande status, vous pouvez constater que votre chier LISEZMOI est maintenant suivi et index :
$ git status
# On branch master
# Changes to be committed:
#
#
# new file:
LISEZMOI
Vous pouvez armer quil est index car il apparat dans la section Changes to be commied
(Modications enregistrer).Si vous enregistrez ce moment, la version du chier linstant o vous
lancez git add est celle qui appartiendra linstantan. Vous pouvez vous souvenir que lorsque
vous avez prcdemment lanc git init, vous avez ensuite lanc git add (fichiers)
ctait bien sur pour commencer placer sous suivi de version les chiers de votre rpertoire de
travail. La commande git add accepte en paramtre un chemin qui correspond un chier ou un
rpertoire ; dans le cas dun rpertoire, la commande ajoute rcursivement tous les chiers de ce
rpertoire.
$ git status
# On branch master
# Changes to be committed:
#
#
# new file:
LISEZMOI
#
# Changed but not updated:
#
#
# modified:
benchmarks.rb
Le chier benchmarks.rb apparat sous la section nomme Changed but not updated ce
qui signie que le chier sous suivi de version a t modi dans la copie de travail mais nest
pas encore index. Pour lindexer, il faut lancer la commande git add (qui est une commande
multi-usage elle peut tre utilise pour placer un chier sous suivi de version, pour indexer un
chier ou pour dautres actions telles que marquer comme rsolu des conits de fusion de chiers).
Lanons maintenant git add pour indexer le chier benchmarks.rb, et relanons la commande
git status :
#
# new file:
LISEZMOI
# modified:
benchmarks.rb
A prsent, les deux chiers sont indexs et feront partie de la prochaine validation. Mais supposons que vous souhaitiez apporter encore une petite modication au chier benchmarks.rb avant
de rellement valider la nouvelle version. Vous louvrez nouveau, ralisez la petite modication
et vous voil prt valider. Nanmoins, vous lancez git status une dernire fois :
$ vim benchmarks.rb
$ git status
# On branch master
# Changes to be committed:
#
#
# new file:
LISEZMOI
# modified:
benchmarks.rb
#
# Changed but not updated:
#
17
# modified:
benchmarks.rb
e sest-il donc pass ? prsent, benchmarks.rb apparat la fois comme index et non
index. En fait, Git indexe un chier dans son tat au moment o la commande git add est lance.
Si on valide les modications maintenant, la version de benchmarks.rb qui fera partie de linstantan
est celle correspondant au moment o la commande git add benchmarks.rb a t lance, et
non la version actuellement prsente dans la copie de travail au moment o la commande git commit
est lance. Si le chier est modi aprs un git add, il faut relancer git add pour prendre en
compte ltat actuel dans la copie de travail :
#
# new file:
LISEZMOI
# modified:
benchmarks.rb
$ cat .gitignore
*.[oa]
*~
La premire ligne ordonne Git dignorer tout chier se terminant en .o ou .a des chiers
objet ou archive qui sont gnralement produits par la compilation dun programme. La seconde
ligne indique Git dignorer tous les chiers se terminant par un tilde (~), ce qui est le cas des noms
des chiers temporaires pour de nombreux diteurs de texte tels quEmacs. On peut aussi inclure
un rpertoire log, tmp ou pid, ou le rpertoire de documentation gnre automatiquement, ou tout
autre chier. Renseigner un chier .gitignore avant de commencer travailler est gnralement une
bonne ide qui vitera de valider par inadvertance des chiers qui ne doivent pas apparatre dans
le dpt Git.
Les rgles de construction des patrons placer dans le chier .gitignore sont les suivantes :
Les lignes vides ou commenant par # sont ignore
Les patrons standards de chiers sont utilisables
18
# pas de fichier .a
!lib.a
/TODO
build/
$ git status
# On branch master
# Changes to be committed:
#
#
# new file:
LISEZMOI
#
# Changed but not updated:
#
#
# modified:
benchmarks.rb
Pour visualiser ce qui a t modi mais pas encore index, tapez git diff sans autre argument :
19
$ git diff
diff --git a/benchmarks.rb b/benchmarks.rb
index 3cb747f..da65585 100644
--- a/benchmarks.rb
+++ b/benchmarks.rb
@@ -36,6 +36,10 @@ def main
@commit.parents[0].parents[0].parents[0]
end
+
git.commits.size
end
+
run_code(x, 'commits 2') do
log = git.commits('master', 15)
log.size
Cee commande compare le contenu du rpertoire de travail avec la zone dindex. Le rsultat
vous indique les modications ralises mais non indexes.
Si vous souhaitez visualiser les modications indexes qui feront partie de la prochaine validation, vous pouvez utiliser git diff --cached (avec les versions 1.6.1 et suprieures de Git,
vous pouvez aussi utiliser git diff --staged, qui est plus mnmotechnique). Cee commande
compare les chiers indexs et le dernier instantan :
Il est important de noter que git diff ne montre pas les modications ralises depuis la
dernire validation seulement les modications qui sont non indexes. Cela peut introduire une
confusion car si tous les chiers modis ont t indexs, git diff nindiquera aucun changement.
Par exemple, si vous indexez le chier benchmarks.rb et lditez en suite, vous pouvez utiliser
git diff pour visualiser les modications indexes et non indexes de ce chier :
20
#
# Changes to be committed:
#
# modified:
benchmarks.rb
#
# Changed but not updated:
#
# modified:
benchmarks.rb
A prsent, vous pouvez utiliser git diff pour visualiser les modications non indexes :
$ git diff
diff --git a/benchmarks.rb b/benchmarks.rb
index e445e28..86b2f7c 100644
--- a/benchmarks.rb
+++ b/benchmarks.rb
@@ -127,3 +127,4 @@ end
main()
##pp Grit::GitRuby.cache_client.stats
+# test line
+
run_code(x, 'commits 2') do
log = git.commits('master', 15)
log.size
Dans notre cas, la dernire fois que vous avez lanc git status, vous avez vri que tout
tait index, et vous tes donc prt valider vos modications. La manire la plus simple de valider
est de taper git commit :
$ git commit
Cee action lance votre diteur par dfaut (qui est paramtr par la variable denvironnement
$EDITOR de votre shell habituellement vim ou Emacs, mais vous pouvez le paramtrer spciquement pour git en utilisant la commande git config --global core.editor comme
nous lavons vu au chapitre 1).
Lditeur ache le texte suivant :
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
#
#
#
new file:
LISEZMOI
modified:
benchmarks.rb
~
~
~
".git/COMMIT_EDITMSG" 10L, 283C
Vous constatez que le message de validation par dfaut contient une ligne vide suivie en commentaire le rsultat de la commande git status. Vous pouvez eacer ces lignes de commentaire
et saisir votre propre message de validation, ou vous pouvez les laisser en place vous aider vous
rappeler de ce que vous tes en train de valider (pour un rappel plus explicite de ce que vous avez
modi, vous pouvez aussi passer loption -v la commande git commit. Cee option place le
rsultat du di en commentaire dans lditeur pour vous permere de visualiser exactement ce que
vous avez modi). and vous quiez lditeur (aprs avoir sauvegard le message), Git cre votre
commit avec ce message de validation (aprs avoir retir les commentaires et le di).
Dune autre manire, vous pouvez spcier votre message de validation en ligne avec la commande commit en le saisissant aprs loption -m, de cee manire :
A prsent, vous avez cr votre premier commit ! Vous pouvez constater que le commit vous
fournit quelques information sur lui-mme : sur quelle branche vous avez valid (master), quelle
est sa somme de contrle SHA-1 (463dc4f), combien de chiers ont t modis, et quelques
statistiques sur les lignes ajoutes et eaces dans ce commit.
22
Souvenez-vous que la validation enregistre linstantan que vous avez prpar dans la zone
dindex. Tout ce que vous navez pas index est toujours en tat modi ; vous pouvez raliser une
nouvelle validation pour lajouter lhistorique. A chaque validation, vous enregistrez un instantan
du projet en forme de jalon auquel vous pourrez revenir ou comparer votre travail ultrieur.
$ git status
# On branch master
#
# Changed but not updated:
#
# modified:
benchmarks.rb
#
$ git commit -a -m 'added new benchmarks'
[master 83e38c7] added new benchmarks
1 files changed, 5 insertions(+), 0 deletions(-)
Notez bien que vous navez pas eu lancer git add sur le chier benchmarks.rb avant de
valider.
$ rm grit.gemspec
$ git status
# On branch master
#
# Changed but not updated:
#
#
#
deleted:
grit.gemspec
$ git rm grit.gemspec
rm 'grit.gemspec'
$ git status
# On branch master
#
# Changes to be committed:
#
#
#
deleted:
grit.gemspec
Lors de la prochaine validation, le chier sera absent et non-suivi en version. Si vous avez
auparavant modi et index le chier, son limination doit tre force avec loption -f. Cest une
mesure de scurit pour empcher un eacement accidentel de donnes qui nont pas encore t
enregistres dans un instantan et qui seraient dnitivement perdues.
Un autre scnario serait de vouloir abandonner le suivi de version dun chier tout en le conservant dans la copie de travail. Ceci est particulirement utile lorsquon a oubli de spcier un
patron dans le chier .gitignore et on a accidentellement ajout un chier dans linstantan, tel
quun gros chier de journal ou une srie darchives de compilation .a. Pour raliser ce scnario,
utilisez loption --cached :
Vous pouvez spcier des noms de chiers ou de rpertoires, ou des patrons de chiers la
commande git rm. Cela signie que vous pouvez lancer des commandes telles que
$ git rm log/\*.log
Notez bien lantislash (\) devant *. Il est ncessaire dchapper le caractre * car Git utilise
sa propre expansion de nom de chier en addition de lexpansion du shell. Cee commande eace
tous les chiers avec lextension .log prsents dans le rpertoire log/. Vous pouvez aussi lancer
une commande telle que :
$ git rm \*~
De ce fait, que Git ait une commande mv peut paratre trompeur. Si vous souhaitez renommer
un chier dans Git, vous pouvez lancer quelque chose comme
et cela fonctionne. En fait, si vous lancez quelque chose comme ceci et inspectez le rsultat
dune commande status, vous constaterez que Git gre le renommage de chier :
#
#
renamed:
$ mv LISEZMOI.txt LISEZMOI
$ git rm LISEZMOI.txt
$ git add LISEZMOI
Git trouve implicitement que cest un renommage, donc cela importe peu si vous renommez
un chier de cee manire ou avec la commande mv. La seule dirence relle est que mv ne fait
quune commande taper au lieu de trois cest une commande de convenance. Le point principal
est que vous pouvez utiliser nimporte quel outil pour renommer un chier, et traiter les commandes
add/rm plus tard, avant de valider la modication.
Lorsque vous lancez git log dans le rpertoire de ce projet, vous devriez obtenir un rsultat
qui ressemble ceci :
25
$ git log
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:
first commit
Par dfaut, git log invoqu sans argument numre en ordre chronologique invers les
commits raliss. Cela signie que les commits les plus rcents apparaissent en premier. Comme
vous le remarquez, cee commande indique chaque commit avec sa somme de contrle SHA-1, le
nom et le-mail de lauteur, la date et le message du commit.
git log dispose dun trs grand nombre doptions permeant de paramtrer exactement ce
que lon cherche voir. Nous allons dtailler quelques unes des plus utilises.
Une des options les plus utiles est -p, qui montre les dirences introduites entre chaque validation. Vous pouvez aussi utiliser -2 qui limite la sortie de la commande aux deux entres les plus
rcentes :
$ git log p -2
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:
s.version
"0.1.0"
s.version
"0.1.1"
s.author
"Scott Chacon"
commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:
26
git = SimpleGit.new
puts git.show
-end
\ No newline at end of file
Cee option ache la mme information mais avec un di suivant directement chaque entre.
Cest trs utile pour des revues de code ou pour naviguer rapidement travers lhistorique des
modications quun collaborateur a apportes.
Vous pouvez aussi utiliser une liste doptions de rsum avec git log. Par exemple, si vous
souhaitez visualiser des statistiques rsumes pour chaque commit, vous pouvez utiliser loption
--stat :
2 +-
5 -----
first commit
LISEZMOI
Rakefile
|
|
lib/simplegit.rb |
6 ++++++
23 +++++++++++++++++++++++
25 +++++++++++++++++++++++++
27
Comme vous pouvez le voir, loption --stat ache sous chaque entre de validation une
liste des chiers modis, combien de chiers ont t changs et combien de lignes ont t ajoutes
ou retires dans ces chiers. Elle ajoute un rsum des informations en n de sortie. Une autre
option utile est --pretty. Cee option modie le journal vers un format dirent. elques
options incluses sont disponibles. Loption oneline ache chaque commit sur une seule ligne,
ce qui peut savrer utile lors de la revue dun long journal. De plus, les options short, full et
fuller montrent le rsultat peu de choses prs dans le mme format mais avec de plus en plus
dinformation :
Loption la plus intressante est format qui permet de dcrire prcisment le format de sortie.
Cest spcialement utile pour gnrer des sorties dans un format facile analyser par une machine
lorsquon spcie intgralement et explicitement le format, on sassure quil ne changera pas au gr
des mises jour de Git :
Vous pourriez vous demander quelle est la dirence entre auteur et validateur. Lauteur est la
personne qui a ralis initialement le travail, alors que le validateur est la personne qui a eectivement valid ce travail en gestion de version. Donc, si quelquun envoie patch un projet et un des
membres du projet lapplique, les deux personnes reoivent le crdit lcrivain en tant quauteur,
28
et le membre du projet en tant que validateur. Nous traiterons plus avant de cee distinction au
chapitre 5.
Les options oneline et format sont encore plus utiles avec une autre option log appele -graph. Cee option ajoute un joli graphe en caractres ASCII pour dcrire lhistorique des branches
et fusions, ce que nous pouvons visualiser pour notre copie du dpt de Grit :
|\
| * 420eac9 Added a method for getting the current branch.
* | 30e367c timeout code and tests
* | 5a09431 add timeout protection to grit
* | e1193f8 support for heads with slashes in them
|/
* d6016bc require time for xmlschema
*
Les options ci-dessus ne sont que des options simples de format de sortie de git log il y
en a de nombreuses autres. Le tableau 2-2 donne une liste des options que nous avons traites ainsi
que dautres options communment utilises accompagnes de la manire dont elles modient le
rsultat de la commande log.
Option Description
-p Affiche le patch appliqu par chaque commit
--stat Affiche les statistiques de chaque fichier pour chaque commit
--shortstat N'affiche que les ligne modifies/insres/effaces de l'option --stat
--name-only Affiche la liste des fichiers modifis aprs les informations du commit
--name-status Affiche la liste des fichiers affects accompagns des informations d'ajout/
modification/suppression
--abbrev-commit N'affiche que les premiers caractres de la somme de contrle SHA-1
--relative-date Affiche la date en format relatif (par exemple "2 weeks ago" : il y a deux semaines) au lieu du
--graph Affiche en caractre ASCII le graphe de branches et fusions en vis-vis de l'historique
--pretty=<format>Affiche les commits dans un format alternatif. Les formats incluent oneline, short, full, fu
Cee commande fonctionne avec de nombreux formats vous pouvez indiquer une date spcique (2008-01-05) ou une date relative au prsent telle que 2 years 1 day 3 minutes ago .
Vous pouvez aussi restreindre la liste aux commits vriant certains critres de recherche.
Loption --author permet de ltrer sur un auteur spcique, et loption --grep permet de
chercher des mots cls dans les messages de validation. Notez que si vous cherchez seulement
des commits correspondant simultanment aux deux critres, vous devez ajouter loption --allmatch, car par dfaut ces commandes retournent les commits vriant au moins un critre lors de
recherche de chanes de caractres.
La dernire option vraiment utile git log est la spcication dun chemin. Si un rpertoire
ou un nom de chier est spci, le journal est limit aux commits qui ont introduit des modications
aux chiers concerns. Cest toujours la dernire option de la commande, souvent prcde de deux
tirets (--) pour sparer le chemin des options prcdentes.
Le tableau 2-3 rcapitule les options que nous venons de voir ainsi que quelques autres pour
rfrence.
Option Description
-(n) N'affiche que les n derniers commits
--since, --after Limite l'affichage aux commits raliss aprs la date spcifie
--until, --before Limite l'affichage aux commits raliss avant la date spcifie
--author Ne montre que les commits dont le champ auteur correspond la chane passe en argument
--committer Ne montre que les commits dont le champ validateur correspond la chane passe en argument
Par exemple, si vous souhaitez visualiser quels commits modiant les chiers de test dans
lhistorique du source de Git ont t valids par Junio Hamano et ntaient pas des fusions durant
le mois doctobre 2008, vous pouvez lancer ce qui suit :
A partir des 20 000 commits constituant lhistorique des sources de Git, cee commande extrait
les 6 qui correspondent aux critres.
mimant les fonctionnalits de git log, et il donne accs quasiment toutes les options de ltrage
de git log. Si vous tapez gitk en ligne de commande, vous devriez voir une interface ressemblant
la gure 2-2.
Vous pouvez voir lhistorique des commits dans la partie suprieure de la fentre avec un
graphique denchanement. Le visualisateur de di dans la partie infrieure de la fentre ache
les modications introduites par le commit slectionn.
Cee commande prend en compte la zone dindex et lutilise pour le commit. Si aucune modication na t ralise depuis la dernire validation (par exemple en lanant cee commande immdiatement aprs la dernire validation), alors linstantan sera identique et la seule modication
introduire sera le message de validation.
31
Les trois dernires commandes donnent lieu la cration dun unique commit la seconde
validation remplace le rsultat de la premire.
$ git add .
$ git status
# On branch master
# Changes to be committed:
#
#
#
modified:
LISEZMOI.txt
modified:
benchmarks.rb
Juste sous le texte Changes to be commied , elle vous indique dutiliser git reset HEAD
<fichier>... pour dsindexer un chier. Utilisons donc ce conseil pour dsindexer le chier
benchmarks.rb :
#
#
modified:
LISEZMOI.txt
#
# Changed but not updated:
#
32
#
#
modified:
benchmarks.rb
La commande taper peut sembler trange mais elle fonctionne. Le chier benchmark.rb est
modi mais de retour ltat non index.
#
#
modified:
benchmarks.rb
Cela vous indique de faon explicite comment annuler des modications que vous avez faites
(du moins, les nouvelles versions de Git, 1.6.1 et suprieures le font, si vous avez une version plus
ancienne, nous vous recommandons de la mere jour pour bncier de ces fonctionnalits pratiques). Faisons comme indiqu :
#
#
modified:
LISEZMOI
Vous pouvez constater que les modications ont t annules. Vous devriez aussi vous apercevoir
que cest une commande dangereuse : toutes les modications que vous auriez ralises sur ce chier
ont disparu vous venez tout juste de lcraser avec un autre chier. Nutilisez jamais cee commande moins dtre vraiment sr de ne pas vouloir de ces modications. Si vous souhaitez seulement carter momentanment cee modication, nous verrons comment mere de ct et crer des
branches dans le chapitre suivant ; ce sont de meilleures faons de procder. Souvenez-vous, tout
ce qui a t valid dans Git peut quasiment toujours tre rcupr. Y compris des commits sur des
branches qui ont t eaces ou des commits qui ont t crass par une validation avec loption
--amend (se rfrer au chapitre 9 pour la rcupration de donnes). Cependant, tout ce que vous
perdez avant de lavoir valid na aucune chance dtre rcuprable via Git.
33
Vous pouvez aussi spcier -v, qui vous montre lURL que Git a stock pour nom court
tendre :
$ git remote -v
origin git://github.com/schacon/ticgit.git
Si vous avez plus dun dpt distant, la commande prcdente les liste tous. Par exemple, mon
dpt Grit ressemble ceci.
$ cd grit
$ git remote -v
bakkdoor
git://github.com/bakkdoor/grit.git
cho45
git://github.com/cho45/grit.git
defunkt
git://github.com/defunkt/grit.git
koke
git://github.com/koke/grit.git
origin
git@github.com:mojombo/grit.git
34
Cela signie que nous pouvons tirer trs facilement des contributions depuis certains utilisateurs. Mais il est noter que seul le dpt distant origin utilise une URL SSH, ce qui signie que
cest le seul sur lequel je peux pousser (nous traiterons de ceci au chapitre 4).
$ git remote
origin
$ git remote add pb git://github.com/paulboone/ticgit.git
$ git remote -v
origin git://github.com/schacon/ticgit.git
pb git://github.com/paulboone/ticgit.git
Maintenant, vous pouvez utiliser le mot-cl pb sur la ligne de commande au lieu de lURL
complte. Par exemple, si vous voulez rcuprer toute linformation que Paul a mais ne souhaitez
pas lavoir encore dans votre branche, vous pouvez lancer git fetch pb :
$ git fetch pb
remote: Counting objects: 58, done.
remote: Compressing objects: 100% (41/41), done.
remote: Total 44 (delta 24), reused 1 (delta 0)
Unpacking objects: 100% (44/44), done.
From git://github.com/paulboone/ticgit
* [new branch]
master
-> pb/master
* [new branch]
ticgit
-> pb/ticgit
La branche master de Paul est accessible localement en tant que pb/master vous pouvez
la fusionner dans une de vos propres branches, ou vous pouvez extraire une branche localement si
vous souhaitez linspecter.
Cee commande sadresse au dpt distant et rcupre toutes les donnes de ce projet que vous
ne possdez pas dj. Aprs cee action, vous possdez toutes les rfrences toutes les branches
contenues dans ce dpt, que vous pouvez fusionner ou inspecter tout moment (nous reviendrons
plus prcisment sur les branches et leur utilisation au chapitre 3).
35
Si vous clonez un dpt, le dpt distant est automatiquement ajout sous le nom origin. Donc,
git fetch origin rcupre tout ajout qui a t pouss vers ce dpt depuis que vous lavez
clon ou la dernire fois que vous avez rcupr les ajouts. Il faut noter que la commande fetch tire
les donnes dans votre dpt local mais sous sa propre branche elle ne les fusionne pas automatiquement avec aucun de vos travaux ni ne modie votre copie de travail. Vous devez volontairement
fusionner ses modications distantes dans votre travail lorsque vous le souhaitez.
Si vous avez cr une branche pour suivre lvolution dune branche distante (Cf. la section
suivante et le chapitre 3 pour plus dinformation), vous pouvez utiliser la commande git pull
qui rcupre et fusionne automatiquement une branche distante dans votre branche locale. Ce comportement peut correspondre une mthode de travail plus confortable, sachant que par dfaut la
commande git clone paramtre votre branche locale pour quelle suive la branche master du
dpt que vous avez clon (en supposant que le dpt distant ait une branche master). Lancer git
pull rcupre gnralement les donnes depuis le serveur qui a t initialement clon et essaie de
la fusionner dans votre branche de travail actuel.
Cee commande ne fonctionne que si vous avez clon depuis un serveur sur lequel vous avez
des droits daccs en criture et si personne na pouss dans lintervalle. Si vous et quelquun dautre
clonez un dpt au mme moment et que cee autre personne pousse ses modications et quaprs
vous tentez de pousser les vtres, votre pousse sera rejete juste titre. Vous devrez tout dabord
tirer les modications de lautre personne et les fusionner avec les vtres avant de pouvoir pousser.
Rfrez-vous au chapitre 3 pour de plus amples informations sur les techniques pour pousser vers
un serveur distant.
36
ticgit
Cela donne le liste des URL pour le dpt distant ainsi que la liste des branches distantes suivies.
Cee commande vous informe que si vous tes sur la branche master et si vous lancez git pull,
il va automatiquement fusionner la branche master du dpt distant aprs avoir rcupr toutes les
rfrences sur le serveur distant. Cela donne aussi la liste des autres rfrences quil aura tires.
Le rsultat ci-dessus est un exemple simple mais raliste de dpt distant. Lors dune utilisation
plus intense de Git, la commande git remote show fournira beaucoup dinformation :
Cee commande ache les branches pousses automatiquement lorsquon lance git push
dessus. Elle montre aussi les branches distantes qui nont pas encore t rapatries, les branches distantes prsentes localement mais eaces sur le serveur, et toutes les branches qui seront fusionnes
quand on lancera git pull.
37
Il faut mentionner que ceci modie aussi les noms de branches distantes. Celle qui tait rfrence
sous pb/master lest maintenant sous paul/master.
Si vous souhaitez retirer une rfrence pour certaines raisons vous avez chang de serveur
ou vous nutilisez plus ce serveur particulier, ou peut-tre un contributeur a cess de contribuer
vous pouvez utiliser git remote rm :
2.6 Balisage
linstar de la plupart des VCS, Git donne la possibilit de baliser un certain tat dans lhistorique
comme important. Gnralement, les gens utilisent cee fonctionnalit pour marquer les tats de
publication (v1.0 et ainsi de suite). Dans cee section, nous apprendrons comment lister les diffrentes balises, comment crer de nouvelles balises et les dirents types de balises.
$ git tag
v0.1
v1.3
Cee commande liste les balises dans lordre alphabtique. Lordre dans lequel elles apparaissent na aucun rapport avec lhistorique.
Vous pouvez aussi rechercher les balises correspondant un motif particulier. Par exemple, le
dpt des sources de Git contient plus de 240 balises. Si vous souhaitez ne visualiser que les srie
1.4.2, vous pouvez lancer ceci :
gnralement recommand de crer des balises annotes pour gnrer toute cee information mais
si la balise doit rester temporaire ou linformation supplmentaire nest pas dsire, il reste toujours
les balises lgres.
Loption -m permet de spcier le message de balisage qui sera stock avec la balise. Si vous
ne spciez pas de message en ligne pour une balise annote, Git lance votre diteur pour pouvoir
le saisir.
Vous pouvez visualiser les donnes de la balise ct du commit qui a t marqu en utilisant
la commande git show :
my version 1.4
commit 15027957951b64cf874c3557a0f3547bd83b3ff6
Merge: 4a447f7... a6b4c97...
Author: Scott Chacon <schacon@gee-mail.com>
Date:
39
En lanant git show sur cee balise, on peut visualiser la signature GPG aache :
Cee fois-ci, en lanant git show sur la balise, on ne voit plus aucune information complmentaire. La commande ne montre que linformation de commit :
40
gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A
gpg: Can't check signature: public key not found
error: could not verify the tag 'v1.4.2.1'
Maintenant, supposons que vous avez oubli de baliser le projet la version v1.2 qui correspondait au commit mise jour rakele . Vous pouvez toujours le faire aprs lvnement. Pour
baliser ce commit, vous spciez la somme de contrle du commit (ou une partie) en n de commande :
41
Le commit a t balis :
$ git tag
v0.1
v1.2
v1.3
v1.4
v1.4-lw
v1.5
$ git show v1.2
tag v1.2
Tagger: Scott Chacon <schacon@gee-mail.com>
Date:
version 1.2
commit 9fceb02d0ae598e95dc970b74767f19372d61af8
Author: Magnus Chacon <mchacon@gee-mail.com>
Date:
Si vous avez de nombreuses balises que vous souhaitez pousser en une fois, vous pouvez aussi
utiliser loption --tags avec la commande git push. Ceci transfrera toutes les nouvelles balises
vers le serveur distant.
42
* [new tag]
* [new tag]
* [new tag]
* [new tag]
A prsent, lorsquune autre personne clone ou tire depuis votre dpt, elle obtient aussi les
balises.
2.7.1 Auto-Compltion
Si vous utilisez le shell Bash, Git est livr avec un script dauto-compltion utile. Tlchargez
le code source de Git, et jetez un il dans le rpertoire contrib/completion. Il devrait y avoir
un chier nomm git-completion.bash. Copiez ce chier dans votre rpertoire personnel et
ajoutez cee ligne votre chier .bashrc :
source ~/.git-completion.bash
Si vous souhaitez paramtrer Bash pour activer la compltion automatique de Git pour tous les
utilisateur, copiez le script dans le rpertoire /opt/local/etc/bash_completion.d sur les
systmes Mac ou dans le rpertoire /etc/bash_completion.d sur les systmes Linux. Cest le
rpertoire dans lequel Bash lit pour fournir automatiquement la compltion en ligne de commande.
Si vous utilisez Windows avec le Bash Git, qui est install par dfaut avec Git en msysGit,
lauto-compltion est pr-congure.
Pressez la touche Tab lorsque vous crivez une commande Git, et le shell devrait vous indiquer
une liste de suggestions pour continuer la commande :
$ git co<tab><tab>
commit config
Dans ce cas, taper git co et appuyer sur la touche Tab deux fois suggre commit et cong.
Ajouter m<tab> complte git commit automatiquement.
43
Cela fonctionne aussi avec les options, ce qui est probablement plus utile. Par exemple, si vous
tapez la commande git log et ne vous souvenez plus dune des options, vous pouvez commencer
la taper, et appuyer sur la touche Tab pour voir ce qui peut correspondre :
--since=
--src-prefix=
--stat
--summary
Cest une astuce qui peut clairement vous viter de perdre du temps ou de lire de la documentation.
Ceci signie que, par exemple, au lieu de taper git commit, vous navez plus qu taper git
ci. Au fur et mesure de votre utilisation de git, vous utiliserez probablement dautres commandes
plus frquemment. Dans ce cas, nhsitez pas crer de nouveaux alias.
Cee technique peut aussi tre utile pour crer des commandes qui vous manquent. Par exemple, pour corriger le problme dergonomie que vous avez rencontr lors de la dsindexation dun
chier, vous pourriez crer un alias pour dsindexer :
Cela rend les choses plus claires. Il est aussi commun dajouter un alias last, de la manire
suivante :
44
$ git last
commit 66938dae3329c7aebe598c2246a8e6af90d04646
Author: Josh Goebel <dreamer3@example.com>
Date:
Pour explication, Git remplace simplement la nouvelle commande par tout ce que vous lui
aurez demand daliaser. Si par contre vous souhaitez lancer une commande externe plutt quune
sous-commande Git, vous pouvez commencer votre commande par un caractre !. Cest utile si
vous crivez vos propres outils pour travailler dans un dpt Git. On peut par exemple aliaser git
visual pour lancer gitk :
2.8 Rsum
A prsent, vous pouvez raliser toutes les oprations locales de base de Git crer et cloner un
dpt, faire des modications, les indexer et les valider, visualiser lhistorique de ces modications.
Au prochain chapitre, nous traiterons de la fonctionnalit unique de Git : son modle de branches.
45
Chapitre 3
47
Lorsque vous crez le commit en lanant la commande git commit, Git calcule la somme de
contrle de chaque rpertoire (ici, seulement pour le rpertoire racine) et stocke ces objets arbres
dans le dpt Git. Git cre alors un objet commit qui contient les mta-donnes et un pointeur vers
larbre projet dorigine de manire pouvoir recrer linstantan si besoin.
Votre dpt Git contient prsent cinq objets : un blob pour le contenu de chacun des trois
chiers, un arbre qui liste les contenus des rpertoires et spcie quels noms de chier sont aachs
quels blobs et un objet commit avec le pointeur vers larbre dorigine et toutes les mta-donnes
aaches au commit. Conceptuellement, les donnes contenues dans votre dpt git ressemblent
la Figure 3.1.
Si vous ralisez des modications et validez nouveau, le prochain commit stocke un pointeur vers le commit immdiatement prcdent. Aprs deux autres validations, lhistorique pourrait
ressembler la gure 3-2.
Une branche dans Git est tout simplement un pointeur mobile lger vers un de ces objets commit. La branche par dfaut dans Git sappelle master. Au fur et mesure des validations, la branche
master pointe vers le dernier des commits raliss. chaque validation, le pointeur de la branche
master avance automatiquement.
e se passe-t-il si vous crez une nouvelle branche ? Et bien, cela cre un nouveau pointeur dplacer. Supposons que vous crez une nouvelle branche nomme testing. Vous utilisez la
commande git branch :
48
Cela cre un nouveau pointeur vers le commit actuel (Cf. gure 3-4).
Figure 3.4: Branes multiples pointant dans lhistorique des donnes de commit.
Comment Git connat-il la branche sur laquelle vous vous trouvez ? Il conserve un pointeur
spcial appel HEAD. Remarquez que sous cee appellation se cache un concept trs dirent de
celui utilis dans les autres VCS tels que Subversion ou CVS. Dans Git, cest un pointeur sur la
branche locale o vous vous trouvez. Dans notre cas, vous vous trouvez toujours sur master. La
commande git branch na fait que crer une nouvelle branche elle na pas fait basculer la copie
de travail vers cee branche (Cf. gure 3-5).
Pour basculer vers une branche existante, il sut de lancer la commande git checkout.
Basculons vers la nouvelle branche testing :
49
Cela dplace HEAD pour le faire pointer vers la branche testing (voir gure 3-6)
Figure 3.6: HEAD pointe vers une autre brane quand on bascule de brane
$ vim test.rb
$ git commit -a -m 'petite modification'
Figure 3.7: La brane sur laquelle HEAD pointe avance avec aque nouveau commit.
Cest intressant parce qu prsent, votre branche testing a avanc, tandis que la branche
master pointe toujours sur le commit sur lequel vous tiez lorsque vous avez lanc git checkout
pour basculer de branche. Retournons sur la branche master :
Figure 3.8: HEAD se dplace sur une autre brane lors dun eout.
$ vim test.rb
$ git commit -a -m 'autres modifications'
Maintenant, lhistorique du projet a diverg (voir gure 3-9). Vous avez cr une branche et
bascul dessus, avez ralis des modications, puis avez rebascul sur la branche principale et ralis
dautres modications. Ces deux modications sont isoles dans des branches spares. Vous pouvez
basculer dune branche lautre et les fusionner quand vous tes prt. Vous avez fait tout ceci avec
de simples commandes branch et checkout.
Parce que dans Git, une branche nest en fait quun simple chier contenant les 40 caractres de
la somme de contrle SHA-1 du commit sur lequel elle pointe, les branches ne cotent rien crer
et dtruire. Crer une branche est aussi rapide qucrire un chier de 41 caractres (40 caractres
plus un retour chariot).
Cest une dirence de taille avec la manire dont la plupart des VCS grent les branches, qui
implique de copier tous les chiers du projet dans un second rpertoire. Cela peut durer plusieurs
secondes ou mme quelques minutes selon la taille du projet, alors que pour Git, le processus est
toujours instantan. De plus, comme nous enregistrons les parents quand nous validons les modications, la dtermination de lanctre commun pour la fusion est ralise automatiquement et
51
de manire trs facile. Ces fonctionnalits encouragent naturellement les dveloppeurs crer et
utiliser souvent des branches.
Voyons pourquoi vous devriez en faire autant.
Vous avez dcid de travailler sur le problme numrot #53 dans le suivi de faits techniques
que votre entreprise utilise. Pour clarier, Git nest pas li un gestionnaire particulier de faits
techniques. Mais comme le problme #53 est un problme cibl sur lequel vous voulez travailler,
vous allez crer une nouvelle branche ddie sa rsolution. Pour crer une branche et y basculer
tout de suite, vous pouvez lancer la commande git checkout avec loption -b :
52
Vous travaillez sur votre site web et validez des modications. Ce faisant, la branche prob53
avance, parce que vous lavez extraite (cest--dire que votre pointeur HEAD pointe dessus, voir
gure 3-12) :
$ vim index.html
$ git commit -a -m 'ajout d'un pied de page [problme 53]'
Maintenant vous recevez un appel qui vous apprend quil y a un problme sur le site web,
un problme quil faut rsoudre immdiatement. Avec Git, vous navez pas besoin de dployer les
modications dj valide pour prob53 avec les correctifs du problme et vous navez pas non
plus suer pour liminer ces modications avant de pouvoir appliquer les correctifs du problme
en production. Tout ce que vous avez faire, cest simplement rebasculer sur la branche master.
Cependant, avant de le faire, notez que si votre copie de travail ou votre zone de prparation
contient des modications non valides qui sont en conit avec la branche que vous extrayez, Git
ne vous laissera pas basculer de branche. Le mieux est davoir votre copie de travail dans un tat
propre au moment de basculer de branche. Il y a des moyens de contourner ceci (prcisment par la
planque et lamendement de commit) dont nous parlerons plus loin. Pour linstant, vous avez valid
tous vos changements dans la branche prob53 et vous pouvez donc rebasculer vers la branche
master :
53
prsent, votre rpertoire de copie de travail est exactement dans ltat prcdent les modications pour le problme #53 et vous pouvez vous consacrer votre correctif. Cest un point important :
Git rinitialise le rpertoire de travail pour quil ressemble linstantan de la validation sur laquelle
la branche que vous extrayez pointe. Il ajoute, retire et modie les chiers automatiquement pour
assurer que la copie de travail soit identique ce quelle tait lors de votre dernire validation sur
la branche.
Ensuite, vous avez un correctif faire. Crons une branche de correctif sur laquelle travailler
jusqu ce que ce soit termin (voir gure 3-13) :
Vous pouvez lancer vos tests, vous assurer que la correction est ecace et la fusionner dans la
branche master pour la dployer en production. Vous ralisez ceci au moyen de la commande git
merge :
1 -
Vous noterez la mention Fast forward qui signie avance rapide dans cee fusion. Comme
le commit point par la branche que vous avez fusionn tait directement descendant du commit
sur lequel vous vous trouvez, Git a avanc le pointeur en avant. Autrement dit, lorsque lon cherche
54
fusionner un commit qui peut tre joint en suivant lhistorique depuis le commit dorigine, Git
avance simplement le pointeur car il ny a pas de travaux divergeant rellement fusionner ceci
sappelle lavance rapide.
Votre modication est maintenant dans linstantan du commit point par la branche master
et vous pouvez dployer votre modication (voir gure 3-14)
Figure 3.14: Aprs la fusion, votre brane master pointe au mme endroit que la correction.
Aprs le dploiement de votre correction super-importante, vous voil de nouveau prt travailler sur votre sujet prcdent linterruption. Cependant, vous allez avant tout eacer la branche
correctif parce que vous nen avez plus besoin et la branche master pointe au mme endroit.
Vous pouvez leacer avec loption -d de la commande git branch :
Maintenant, il est temps de basculer sur la branche travaux en cours sur le problme #53 et
de continuer travailler dessus (voir gure 3-15) :
Il est utile de noter que le travail ralis dans correctif nest pas contenu dans les chiers
de la branche prob53. Si vous avez besoin de les y rapatrier, vous pouvez fusionner la branche
master dans la branche prob53 en lanant la commande git merge master, ou vous pouvez
retarder lintgration de ces modications jusqu ce que vous dcidiez plus tard de rapatrier la
branche prob53 dans master.
prob53 de la mme manire que vous lavez fait plus tt pour la branche correctif. Tout ce
que vous avez faire est dextraire la branche dans laquelle vous souhaitez fusionner et lancer la
commande git merge :
1 +
Figure 3.16: Git identie automatiquement la meilleure base danctre commun pour raliser la fusion.
Au lieu de simplement davancer le pointeur de branche, Git cre un nouvel instantan qui
rsulte de la fusion trois branches et cre automatiquement un nouveau commit qui pointe dessus
56
(voir gure 3-17). On appelle ceci un commit de fusion, qui est spcial en ce quil comporte plus dun
parent.
Il est noter que Git dtermine par lui-mme le meilleur anctre commun utiliser comme
base de fusion ; ce comportement est trs dirent de celui de CVS ou Subversion (antrieur la
version 1.5), o le dveloppeur en charge de la fusion doit trouver par lui-mme la meilleure base
de fusion. Cela rend la fusion tellement plus facile dans Git que dans les autres systmes.
Figure 3.17: Git cre automatiquement un nouvel objet commit qui contient le travail fusionn.
A prsent que votre travail a t fusionn, vous navez plus besoin de la branche prob53. Vous
pouvez leacer et fermer manuellement le ticket dans votre outil de suivi de faits techniques :
57
#
# unmerged:
index.html
Tout ce qui comporte des conits de fusion et na pas t rsolu est list comme unmerged.
Git ajoute des marques de conit standard dans les chiers qui comportent des conits, pour que
vous puissiez les ouvrir et rsoudre les conits manuellement. Votre chier contient des sections
qui ressemblent ceci :
<<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
please contact us at support@github.com
</div>
>>>>>>> prob53:index.html
Cela signie que la version dans HEAD (votre branche master, parce que cest celle que vous
aviez extraite quand vous avez lanc votre commande de fusion) est la partie suprieure de ce bloc
(tout ce qui se trouve au dessus de la ligne =======), tandis que la version de la branche prob53
se trouve en dessous. Pour rsoudre le conit, vous devez choisir une partie ou lautre ou bien
fusionner leurs contenus par vous-mme. Par exemple, vous pourriez choisir de rsoudre ce conit
en remplaant tout le bloc par ceci :
<div id="footer">
please contact us at email.support@github.com
</div>
Cee rsolution comporte des parties de chaque section et les lignes <<<<<<<, ======= et
>>>>>>> ont t compltement eaces. Aprs avoir rsolu chacune de ces sections dans chaque
chier comportant un conit, lancez git add sur chaque chier pour le marquer comme rsolu.
Prparer le chier en zone de prparation sut le marquer rsolu pour Git. Si vous souhaitez
utiliser un outil graphique pour rsoudre ces problmes, vous pouvez lancer git mergetool qui
dmarre loutil graphique de fusion appropri et vous permet de naviguer dans les conits :
$ git mergetool
merge tool candidates: kdiff3 tkdiff xxdiff meld gvimdiff opendiff emerge vimdiff
Merging the files: index.html
Normal merge conflict for 'index.html':
{local}: modified
{remote}: modified
Hit return to start merge resolution tool (opendiff):
58
Si vous souhaitez utiliser un outil de fusion autre que celui par dfaut (Git a choisi opendiff
pour moi dans ce cas car jutilise la commande sous Mac), vous pouvez voir tous les outils supports
aprs lindication merge tool candidates . Tapez le nom de loutil que vous prfreriez utiliser. Au
chapitre 7, nous expliquerons comment changer cee valeur par dfaut dans votre environnement.
Aprs avoir qui loutil de fusion, Git vous demande si la fusion a t russie. Si vous rpondez
par la positive loutil, il indexe le chier pour le marquer comme rsolu.
Vous pouvez lancer nouveau la commande git status pour vrier que tous les conits
ont t rsolus :
$ git status
# On branch master
# Changes to be committed:
#
#
# modified:
index.html
Cela vous convient et vous avez vri que tout ce qui comportait un conit a t index,
vous pouvez taper la commande git commit pour naliser le commit de fusion. Le message de
validation ressemble dhabitude ceci :
Vous pouvez modier ce message pour inclure les dtails sur la rsolution du conit si vous
pensez que cela peut tre utile lors dune revue ultrieure pourquoi vous avez fait ceci si ce nest
pas clair.
$ git branch
prob53
* master
testing
59
Notez le caractre * qui prxe la branche master. Ce caractre indique la branche qui a
t extraite. Ceci signie que si vous validez des modications, la branche master avancera avec
votre travail. Pour visualiser les dernires validations sur chaque branche, vous pouvez lancer le
commande git branch -v :
$ git branch -v
prob53
* master
Une autre option permeant de voir ltat des branches permet de ltrer cee liste par les
branches qui ont ou nont pas encore t fusionnes dans la branche courante. Les options -merged et --no-merge sont disponibles depuis la version 1.5.6 de Git. Pour voir quelles branches
ont dj t fusionnes dans votre branche actuelle, lancez git branch --merged :
Comme vous avez dj fusionn prob53 auparavant, vous la voyez dans votre liste. Les
branches de cee liste qui ne comportent pas ltoile en prxe peuvent gnralement tre eaces
sans risque au moyen de git branch -d ; vous avez dj incorpor leurs modications dans
une autre branche et nallez donc rien perdre.
Lancez git branch --no-merged pour visualiser les branches qui contiennent des
travaux qui nont pas encore t fusionns :
Ceci montre votre autre branche. Comme elle contient des modications qui nont pas encore
t fusionnes, un essai deacement par git branch -d se solde par un chec :
Si vous souhaitez rellement eacer cee branche et perdre ainsi le travail ralis, vous pouvez
forcer leacement avec loption -D, comme lindique justement le message.
60
Figure 3.18: Les branes les plus stables sont gnralement plus bas dans lhistorique des commits.
Vous pouvez reproduire ce schma sur plusieurs niveaux de stabilit. Des projets plus gros ont
aussi une branche proposed ou pu (proposed updates) qui permet dintgrer des branches qui ne
sont pas encore prtes pour la prochaine version ou pour master. Lide reste que les branches
voluent dirents niveaux de stabilit ; quand elles aeignent un niveau plus stable, elles peuvent
tre fusionnes dans la branche de stabilit suprieure. Une fois encore, les branches au long cours
61
ne sont pas ncessaires, mais savrent souvent utiles, spcialement dans le cadre de projets gros ou
complexes.
Maintenant, supposons que vous dcidiez que vous prfrez la seconde solution pour le problme (prob91v2) et que vous ayez montr la branche ideeidiote vos collgues qui vous ont
dit quelle tait gniale. Vous pouvez jeter la branche prob91 originale (en eaant les commits
C5 et C6) et fusionner les deux autres. Votre historique ressemble prsent la gure 3-21.
Souvenez-vous que lors de la ralisation de ces actions, toutes ces branches sont compltement
62
locales. Lorsque vous branchez et fusionnez, tout est ralis dans votre dpt Git. Aucune communication avec un serveur na lieu.
Figure 3.22: Un clonage Git vous fournit une brane master et une brane origin/master pointant sur la brane
master de lorigine.
Figure 3.23: Les travaux locaux et les modications pousses sur le serveur distant font diverger les deux historiques.
origin/master sa valeur nouvelle jour avec le serveur distant (voir gure 3-24).
Pour dmontrer lusage de multiples serveurs distants et le fonctionnement avec des branches
multiples, supposons que vous avez un autre serveur Git interne qui nest utilis pour le dveloppement que par une quipe. Ce serveur se trouve sur git.equipe1.notresociete.com. Vous
pouvez lajouter aux rfrences distantes de votre projet actuel en lanant la commande git remote add comme nous lavons dcrit au chapitre 2. Nommez ce serveur distant equipeun qui
sera le raccourci pour lURL complte (voir gure 3-25).
Maintenant, lancez git fetch equipeun pour rcuprer lensemble des informations du
serveur que vous ne possdez pas. Comme ce serveur contient dj un sous-ensemble des donnes
du serveur origin, Git ne rcupre aucune donne mais positionne une branche distante appele
equipeun/master qui pointe sur le commit que equipeun a comme branche master (voir
gure 3-26).
64
Figure 3.24: La commande git fet met jour vos rfrences distantes.
Figure 3.26: Vous rcuprez une rfrence locale la bran master de equipeun.
66
correctionserveur
-> origin/correctionserveur
Important : lorsque lon rcupre une nouvelle branche depuis un serveur distant, il ny a
pas de cration automatique dune copie locale ditable. En dautres termes, il ny a pas de branche
correctionserveur, seulement un pointeur sur la branche origin/correctionserveur
qui nest pas modiable.
Pour fusionner ce travail dans votre branche actuelle de travail, vous pouvez lancer git merge
origin/correctionserveur. Si vous souhaitez crer votre propre branche correctionserveur pour pouvoir y travailler, vous pouvez la baser sur le pointeur distant :
correctionserveur
set
up
to
track
remote
branch
refs/remotes/origin/
correctionserveur.
Switched to a new branch "correctionserveur"
Cee commande vous fournit une branche locale modiable base sur ltat actuel de origin/correctionserveur.
correctionserveur
set
up
to
track
remote
branch
refs/remotes/origin/
correctionserveur.
Switched to a new branch "serverfix"
Pour crer une branche locale avec un nom dirent de celui de la branche distante, vous
pouvez simplement utiliser la premire version avec un nom de branch locale dirent :
67
prsent, votre branche locale sf poussera vers et tirera automatiquement depuis origin/
correctionserveur.
correctionserveur
Boum ! Plus de branche sur le serveur. Vous souhaiterez srement corner cee page parce que
vous aurez besoin de cee commande et il y a de fortes chances que vous en oubliez la syntaxe. Un
moyen mnmotechnique est de lassocier la syntaxe de la commande git push [nomdistant] [branchelocale]:[branchedistante] que nous avons utilis prcdemment. Si
vous liminez la partie [branchelocale], cela signie ne rien prendre de mon ct et en faire
[branchedistante] .
3.6 Rebaser
Dans Git, il y a deux faons dintgrer les modications dune branche dans une autre : en
fusionnant merge et en rebasant rebase. Dans ce chapitre, vous apprendrez la signication de
rebaser, comment le faire, pourquoi cest un outil plutt bouriant et dans quels cas il est dconseill
de lutiliser.
Comme nous lavons dj expliqu, le moyen le plus simple pour intgrer ensemble ces branches
est la fusion via la commande merge. Cee commande ralise une fusion trois branches entre les
68
deux derniers instantans de chaque branche (C3 et C4) et lanctre commun le plus rcent (C2),
crant un nouvel instantan (et un commit), comme montr par la gure 3-28.
Figure 3.28: Fusion dune brane pour intgrer les historiques divergents.
Cependant, il existe un autre moyen : vous pouvez prendre le patch de la modication introduite en C3 et le rappliquer sur C4. Dans Git, cee action est appele rebaser. Avec la commande
rebase, vous prenez toutes les modications qui ont t valides sur une branche et vous les rejouez sur une autre.
Dans cet exemple, vous lanceriez les commandes suivantes :
Cela fonctionne en cherchant lanctre commun le plus rcent des deux branches (celle sur
laquelle vous vous trouvez et celle sur laquelle vous rebasez), en rcuprant toutes les dirences
introduites entre chaque validation de la branche sur laquelle vous tes, en les sauvant dans des
chiers temporaires, en basculant sur la branche destination et en rappliquant chaque modication
dans le mme ordre. La gure 3-29 illustre ce processus.
ce moment, vous pouvez retourner sur la branche master et raliser une fusion en avance
rapide (voir gure 3-30).
prsent, linstantan point par C3 est exactement le mme que celui point par C5 dans
lexemple de fusion. Il ny a pas de dirence entre les rsultats des deux types dintgration, mais
rebaser rend lhistorique plus clair. Si vous examinez le journal de la branche rebase, elle est devenue linaire : toutes les modications apparaissent en srie mme si elles ont eu lieu en parallle.
Vous aurez souvent rebaser pour vous assurer que les patchs que vous envoyez sappliquent
correctement sur une branche distante par exemple, sur un projet o vous souhaitez contribuer
69
mais que vous ne maintenez pas. Dans ce cas, vous raliseriez votre travail dans une branche puis
vous rebaseriez votre travail sur origin/master quand vous tes prt soumere vos patches
au projet principal. De cee manire, le mainteneur na pas raliser de travail dintgration juste
une avance rapide ou simplement une application propre.
Il faut noter que linstantan point par le commit nal, quil soit le dernier des commits dune
opration de rebase ou le commit nal issu dune fusion, sont en fait le mme instantan cest
juste que lhistorique est dirent. Rebaser rejoue les modications dune ligne de commits sur une
autre dans lordre dapparition, alors que la fusion joint et fusionne les deux ttes.
Figure 3.31: Un historique avec une brane qui sort dune autre brane de sujet.
Supposons que vous dcidez que vous souhaitez fusionner vos modications pour le ct client
dans votre ligne principale pour une publication mais vous souhaitez retenir les modications pour
la partie serveur jusqu ce quelles soient un peu plus testes. Vous pouvez rcuprer les modications pour le ct client qui ne sont pas sur le serveur (C8 et C9) et les rejouer sur la branche master
70
Cela signie en essence Extrait la branche client, dtermine les patchs depuis lanctre commun des branches client et server puis rejoue les sur master . Cest assez complexe, mais
le rsultat visible sur la gure 3-32 est assez impressionnant.
Figure 3.32: Rebaser une brane de sujet sur une autre brane.
Maintenant, vous pouvez faire une avance rapide sur votre branche master (voir gure 3-33) :
Figure 3.33: Avance rapide sur votre brane master pour inclure les modications de la brane client.
Supposons que vous dcidiez de tirer de votre branche server aussi. Vous pouvez rebaser la
branche server sur la branche master sans avoir lextraire avant en utilisant git rebase
[branchedebase] [branchedesujet] qui extrait la branche de sujet (dans notre cas,
server) pour vous et la rejoue sur la branche de base (master) :
71
Cee commande rejoue les modications de server sur le sommet de la branche master,
comme indiqu dans la gure 3-34.
Ensuite, vous pouvez faire une avance rapide sur la branche de base (master) :
Vous pouvez eacer les branches client et server une fois que tout le travail est intgr
et que vous nen avez plus besoin, liminant tout lhistorique de ce processus, comme visible sur la
gure 3-35 :
A prsent, une autre personne travaille et inclut une fusion, puis elle pousse ce travail sur le
serveur central. Vous le rcuprez et vous fusionnez le nouvelle branche distante dans votre copie,
ce qui donne lhistorique de la gure 3-37.
Ensuite, la personne qui a pouss le travail que vous venez de fusionner dcide de faire marche
arrire et de rebaser son travail. Elle lance un git push --force pour forcer lcrasement
de lhistorique sur le serveur. Vous rcuprez alors les donnes du serveur, qui vous amnent les
nouveaux commits.
A ce moment, vous devez fusionner son travail une nouvelle fois, mme si vous lavez dj fait.
Rebaser change les empreintes SHA-1 de ces commits, ce qui les rend nouveaux aux yeux de Git,
alors quen fait, vous avez dj le travail de C4 dans votre historique (voir gure 3-39).
Vous devez fusionner ce travail pour pouvoir continuer suivre ce dveloppeur dans le futur.
Aprs fusion, votre historique contient la fois les commits C4 et C4, qui ont des empreintes SHA-1
direntes mais introduisent les mme modications et ont les mmes messages de validation. Si
vous lancez git log lorsque votre historique ressemble ceci, vous verrez deux commits qui ont
la mme date dauteur et les mmes messages, ce qui est droutant. De plus, si vous poussez cet
historique sur le serveur, vous rintroduirez tous ces commits rebass sur le serveur central, ce qui
73
Figure 3.38: elquun pousse des commits rebass, en abandonnant les commits sur lesquels vous avez fond
votre travail.
Figure 3.39: Vous fusionnez le mme travail une nouvelle fois dans un nouveau commit de fusion.
3.7 Rsum
Nous avons trait les bases des branches et de fusions dans Git. Vous devriez tre laise pour
le cration et le basculement sur de nouvelles branches, le basculement entre branches et la fusion
de branches locales. Vous devriez aussi tre capable de partager vos branches en les poussant sur
une serveur partag, travailler avec dautres personnes sur des branches partages et rebaser vos
branches avant de les partager.
74
Chapitre 4
4.1 Protocoles
Git peut utiliser quatre protocoles rseau majeurs pour transporter des donnes : local, Secure
Shell (SSH), Git et HTTP. Nous allons voir leur nature et dans quelles circonstances ils peuvent (ou
ne peuvent pas) tre utiliss.
Il est noter que mis part HTTP, tous le protocoles ncessitent linstallation de Git sur le
serveur.
75
Ou bien cela :
Ensuite, vous pouvez pousser vers et tirer depuis ce dpt distant de la mme manire que vous
le feriez pour un dpt accessible sur le rseau.
Avantages
Les avantages des dpts accessibles sur le systme de chier sont quils sont simples et quils
utilisent les permissions du systme de chier. Si vous avez dj un montage partag auquel toute
votre quipe a accs, dployer un dpt est extrmement facile. Vous placez la copie du dpt nu
un endroit accessible de tous et positionnez correctement les droits de lecture/criture de la mme
manire que pour tout autre partage. Nous aborderons la mthode pour exporter une copie de dpt
nu cee n dans la section suivante Dployer Git sur un serveur .
Cest un choix satisfaisant pour partager rapidement le travail. Si vous et votre coquipier
travaillez sur le mme projet et quil souhaite partager son travail, lancer une commande telle que
76
git pull /home/john/project est certainement plus simple que de passer par un serveur
intermdiaire.
Inconvnients
Les inconvnients de cee mthode sont quil est gnralement plus dicile de rendre disponible
un partage rseau depuis de nombreux endroits que de simplement grer des accs rseau. Si vous
souhaitez pousser depuis votre portable la maison, vous devez monter le partage distant, ce qui
peut savrer plus dicile et lent que daccder directement par un protocole rseau.
Il est aussi mentionner que ce nest pas ncessairement loption la plus rapide lutilisation
si un partage rseau est utilis. Un dpt local nest rapide que si laccs aux chiers est rapide. Un
dpt accessible sur un montage NFS est souvent plus lent quun dpt accessible via SSH sur le
mme serveur qui ferait tourner Git avec un accs au disques locaux.
ou ne spciez pas de protocole du tout Git choisit SSH par dfaut si vous ntes pas explicite :
Vous pouvez aussi ne pas spcier de nom dutilisateur et Git utilisera par dfaut le nom de
login.
Avantages
Les avantages lis lutilisation de SSH sont nombreux. Primo, vous ne pourrez pas faire
autrement si vous souhaitez grer un accs authenti en criture votre dpt au travers le rseau.
Secundo, SSH est relativement simple mere en place, les daemons SSH sont facilement disponibles,
les administrateurs rseaux sont habitus les grer et de nombreuses distributions de systmes
dexploitation en disposent et proposent des outils de gestion. Ensuite, laccs distant travers SSH
est scuris, toutes les donnes sont chires et authenties. Enn, comme les protocoles Git et
local, SSH est ecace et permet de comprimer autant que possible les donnes avant de les transfrer.
77
Inconvnients
Le point ngatif avec SSH est quil est impossible de proposer un accs anonyme au dpt. Les
accs sont rgis par les permission SSH, mme pour un accs en lecture seule, ce qui soppose une
optique open-source. Si vous souhaitez utiliser Git dans un environnement dentreprise, SSH peut
bien tre le seul protocole ncessaire. Si vous souhaitez proposer de laccs anonyme en lecture seule
vos projets, vous aurez besoin de SSH pour vous permere de pousser mais un autre protocole
sera ncessaire pour permere dautres de tirer.
$ cd /var/www/htdocs/
$ git clone --bare /chemin/vers/git_projet projetgit.git
$ cd projetgit.git
$ mv hooks/post-update.sample hooks/post-update
$ chmod a+x hooks/post-update
Cest tout. Le crochet post-update qui est livr avec Git par dfaut lance la commande
approprie (git update-server-info) pour permere un fonctionnement correct du clonage
et de la rcupration par HTTP. Cee commande est lance lorsque vous poussez vers ce dpt par
SSH ; ainsi, les autres personnes peuvent cloner via la commande
Dans ce cas particulier, nous utilisons le chemin /var/www/htdocs qui est commun pour les
installations dApache, mais vous pouvez utiliser nimporte quel serveur web de pages statiques il
sut de placer le dpt nu dans le chemin daccs. Les donnes Git sont servies comme des simples
chiers statiques (voir chapitre 9 pour la manire dtaille dont ils sont servis).
Il est possible de faire pousser Git travers HTTP, bien que cee technique ne soit pas utilise et
ncessite de grer les exigences complexes de WebDAV. Comme elle est rarement utilise, nous ne la
dtaillerons pas dans ce livre. Si vous tes tout de mme intress par lutilisation des protocoles de
push-HTTP, vous pouvez vous rfrer http://www.kernel.org/pub/software/scm/
git/docs/howto/setup-git-server-over-http.txt. Un des intrts permere de
pousser par HTTP est que vous pouvez utiliser sur nimporte quel serveur WebDAV, sans liaison
avec Git. Il est donc possible dutiliser cee fonctionnalit si votre fournisseur dhbergement web
supporte WebDAV pour la mise jour de vos sites.
Avantages
Lavantage dutiliser le protocole HTTP est quil est trs simple mere en uvre. Donner
un accs public en lecture votre dpt Git ne ncessite que quelques commandes. Cela ne prend
que quelques minutes. De plus, le protocole HTTP nest pas trs demandeur en ressources systme.
Les besoins tant limits servir des donnes statiques, un serveur Apache standard peut servir des
milliers de chiers par seconde en moyenne et il est trs dicile de surcharger mme un ordinateur
moyen.
Vous pouvez aussi publier votre dpt par HTTPS, ce qui signie que vous pouvez chirer le
contenu transfr. Vous pouvez mme obliger les clients utiliser des certicats SSL spciques.
Gnralement, si vous souhaitez pousser jusque l, il est prfrable de passer par des cls SSH
publiques. Cependant, certains cas ncessitent lutilisation de certicats SSL signs ou dautres
mthodes dauthentication bases sur HTTP pour les accs en lecture seule sur HTTPS.
Un autre avantage indniable de HTTP est que cest un protocole si commun que les pare-feux
dentreprise sont souvent paramtrs pour le laisser passer.
79
Inconvnients
Linconvnient majeur de servir votre dpt sur HTTP est que cest relativement inecace
pour le client. Cela prend gnralement beaucoup plus longtemps de cloner ou tirer depuis le dpt
et il en rsulte un plus grand trac rseau et de plus gros volumes de transfert que pour les autres
protocoles. Le protocole HTTP est souvent appel le protocole idiot parce quil na pas lintelligence
de slectionner seulement les donnes ncessaires transfrer du fait du manque de traitement
dynamique ct serveur. Pour plus dinformation sur les dirences decacit entre le protocole
HTTP et les autres, rfrez-vous au chapitre 9.
La sortie de cee commande est un peu droutante. Comme clone est un git init de
base, suivi dun git fetch, nous voyons les messages du git init qui cre un rpertoire
vide. Le transfert eectif dobjet ne fournit aucune sortie, mais il a tout de mme lieu. Vous devriez
maintenant avoir une copie des donnes de Git dans votre rpertoire mon_project.git.
Cest grossirement quivalent
Il y a quelques lgres dirences dans le chier de conguration mais pour lutilisation envisage, cest trs proche. La commande extrait le rpertoire Git sans rpertoire de travail et cre
un rpertoire spcique pour laccueillir.
80
A partir de maintenant, tous les autres utilisateurs disposant dun accs SSH au serveur et
ayant un accs en lecture seule au rpertoire /opt/git peuvent cloner votre dpt en lanant la
commande
$ ssh utilisateur@git.exemple.com
$ cd /opt/git/mon_projet.git
$ git init --bare --shared
Vous voyez comme il est simple de prendre un dpt Git, crer une version nue et la placer sur
un serveur auquel vous et vos collaborateurs avez accs en SSH. Vous voil prts collaborer sur le
mme projet.
Il faut noter que cest liralement tout ce dont vous avez besoin pour dmarrer un serveur
Git utile auquel plusieurs personnes ont accs ajoutez des comptes SSH sur un serveur, et collez
un dpt nu quelque part o tous les utilisateurs ont accs en lecture et criture. Vous tes prts
travailler, vous navez besoin de rien dautre.
Dans les chapitres venir, nous traiterons de mises en place plus sophistiques. Ces sujets incluront llimination du besoin de crer un compte systme pour chaque utilisateur, laccs public
aux dpts, la mise en place dinterfaces utilisateurs web, lutilisation de loutil Gitosis, etc. Nanmoins, gardez lesprit que pour collaborer avec quelques personnes sur un projet priv, tout ce
quil faut, cest un serveur SSH et un dpt nu.
un accs SSH pour eux. En supposant que pour vos dpts, vous disposiez dj dun serveur SSH
install et sur lequel vous avez accs.
Il y a quelques moyens de donner un accs tout le monde dans lquipe. Le premier est de crer
des comptes pour tout le monde, ce qui est logique mais peut savrer lourd. Vous ne souhaiteriez
srement pas lancer adduser et entrer un mot de passe temporaire pour chaque utilisateur.
Une seconde mthode consiste crer un seul utilisateur git sur la machine, demander chaque
dveloppeur ncessitant un accs en criture de vous envoyer une clef publique SSH et dajouter
la dite clef au chier ~/.ssh/authorized_keys de votre utilisateur git. partir de l, tout le
monde sera capable daccder la machine via lutilisateur git. Cela naecte en rien les donnes de
commit les informations de lutilisateur SSH par lequel on se connecte naectent pas les donnes
de commit enregistres.
Une dernire mthode consiste faire une authentication SSH auprs dun serveur LDAP ou
tout autre systme dauthentication centralis que vous utiliseriez dj. Tant que chaque utilisateur peut accder un shell sur la machine, nimporte quel schma dauthentication SSH devrait
fonctionner.
$ cd ~/.ssh
$ ls
authorized_keys2
id_dsa
config
id_dsa.pub
known_hosts
Recherchez une paire de chiers appels quelqueose et quelqueose.pub o le quelquechose en question est gnralement id_dsa ou id_rsa. Le chier en .pub est la clef publique
tandis que lautre est la clef prive. Si vous ne voyez pas ces chiers (ou navez mme pas de rpertoire .ssh), vous pouvez les crer en lanant un programme appel ssh-keygen fourni par le
paquet SSH sur les systmes Linux/Mac et MSysGit pour Windows :
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/schacon/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/schacon/.ssh/id_rsa.
Your public key has been saved in /Users/schacon/.ssh/id_rsa.pub.
The key fingerprint is:
43:c5:5b:5f:b1:f1:50:43:ad:20:a6:92:6a:1f:9a:3a schacon@agadorlaptop.local
82
Premirement, le programme demande conrmation pour lendroit o vous souhaitez sauvegarder la clef (.ssh/id_rsa) puis il demande deux fois dentrer un mot de passe qui peut tre
laiss vide si vous ne souhaitez pas devoir taper un mot de passe quand vous utilisez la clef.
Maintenant, chaque utilisateur ayant suivi ces indications doit envoyer la clef publique la personne en charge de ladministration du serveur Git (en supposant que vous utilisez un serveur SSH
rgl pour lutilisation de clefs publiques). Ils doivent copier le contenu du chier .pub et lenvoyer
par e-mail. Les clefs publiques ressemblent ceci :
$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU
GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3
Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA
t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En
mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx
NrRFi9wrf+M7Q== schacon@agadorlaptop.local
Pour un tutoriel plus approfondi sur la cration de clef SSH sur dirents systmes dexploitation,
rfrez-vous au guide GitHub sur les clefs SSH http://github.com/guides/providing-your-ssh-key.
Ensuite, vous devez ajouter la clef publique dun dveloppeur au chier authorized_keys
de lutilisateur git. Supposons que vous avez reu quelques clefs par e-mail et les avez sauves dans
des chiers temporaires. Pour rappel, une clef publique ressemble ceci :
$ cat /tmp/id_rsa.john.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCB007n/ww+ouN4gSLKssMxXnBOvf9LGt4L
ojG6rs6hPB09j9R/T17/x4lhJA0F3FR1rP6kYBRsWj2aThGw6HXLm9/5zytK6Ztg3RPKK+4k
Yjh6541NYsnEAZuXz0jTTyAUfrtU3Z5E003C4oxOj6H0rfIF1kKI9MAQLMdpGW1GYEIgS9Ez
Sdfd8AcCIicTDWbqLAcU4UpkaX8KyGlLwsNuuGztobF8m72ALC/nLF6JLtPofwFBlgc+myiv
O7TCUSBdLQlgMVOFq1I2uPWQOkOWQAHukEOmfjy2jctxSDBQ220ymjaNsHT4kgtZg2AYYgPq
dAv8JggJICUvax2T9va5 gsg-keypair
Maintenant, vous pouvez crer un dpt vide nu en lanant la commande git init avec
loption --bare, ce qui initialise un dpt sans rpertoire de travail :
$ cd /opt/git
$ mkdir projet.git
$ cd projet.git
$ git --bare init
Alors, John, Josie ou Jessica peuvent pousser la premire version de leur projet vers ce dpt
en lajoutant en tant que dpt distant et en lui poussant une branche. Notons que quelquun doit
se connecter au serveur et crer un dpt nu pour chaque ajout de projet. Supposons que le nom
du serveur soit gitserveur. Si vous lhbergez en interne et avez rgl le DNS pour faire pointer
gitserver sur ce serveur, alors vous pouvez utiliser les commandes suivantes telle quelle :
prsent, les autres utilisateurs peuvent cloner le dpt et y pousser leurs modications aussi
simplement :
De cee manire, vous pouvez rapidement mere en place un serveur Git en lecture/criture
pour une poigne de dveloppeurs.
En prcaution supplmentaire, vous pouvez simplement restreindre lutilisateur git des actions Git avec un shell limit appel git-shell qui est fourni avec Git. Si vous positionnez ce
shell comme shell de login de lutilisateur git, lutilisateur git ne peut pas avoir de shell normal sur
ce serveur. Pour utiliser cee fonction, spciez git-shell en lieu et place de bash ou csh pour
shell de lutilisateur. Cela se ralise gnralement en ditant le chier /etc/passwd :
84
Tout au bas, vous devriez trouver une ligne qui ressemble ceci :
git:x:1000:1000::/home/git:/bin/sh
Modiez /bin/sh en /usr/bin/git-shell (ou le rsultat de la commande which gitshell qui indique o il est install). La ligne devrait maintenant ressembler ceci :
git:x:1000:1000::/home/git:/usr/bin/git-shell
prsent, lutilisateur git ne peut plus utiliser la connexion SSH que pour pousser et tirer sur
des dpts Git, il ne peut plus ouvrir un shell. Si vous essayez, vous verrez un rejet de login :
$ ssh git@gitserveur
fatal: What do you think I am? A shell?
Connection to gitserveur closed.
$ cd projet.git
$ mv hooks/post-update.sample hooks/post-update
$ chmod a+x hooks/post-update
Si vous utilisez une version de Git antrieure 1.6, la commande mv nest pas ncessaire car
Git na commenc utiliser le nommage des exemples de crochet en utilisant le postxe .sample
que rcemment.
elle est laction de ce crochet post-update ? Il contient simplement ceci :
85
$ cat .git/hooks/post-update
#!/bin/sh
exec git-update-server-info
Cela signie que lorsque vous poussez vers le serveur via SSH, Git lance cee commande pour
mere jour les chiers ncessaires lorsquon tire par HTTP.
Ensuite, il faut ajouter dans la conguration Apache une entre VirtualHost dont la racine
pointe sur vos dpts Git. Ici, nous supposerons que vous avez rgl un DNS avec rsolution gnrique
qui renvoit *.gitserveur vers la machine qui hberge ce systme :
<VirtualHost *:80>
ServerName git.gitserveur
DocumentRoot /opt/git
<Directory /opt/git/>
Order allow, deny
allow from all
</Directory>
</VirtualHost>
Vous devrez aussi positionner le groupe dutilisateur Unix du rpertoire /opt/git wwwdata de manire ce que le serveur web puisse avoir accs en lecture seule aux rpertoires si le
serveur Apache lance le script CGI avec cet utilisateur (par dfaut) :
Aprs avoir redmarr Apache, vous devriez tre capable de cloner vos dpts en spciant
lURL de votre projet :
Ainsi, vous pouvez donner accs en lecture seule tous vos projets un grand nombre dutilisateurs
en quelques minutes. Une autre option simple pour fournir un accs public non-authenti consiste
lancer un daemon Git, bien que cela requiert de daemoniser le processus nous traiterons cee
option dans un chapitre ultrieur si vous prfrez cee option.
4.6 GitWeb
Aprs avoir rgl les accs de base en lecture/criture et en lecture seule pour vos projets, vous
souhaiterez peut-tre mere en place une interface web simple de visualisation. Git fournit un script
CGI appel GitWeb qui est souvent utilis cee n. Vous pouvez voir GitWeb en action sur des
sites tels que http://git.kernel.org (voir gure 4-1).
86
Si vous souhaitez vrier quoi GitWeb ressemblerait pour votre projet, Git fournit une commande pour dmarrer une instance temporaire de serveur si vous avez un serveur lger tel que
lighttpd ou webrick sur votre systme. Sur les machines Linux, lighttpd est souvent prinstall et vous devriez pouvoir le dmarrer en tapant git instaweb dans votre rpertoire de
travail. Si vous utilisez un Mac, Ruby est install de base avec Lopard, donc webrick est une
meilleure option. Pour dmarrer instaweb avec un gestionnaire autre que lighpd, vous pouvez
le lancer avec loption --httpd.
WEBrick 1.3.1
Cee commande dmarre un serveur HTTP sur le port 1234 et lance automatique un navigateur
internet qui ouvre la page daccueil. Cest vraiment trs simple. Pour arrter le serveur, il sut de
lancer la mme commande, mais avec loption --stop :
Si vous souhaitez fournir linterface web en permanence sur le serveur pour votre quipe ou
pour un projet opensource que vous hbergez, il sera ncessaire dinstaller le script CGI pour quil
soit appel par votre serveur web. elques distributions Linux ont un package gitweb quil sufra dinstaller via apt ou yum, ce qui est une possibilit. Nous dtaillerons tout de mme rapidement linstallation manuelle de GitWeb. Premirement, le code source de Git qui fournit GitWeb est
ncessaire pour pouvoir gnrer un script CGI personnalis :
87
Notez que vous devez indiquer o trouver les dpts Git au moyen de la variable GITWEB_PROJECTROOT.
Maintenant, il faut paramtrer dans Apache lutilisation de CGI pour ce script, en spciant un nouveau VirtualHost :
<VirtualHost *:80>
ServerName gitserveur
DocumentRoot /var/www/gitweb
<Directory /var/www/gitweb>
Options ExecCGI +FollowSymLinks +SymLinksIfOwnerMatch
AllowOverride All
order allow,deny
Allow from all
AddHandler cgi-script cgi
DirectoryIndex gitweb.cgi
</Directory>
</VirtualHost>
Une fois de plus, GitWeb peut tre gr par tout serveur Web capable de prendre en charge
CGI. La mise en place ne devrait pas tre plus dicile avec un autre serveur. Aprs redmarrage du
serveur, vous devriez tre capable de visiter http://gitserveur/ pour visualiser vos dpts
en ligne et de cloner et tirer depuis ces dpts par HTTP sur http://git.gitserveur.
4.7 Gitosis
Conserver les clefs publiques de tous les utilisateurs dans le chier authorized_keys nest
satisfaisant quun temps. Avec des centaines dutilisateurs, la gestion devient complique. chaque
fois, il faut se connecter au serveur et il ny a aucun contrle daccs toute personne avec une clef
dans le chier a accs en lecture et criture tous les projets.
Il est temps de se tourner vers un logiciel largement utilis appel Gitosis. Gitosis est une
collection de scripts qui aident grer le chier authorized_keys ainsi qu implmenter des
contrles daccs simples. La partie la plus intressante de loutil est que linterface dadministration
permeant dajouter des utilisateurs et de dterminer leurs droits nest pas une interface web mais
un dpt Git spcial. Vous paramtrez les informations dans ce projet et lorsque vous le poussez,
Gitosis recongure les serveurs en fonction des donnes, ce qui est cool.
Linstallation de Gitosis nest pas des plus aises. Elle est plus simple sur un serveur Linux
les exemples qui suivent utilisent une distribution Ubuntu Server 8.10 de base.
Gitosis ncessite des outils Python. Il faut donc installer le paquet Python setuptools quUbuntu
fournit en tant que python-setuptools :
88
La dernire commande installe deux excutables que Gitosis utilisera. Ensuite, Gitosis veut
grer ses dpts sous /home/git, ce qui est parfait. Mais vous avez dj install vos dpts sous
/opt/git, donc au lieu de tout recongurer, crez un lien symbolique :
$ ln -s /opt/git /home/git/repositories
Comme Gitosis grera vos clefs pour vous, il faut eacer le chier authorized_keys, rajouter les clefs plus tard et laisser Gitosis contrler le chier automatiquement. Pour linstant,
dplacez le chier authorized_keys ailleurs :
$ mv /home/git/.ssh/authorized_keys /home/git/.ssh/ak.bak
Ensuite, il faut ractiver le shell pour lutilisateur git si vous lavez dsactiv au moyen
de git-shell. Les utilisateurs ne pourront toujours pas se connecter car Gitosis contrlera cet
accs. Modions la ligne dans le chier /etc/passwd
git:x:1000:1000::/home/git:/usr/bin/git-shell
git:x:1000:1000::/home/git:/bin/sh
Cela permet lutilisateur disposant de cee clef de modier le dpt Git qui contrle le
paramtrage de Gitosis. Ensuite, il faudra positionner manuellement le bit execute du script
post-update du dpt de contrle nouvellement cr.
89
Vous voil prt. Si tout est rgl correctement, vous pouvez essayer de vous connecter par SSH
au serveur en tant que lutilisateur pour lequel vous avez ajout la clef publique lors de linitialisation
de Gitosis.. Vous devriez voir quelque chose comme :
$ ssh git@gitserveur
PTY allocation request failed on channel 0
fatal: unrecognized command 'gitosis-serve schacon@quaternion'
Connection to gitserveur closed.
Cela signie que Gitosis vous a bien reconnu mais vous a rejet car vous ne lancez pas de
commandes Git. Lanons donc une vraie commande Git en clonant le dpt de contrle Gitosis :
$ cd gitosis-admin
$ find .
./gitosis.conf
./keydir
./keydir/scott.pub
Le chier gitosis.conf est le chier de conguration qui permet de spcier les utilisateurs, les dpts et les permissions. Le rpertoire keydir stocke les clefs publiques de tous les
utilisateurs qui peuvent avoir un accs vos dpts un chier par utilisateur. Le nom du chier
dans keydir (dans lexemple prcdent, scott.pub) sera dirent pour vous Gitosis utilise
le nom issu de la description la n de la clef publique qui a t importe par le script gitosisinit.
Le chier gitosis.conf contient la conguration du projet gitosis-admin clon
linstant :
$ cat gitosis.conf
[gitosis]
[group gitosis-admin]
writable = gitosis-admin
members = scott
Il indique que lutilisateur sco lutilisateur dont la clef publique a servi initialiser
Gitosis est le seul avoir accs au projet gitosis-admin.
A prsent, ajoutons un nouveau projet. Ajoutons une nouvelle section appele mobile o
vous listez les dveloppeurs de votre quipe mobile et les projets auxquels ces dveloppeurs ont
90
accs. Comme sco est le seul utilisateur dclar pour linstant, vous devrez lajouter comme
membre unique et vous crerez un nouveau projet appel iphone_projet pour commencer :
[group mobile]
writable = iphone_projet
members = scott
chaque modication du projet gitosis-admin, il est ncessaire de valider les changements et de les pousser sur le serveur pour quils prennent eet :
Vous pouvez pousser vers le nouveau iphone_projet en ajoutant votre serveur comme
dpt distant dans votre dpt local de projet et en poussant. Vous navez plus besoin de crer
manuellement un dpt nu sur le serveur pour les nouveaux projets. Gitosis les cre automatiquement ds quil voit la premire pousse :
Notez quil est inutile de spcier le chemin distant (en fait, cest interdit), juste deux points et
le nom du projet. Gitosis gre les chemins.
Souhaitant travailler sur ce projet avec vos amis, vous devrez rajouter leurs clefs publics. Plutt
que de les accoler manuellement au chier ~/.ssh/authorized_keys de votre serveur, il faut
les ajouter, une clef par chier dans le rpertoire keydir. Le nom de chier dtermine les noms de
utilisateurs dans le chier gitosis.conf. Rajoutons les clefs publiques de John, Josie et Jessica :
$ cp /tmp/id_rsa.john.pub keydir/john.pub
$ cp /tmp/id_rsa.josie.pub keydir/josie.pub
$ cp /tmp/id_rsa.jessica.pub keydir/jessica.pub
91
Vous pouvez maintenant les ajouter tous votre quipe mobile pour quils aient accs en
lecture/criture iphone_projet :
[group mobile]
writable = iphone_project
members = scott john josie jessica
Aprs validation et pousse vers le serveur, les quatre utilisateurs sont admis lire et crire sur
ce projet.
Gitosis fournit aussi des permissions simples. Si vous souhaitez que John nait quun accs en
lecture ce projet, vous pouvez congurer ceci plutt :
[group mobile]
writable = iphone_projet
members = scott josie jessica
[group mobile_ro]
readonly = iphone_projet
members = john
A prsent, John peut cloner le projet et rcuprer les mises jour, mais Gitosis lui refusera
de pousser sur ce projet. Vous pouvez crer autant que groupes que vous dsirez contenant des
utilisateurs et projets dirents. Vous pouvez aussi spcier un autre groupe comme membre du
groupe (avec le prxe @) pour faire hriter ses membres automatiquement :
[group mobile_committers]
members = scott josie jessica
[group mobile]
writable
= iphone_projet
members
= @mobile_committers
[group mobile_2]
writable
= autre_iphone_projet
members
= @mobile_committers john
Si vous rencontrez des problmes, il peut tre utile dajouter loglevel=DEBUG sous la section [gitosis]. Si vous avez perdu le droit de pousser en envoyant une conguration vrole,
vous pouvez toujours rparer le chier /home/git/.gitosis.conf sur le serveur le chier
dans lequel Gitosis lit sa conguration. Pousser sur le projet gitosis-admin provoque la recopie
du chier gitosis.conf cet endroit. Si vous ditez ce chier la main, il restera dans cet tat
jusqu la prochaine pousse.
92
--reuseaddr autorise le serveur redmarrer sans devoir aendre que les anciennes connexions expirent, loption --base-path autorise les gens cloner des projets sans devoir spcier le chemin complet, et le chemin en n de ligne indique au daemon Git lendroit o chercher
des dpts exporter. Si vous utilisez un pare-feu, il sera ncessaire de rediriger le port 9418 sur la
machine hbergeant le serveur.
Transformer ce processus en daemon se ralise par direntes manires qui dpendent du systme dexploitation sur lequel il est lanc. Sur une machine Ubuntu, cest un script Upstart. Donc
dans le chier
/etc/event.d/local-git-daemon
le script suivant :
start on startup
stop on shutdown
exec /usr/bin/git daemon \
--user=git --group=git \
--reuseaddr \
--base-path=/opt/git/ \
/opt/git/
respawn
Par scurit, ce daemon devrait tre lanc par un utilisateur nayant que des droits de lecture
seule sur les dpts simplement en crant un nouvel utilisateur git-ro qui servira lancer le
daemon. Par simplicit, nous le lancerons avec le mme utilisateur git qui est utilis par Gitosis.
Au rdmarrage de la machine, votre daemon Git dmarrera automatiquement et redmarrera
sil meurt. Pour le lancer sans avoir redmarrer, vous pouvez lancer ceci :
93
Sur dautres systmes, le choix reste large, allant de xinetd un script de systme sysvinit
ou tout autre moyen tant que le programme est daemonis et surveill.
Ensuite, il faut spcier votre serveur Gitosis les dpts autoriser en accs Git. Si vous
ajoutez une section pour chaque dpt, vous pouvez indiquer ceux que vous souhaitez servir en
lecture via votre daemon Git. Par exemple, si vous souhaitez un accs par protocole Git votre
projet iphone, ajoutez ceci la n du chier gitosis.conf :
[repo iphone_projet]
daemon = yes
Une fois cee conguration valide et pousse, votre daemon devrait commencer servir des
requtes pour ce projet tout personne ayant accs au port 9518 de votre serveur.
Si vous dcidez de ne pas utiliser Gitosis, mais dutiliser un daemon Git, il faudra lancer les
commandes suivantes sur chaque projet que vous souhaitez faire servir par le daemon Git :
$ cd /chemin/au/projet.git
$ touch git-daemon-export-ok
La prsence de ce chier indique Git que ce projet peut tre servi sans authentication.
Gitosis peut aussi contrler les projets que GitWeb publie. Premirement, il faut ajouter au
chier /etc/gitweb.conf quelque chose comme :
$projects_list = "/home/git/gitosis/projects.list";
$projectroot = "/home/git/repositories";
$export_ok = "git-daemon-export-ok";
@git_base_url_list = ('git://gitserver');
Vous pouvez contrler les projets publis sur GitWeb en ajoutant ou retirant une proprit
gitweb au chier de conguration de Gitosis. Par exemple, si vous voulez que le projet iphone soit
visible sur GitWeb, le paramtrage repo doit tre le suivant :
[repo iphone_projet]
daemon = yes
gitweb = yes
Maintenant, si vous validez et poussez le projet gitosis-admin, GitWeb commencera automatiquement publier votre projet iphone.
94
4.9.1 GitHub
GitHub est lgrement dirent de la plupart des sites dhbergement de code dans le sens o
il utilise un espace de noms pour les projets. Au lieu dtre principalement orient projet, GitHub
est orient utilisateur. Cela signie que lorsque jhberge mon projet grit sur GitHub, vous ne le
trouverez pas github.com/grit mais plutt github.com/schacon/grit. Il ny a pas
de dpt canonique dun projet, ce qui permet un projet de se dplacer dun utilisateur lautre
sans transition si le premier auteur abandonne le projet.
GitHub est aussi une socit commerciale qui facture les comptes qui utilisent des dpts privs,
mais tout le monde peut rapidement obtenir un compte gratuit pour hberger autant de projets libres
que dsir. Nous allons dtailler comment faire.
Vous devez choisir un nom dutilisateur qui nest pas dj utilis dans le systme et saisir une
adresse e-mail qui sera associe au compte et un mot de passe (voir gure 4-3).
Si vous lavez, cest le bon moment pour ajouter votre clef publique SSH. Nous avons dtaill
comment en gnrer prcdemment au chapitre Petites installations . Copiez le contenu de la clef
publique et collez-le dans la bote texte Cls SSH publiques . En cliquant sur Besoin daide
avec les cls publiques? , vous aurez accs aux instructions (en anglais) pour crer des clefs sur la
majorit des systmes dexploitation. Cliquez sur Crer un compte pour avoir accs au tableau
de bord du nouvel utilisateur (voir gure 4-4).
$ git init
$ git add .
$ git commit -m 'premiere validation'
Dans le cas dun projet Git local, ajoutez GitHub comme dpt distant et poussez-y votre
branche master :
Votre projet est prsent hberg sur GitHub et vous pouvez fournir lURL toute personne
avec qui vous souhaitez le partager. Dans notre cas, il sagit de http://github.com/testinguser/
97
iphone_projet. Vous pouvez aussi voir dans lentte de la page de chaque projet quil y a deux
URL Git (voir gure 4-8).
Figure 4.8: Entte de projet avec une URL publique et une URL prive
LURL Git en lecture seule est une URL Git publique en lecture seule que tout le monde
peut cloner. Utilisez cee URL pour publier et partager votre dpt sur un site web ou autre.
Votre URL SSH est une URL SSH en lecture/criture qui ne vous permet de lire et crire que
si vous possdez la clef prive associe la clef publique tlcharge pour votre utilisateur. and
dautres utilisateurs visiteront cee page de projet, ils ne verront pas cee URL, ils ne verront que
lURL publique.
Si votre projet est trs gros, ne suit pas les standards de nommage ou est priv, cee mthone
risque de ne pas fonctionner. Au chapitre 7, nous traiterons des imports manuels plus compliqus
de projets.
Pour accorder un autre utilisateur laccs en criture au projet, cliquez longlet Collaborateurs . Vous pouvez entrer le nom de lutilisateur dans la bote texte qui apparat. Au fur et
mesure de votre frappe, une liste droulante ache les noms qui correspondent aux caractres
taps. Lorsque vous avez trouv lutilisateur correct, cliquez le bouton Ajouter pour ajouter
lutilisateur comme collaborateur au projet (voir gure 4-11).
Lorsque vous avez ni dajouter des collaborateurs, vous devriez les voir en liste dans la bote
Repository Collaborators (voir gure 4-12).
Si vous devez rvoquer laccs certaines personnes, vous pouvez cliquer la croix rouge leur
correspondant et leur accs en criture sera eac. Pour des projets futurs vous pouvez aussi copier
des groupes de collaborateurs en copiant les permissions dun projet existant.
inverse, similaire ce quacherait la commande git log. Longlet Rseau ache tous les
utilisateurs ayant dupliqu votre projet et contribu. Longlet Tlchagements vous permet de
tlcharger les xcutables du projet ou de fournir des archives des sources de votre projet des
points baliss. Longlet Wiki fournit un wiki ou vous pouvez commencer crire la documentation ou dautres informations du projet. Longlet Graphiques permet de visualiser les contributions et les statistiques. Longlet principal Source sur lequel vous arrivez par dfaut ache le
contenu du rpertoire principal du projet et met en forme dessous le chier README sil en contient
un. Cet onglet ache aussi un bote contenant les informations de la dernire validation.
Figure 4.14: Obtenir un copie modiable et publiable dun dpt en cliquant le bouton Fork .
elques secondes plus tard, vous tes redirigs vers une nouvelle page de projet qui indique
que ce projet est un dupliqu dun autre (voir gure 4-15).
100
4.10 Rsum
Vous disposez de plusieurs moyens de mere en place un dpt Git distant pour pouvoir collaborer avec dautres et partager votre travail.
Grer votre propre serveur vous donne une grande matrise et vous permet de linstaller derrire un pare-feu, mais un tel serveur ncessite gnralement une certaine quantit de travail pour
linstallation et la maintenance. Si vous placez vos donnes sur un serveur hberg, cest trs simple
installer et maintenir. Cependant vous devez pouvoir hberger votre code sur des serveurs tiers
et certaines politiques dorganisation ne le permeent pas.
Choisir la meilleure solution ou combinaison de solutions pour votre cas ou celui de votre
socit ne devrait pas poser de problme.
101
Chapitre 5
Git distribu
Avec un dpt distant Git mis en place pour permere tous les dveloppeurs de partager
leur code, et la connaissance des commandes de base de Git pour une gestion locale, abordons les
mthodes de gestion distribue que Git nous ore.
Dans ce chapitre, vous dcouvrirez comment travailler dans un environnement distribu avec
Git en tant que contributeur ou comme intgrateur. Cela recouvre la manire de contribuer ecacement un projet et de rendre la vie plus facile au mainteneur du projet ainsi qu vous-mme,
mais aussi en tant que mainteneur, de grer un projet avec de nombreux contributeurs.
socit ou votre quipe, vous pouvez simplement continuer utiliser cee mthode avec Git. Meez
en place un dpt unique et donnez tous laccs en pousse. Git empchera les utilisateurs dcraser
le travail des autres. Si un dveloppeur clone le dpt central, fait des modications et essaie de les
pousser alors quun autre dveloppeur pouss ses modications dans le mme temps, le serveur
rejeera les modications du premier. Il lui sera indiqu quil cherche pousser des modications
sans mode avance rapide et quil ne pourra pas le faire tant quil naura pas rcupr et fusionn les
nouvelles modications depuis le serveur. Cee mthode est trs intressante pour de nombreuses
personnes car cest un paradigme avec lequel beaucoup sont familiers et laise.
Ce schma de processus nest pas trs utilis mais savre utile dans des projets trs gros ou
pour lesquels un ordre hirarchique existe, car il permet au chef de projet (le dictateur) de dlguer
une grande partie du travail et de collecter de grands sous-ensembles de codes dirents points
avant de les intgrer.
105
Ce sont des schmas de processus rendus possibles et gnralement utiliss avec des systmes
distribus tels que Git, mais de nombreuses variations restent possibles pour coller un ux de
modications donn. En esprant vous avoir aid choisir le meilleur mode de gestion pour votre
cas, je vais traiter des exemples plus spciques de mthode de ralisation des rles principaux
constituant les dirents ux.
tion facilitent grandement lutilisation de Git et la collaboration entre dveloppeurs. Le projet Git
fournit un document qui dcrit un certain nombre de bonnes pratiques pour crer des commits qui
serviront fournir des patchs le document est accessibles dans les sources de Git, dans le chier
Documentation/SubmittingPatches.
Premirement, il ne faut pas soumere de patchs comportant des erreurs despace (caractres
espace inutiles en n de ligne). Git fournit un moyen simple de le vrier avant de valider, lancez
la commande git diff --check qui identiera et listera les erreurs despace. Voici un exemple
dans lequel les caractres en couleur rouge ont t remplacs par des X :
@git_dir = File.expand_path(git_dir)XX
def command(git_cmd)XXXX
En lanant cee commande avant chaque validation, vous pouvez vrier que vous ne commeez pas derreurs despace qui pourraient ennuyer les autres dveloppeurs.
Ensuite, assurez-vous de faire de chaque validation une modication logiquement atomique. Si
possible, rendez chaque modication digeste ne codez pas pendant un week-end entier sur cinq
sujets dirents pour enn les soumere tous dans une norme validation le lundi suivant. Mme si
vous ne validez pas du week-end, utilisez la zone dindex le lundi pour dcouper votre travail en au
moins une validation par problme, avec un message utile par validation. Si certaines modications
touchent au mme chier, essayez dutiliser git add --patch pour indexer partiellement des
chiers (cee fonctionnalit est traite au chapitre 6). Linstantan nal sera identique, que vous
utilisiez une validation unique ou cinq petites validations, condition que toutes les modications
soient intgres un moment, donc nhsitez pas rendre la vie plus simple vos compagnons
dveloppeurs lorsquils auront vrier vos modications. Cee approche simplie aussi le retrait
ou linversion ultrieurs dune modication en cas de besoin. Le chapitre 6 dcrit justement quelques
trucs et astuces de Git pour rcrire lhistorique et indexer interactivement les chiers utilisez
ces outils pour fabriquer un historique propre et comprhensible.
Le dernier point soigner est le message de validation. Shabituer crire des messages de
validation de qualit facilite grandement lemploi et la collaboration avec Git. En rgle gnrale,
les messages doivent dbuter par une ligne unique dau plus 50 caractres dcrivant concisment la
modication, suivie dun ligne vide, suivie dune explication plus dtaille. Le projet Git exige que
lexplication dtaille inclut la motivation de la modication en contrastant le nouveau comportement par rapport lancien cest une bonne rgle de rdaction. Un bonne rgle consiste aussi
utiliser le prsent de limpratif ou des verbes substantivs dans le message. En dautres termes,
utilisez des ordres. Au lieu dcrire Jai ajout des tests pour ou En train dajouter des tests
pour , utilisez juste Ajoute des tests pour ou Ajout de tests pour .
Voici ci-dessous un modle tir de celui crit par Tim Pope at tpope.net :
107
Si tous vos messages de validation ressemblent ceci, les choses seront beaucoup plus simples
pour vous et les dveloppeurs avec qui vous travaillez. Le projet Git montre des messages de commit
bien formats je vous encourage y lancer un git log --no-merges pour pouvoir voir
comment rend un historique de messages bien formats.
Dans les exemples suivants et travers tout ce livre, par soucis de simplication, je ne formaterai pas les messages aussi proprement. Jutiliserai plutt loption -m de git commit. Faites ce
que je dis, pas ce que je fais.
# Ordinateur de John
$ git clone john@githost:simplegit.git
Initialized empty Git repository in /home/john/simplegit/.git/
...
$ cd simplegit/
$ vim lib/simplegit.rb
$ git commit -am 'Eliminer une valeur par defaut invalide'
[master 738ee87] Eliminer une valeur par defaut invalide
1 files changed, 1 insertions(+), 1 deletions(-)
108
La deuxime dveloppeuse, Jessica, fait la mme chose. Elle clone le dpt et valide une modication :
# Ordinateur de Jessica
$ git clone jessica@githost:simplegit.git
Initialized empty Git repository in /home/jessica/simplegit/.git/
...
$ cd simplegit/
$ vim TODO
$ git commit -am 'Ajouter une tache reset'
[master fbff5bc] Ajouter une tache reset
1 files changed, 1 insertions(+), 0 deletions(-)
# Ordinateur de Jessica
$ git push origin master
...
To jessica@githost:simplegit.git
1edee6b..fbff5bc
# Ordinateur de John
$ git push origin master
To john@githost:simplegit.git
! [rejected]
John na pas le droit de pousser parce que Jessica a dj pouss dans lintervalle. Il est trs
important de comprendre ceci si vous avez dj utilis Subversion, parce quil faut remarquer que les
deux dveloppeurs nont pas modi le mme chier. and des chiers dirents ont t modis,
Subversion ralise cee fusion automatiquement sur le serveur alors que Git ncessite une fusion
des modications locale. John doit rcuprer les modications de Jessica et les fusionner avant dtre
autoris pousser :
-> origin/master
1 +
Cee fusion se passe sans problme lhistorique de commits de John ressemble prsent
la gure 5-5.
Maintenant, John peut tester son code pour sassurer quil fonctionne encore correctement et
peut pousser son travail nouvellement fusionn sur le serveur :
Figure 5.6: Lhistorique de John aprs avoir pouss sur le serveur origin.
Dans lintervalle, Jessica a travaill sur une branche thmatique. Elle a cr une branche thmatique nomme prob54 et ralis trois validations sur cee branche. Elle na pas encore rcupr
les modications de John, ce qui donne un historique semblable la gure 5-7.
Jessica souhaite se synchroniser sur le travail de John. Elle rcupre donc ses modications :
# Ordinateur de Jessica
$ git fetch origin
...
From jessica@githost:simplegit
fbff5bc..72bbc59
master
-> origin/master
Cee commande tire le travail que John avait pouss dans lintervalle. Lhistorique de Jessica
ressemble maintenant la gure 5-8.
Figure 5.8: Lhistorique de Jessica aprs avoir rcupr les modications de John.
Jessica pense que sa branche thmatique et prte mais elle souhaite savoir si elle doit fusionner
son travail avant de pouvoir pousser. Elle lance git log pour sen assurer :
111
Maintenant, Jessica peut fusionner sa branche thmatique dans sa branche master, fusionner le travail de John (origin/master)dans sa branche master, puis pousser le rsultat sur le
serveur. Premirement, elle rebascule sur sa branche master pour intgrer son travail :
Elle peut fusionner soit origin/master soit prob54 en premier les deux sont en avance,
mais lordre nimporte pas. Linstantan nal devrait tre identique quelque soit lordre de fusion quelle choisit. Seul lhistorique sera lgrement dirent. Elle choisit de fusionner en premier
prob54 :
lib/simplegit.rb |
1 +
6 +++++-
Aucun problme napparat. Comme vous pouvez le voir, cest une simple avance rapide. Maintenant, Jessica fusionne le travail de John (origin/master) :
2 +-
112
Figure 5.9: Lhistorique de Jessica aprs avoir fusionn les modications de John.
Chaque dveloppeur a valid quelques fois et fusionn les travaux de lautre avec succs (voir
gure 5-10).
Figure 5.10: Lhistorique de Jessica aprs avoir pouss toutes ses modications sur le serveur.
Cest un des schma les plus simples. Vous travaillez pendant quelques temps, gnralement
sur une branche thmatique, et fusionnez dans votre branche master quand elle est prte tre
intgre. and vous souhaitez partager votre travail, vous rcuprez origin/master et la fusionnez si elle a chang, puis nalement vous poussez le rsultat sur la branche master du serveur.
La squence est illustre par la gure 5-11.
Figure 5.11: Squence gnrale des vnements pour une utilisation simple multi-dveloppeur de Git.
113
# Ordinateur de Jessica
$ git checkout -b fonctionA
Switched to a new branch "fonctionA"
$ vim lib/simplegit.rb
$ git commit -am 'Ajouter une limite la fonction de log'
[fonctionA 3300904] Ajouter une limite la fonction de log
1 files changed, 1 insertions(+), 1 deletions(-)
ce moment, elle a besoin de partager son travail avec John, donc elle pousse les commits de
sa branche fonctionA sur le serveur. Jessica na pas le droit de pousser sur la branche master
seuls les intgrateurs lont et elle doit donc pousser sur une autre branche pour collaborer avec
John :
Jessica envoie un e-mail John pour lui indiquer quelle a pouss son travail dans la branche
appele fonctionA et quil peut linspecter. Pendant quelle aend le retour de John, Jessica dcide
de commencer travailler sur la fonctionB avec Josie. Pour commencer, elle cre une nouvelle
branche thmatique, partir de la base master du serveur :
# Ordinateur de Jessica
$ git fetch origin
$ git checkout -b fonctionB origin/master
Switched to a new branch "fonctionB"
$ vim lib/simplegit.rb
$ git commit -am 'Rendre la fonction ls-tree recursive'
[fonctionB e5b0fdc] Rendre la fonction ls-tree recursive
1 files changed, 1 insertions(+), 1 deletions(-)
$ vim lib/simplegit.rb
$ git commit -am 'Ajout de ls-files'
[fonctionB 8512791] Ajout ls-files
1 files changed, 5 insertions(+), 0 deletions(-)
Elle est prte pousser son travail, mais elle reoit un mail de Josie indiquant quune branche
avec un premier travail a dj t pouss sur le serveur en tant que fonctionBee. Jessica doit
dabord fusionner ces modications avec les siennes avant de pouvoir pousser sur le serveur. Elle
peut rcuprer les modications de Josie avec git fetch :
Jessica peut prsent fusionner ceci dans le travail quelle a ralis grce git merge :
4 ++++
Mais il y a un petit problme elle doit pousser son travail fusionn dans sa branche fonctionB sur la branche fonctionBee du serveur. Elle peut le faire en spciant la branche locale
suivie de deux points (:) suivi de la branche distante la commande git push :
115
Cela sappelle une refspec. Rfrez-vous au chapitre 9 pour une explication plus dtaille des
refspecs Git et des possibilits quelles orent.
Ensuite, John envoie un e-mail Jessica pour lui indiquer quil a pouss des modications sur
la branche fonctionA et lui demander de les vrier. Elle lance git fetch pour tirer toutes
ces modications :
fonctionA
-> origin/fonctionA
10 +++++++++-
Jessica veut rgler quelques dtails. Elle valide donc encore et pousse ses changements sur le
serveur :
116
Jessica, Josie et John informent les intgrateurs que les branches fonctionA et fonctionB
du serveur sont prtes pour une intgration dans la branche principale. Aprs cee intgration, une
synchronisation apportera les commits de fusion, ce qui donnera un historique comme celui de la
gure 5-14.
Figure 5.14: Lhistorique de Jessica aprs la fusion de ses deux branes thmatiques.
De nombreuses quipes basculent vers Git du fait de cee capacit grer plusieurs quipes
travaillant en parallle, fusionnant plusieurs lignes de dveloppement trs tard dans le processus de
livraison. La capacit donne plusieurs sous-groupes dquipes collaborer au moyen de branches
distantes sans ncessairement impacter le reste de lquipe est un grand bnce apport par Git.
La squence de travail qui vous a t dcrite ressemble la gure 5-15.
Premirement, vous souhaiterez probablement cloner le dpt principal, crer une nouvelle
branche thmatique pour le patch ou la srie de patchs que seront votre contribution et commencer
travailler. La squence ressemble globalement ceci :
Vous pouvez utiliser rebase -i pour rduire votre travail une seule validation ou pour
rarranger les modications dans des commits qui rendront les patchs plus faciles relire pour le
mainteneur rfrez-vous au chapitre 6 pour plus dinformation sur comment rebaser de manire
interactive.
Lorsque votre branche de travail est prte et que vous tes prt la fournir au mainteneur,
rendez-vous sur la page du projet et cliquez sur le bouton Fork pour crer votre propre projet
dupliqu sur lequel vous aurez les droits en criture. Vous devez alors ajouter lURL de ce nouveau
dpt en tant que second dpt distant, dans notre cas nomm macopie :
Vous devez pousser votre travail sur cee branche distante. Cest beaucoup plus facile de
pousser la branche sur laquelle vous travaillez sur une branche distante que de fusionner et de
118
poussez le rsultat sur le serveur. La raison principale en est que si le travail nest pas accept ou
sil est picor, vous naurez pas faire marche arrire sur votre branche master. Si le mainteneur
fusionne, rebase ou picore votre travail, vous le saurez en tirant depuis son dpt :
Une fois votre travail pouss sur votre copie du dpt, vous devez notier le mainteneur. Ce
processus est souvent appel une demande de tirage (pull request) et vous pouvez la gnrer soit via
le site web GitHub propose un bouton pull request qui envoie automatiquement un message
au mainteneur soit lancer la commande git request-pull et envoyer manuellement par
e-mail le rsultat au mainteneur de projet.
La commande request-pull prend en paramtres la branche de base dans laquelle vous
souhaitez que votre branche thmatique soit fusionne et lURL du dpt Git depuis lequel vous
souhaitez quelle soit tire, et gnre un rsum des modications que vous demandez faire tirer.
Par exemple, si Jessica envoie John une demande de tirage et quelle a fait deux validations dans
la branche thmatique quelle vient de pousser, elle peut lancer ceci :
10 +++++++++-
Le rsultat peut tre envoy au mainteneur cela lui indique do la modication a t branche,
le rsum des validations et do tirer ce travail.
Pour un projet dont vous ntes pas le mainteneur, il est gnralement plus ais de toujours
laisser la branche master suivre origin\master et de raliser vos travaux sur des branches
thmatiques que vous pourrez facilement eacer si elles sont rejetes. Garder les thmes de travaux
isols sur des branches thmatiques facilite aussi leur rebasage si le sommet du dpt principal a
avanc dans lintervalle et que vos modications ne sappliquent plus proprement. Par exemple,
si vous souhaitez soumere un second sujet de travail au projet, ne continuez pas travailler sur
la branche thmatique que vous venez de pousser mais dmarrez en plutt une depuis la branche
master du dpt principal :
119
$ (travail)
$ git commit
$ git push macopie fonctionB
$ (email au mainteneur)
$ git fetch origin
prsent, chaque sujet est contenu dans son propre silo similaire un le de patchs que
vous pouvez rcrire, rebaser et modier sans que les sujets ninterrent ou ne dpendent entre
eux, comme sur la gure 5-16.
Figure 5.16: Historique initial des commits avec les modication de fonctionB.
Supposons que le mainteneur du projet a tir une poigne dautres patchs et essay par la
suite votre premire branche, mais celle-ci ne sapplique plus proprement. Dans ce cas, vous pouvez
rebaser cee branche au sommet de origin/master, rsoudre les conits pour le mainteneur et
soumere de nouveau vos modications :
Cee action rcrit votre historique pour quil ressemble la gure 5-17.
Comme vous avez rebas votre branche, vous devez spcier loption -f votre commande
pour pousser, pour forcer le remplacement de la branche fonctionA sur le serveur par la suite de
commits qui nen est pas descendante. Une solution alternative serait de pousser ce nouveau travail
dans une branche dirente du serveur (appele par exemple fonctionAv2).
120
Examinons un autre scnario possible : le mainteneur a revu les modications dans votre seconde branche et apprcie le concept, mais il souhaiterait que vous changiez des dtails dimplmentation.
Vous en proterez pour rebaser ce travail sur le sommet actuel de la branche master du projet.
Vous dmarrez une nouvelle branche partir de la branche origin/master courante, y collez
les modications de fonctionB en rsolvant les conits, changez limplmentation et poussez le
tout en tant que nouvelle branche :
Loption --squash prend tout le travail de la branche fusionner et le colle dans un commit
sans fusion au sommet de la branche extraite. Loption --no-commit indique Git de ne pas
enregistrer automatiquement une validation. Cela permet de reporter toutes les modications dune
autre branche, puis de raliser dautres modications avant de raliser une nouvelle validation.
prsent, vous pouvez envoyer au mainteneur un message indiquant que vous avez ralis
les modications demandes et quil peut trouver cee nouvelle mouture sur votre branche fonctionBv2 (voir gure 5-18).
121
$ (travail)
$ git commit
Vous avez prsent deux commits que vous souhaitez envoyer la liste de diusion. Vous
utilisez git format-patch pour gnrer des chiers au format mbox que vous pourrez envoyer la liste. Cee commande transforme chaque commit en un message e-mail dont le sujet est
la premire ligne du message de validation et le corps contient le reste du message plus le patch correspondant. Un point intressant de cee commande est quappliquer le patch partir dun e-mail
format avec format-patch prserve toute linformation de validation comme nous le verrons
dans le chapitre suivant lorsquil sagit de lappliquer.
La commande format-patch ache les noms de chiers de patch crs. Loption -M indique
Git de suivre les renommages. Le contenu des chiers ressemble ceci :
$ cat 0001-Ajout-d-une-limite-la-fonction-de-log.patch
From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith <jessica@example.com>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] Ajout d'une limite la fonction de log
Limite la fonctionnalit de log aux 20 premires lignes
--lib/simplegit.rb |
2 +-
-1.6.2.rc1.20.g8c5b.dirty
Vous pouvez maintenant diter ces chiers de patch pour ajouter plus dinformation destination de la liste de diusion mais que vous ne souhaitez par voir apparatre dans le message de valida122
tion. Si vous ajoutez du texte entre la ligne -- et le dbut du patch (la ligne lib/simplegit.rb),
les dveloppeurs peuvent le lire mais lapplication du patch ne le prend pas en compte.
Pour envoyer par e-mail ces chiers, vous pouvez soit copier leur contenu dans votre application de-mail ou lenvoyer via une ligne de commande. Le copier-coller cause souvent des problmes
de formatage, spcialement avec les applications intelligentes qui ne prservent pas les retours
la ligne et les types despace. Heureusement, Git fournit un outil pour envoyer correctement les
patchs formats via IMAP, la mthode la plus facile. Je dmontrerai comment envoyer un patch
via Gmail qui savre tre lagent e-mail que jutilise ; vous pourrez trouver des instructions dtailles pour de nombreuses applications de mail la n du chier susmentionn Documentation/
SubmittingPatches du code source de Git.
Premirement, il est ncessaire de paramtrer la section imap de votre chier ~/.gitconfig. Vous pouvez positionner ces valeurs sparment avec une srie de commandes git config,
ou vous pouvez les ajouter manuellement. la n, le chier de conguration doit ressembler ceci :
[imap]
folder = "[Gmail]/Drafts"
host = imaps://imap.gmail.com
user = user@gmail.com
pass = p4ssw0rd
port = 993
sslverify = false
Si votre serveur IMAP nutilise pas SSL, les deux dernires lignes ne sont probablement pas
ncessaires et le paramtre host commencera par imap:// au lieu de imaps://. and cest
fait, vous pouvez utiliser la commande git send-email pour placer la srie de patchs dans le
rpertoire Dras du serveur IMAP spci :
La premire question demande ladresse mail dorigine (avec par dfaut celle saisie en cong),
tandis que la seconde demande les destinataires. Enn la dernire question sert indiquer que lon
souhaite poster la srie de patchs comme une rponse au premier patch de la srie, crant ainsi un
l de discussion unique pour cee srie. Ensuite, Git crache un certain nombre dinformations qui
ressemblent ceci pour chaque patch envoyer :
123
To: jessica@example.com
Subject: [PATCH 1/2] Ajout d'une limite la-fonction de log
Date: Sat, 30 May 2009 13:29:15 -0700
Message-Id: <1243715356-61726-1-git-send-email-jessica@example.com>
X-Mailer: git-send-email 1.6.2.rc1.20.g8c5b.dirty
In-Reply-To: <y>
References: <y>
Result: OK
prsent, vous devriez pouvoir vous rendre dans le rpertoire Dras, changer le champ destinataire pour celui de la liste de diusion, y ajouter optionnellement en copie le mainteneur du
projet ou le responsable et lenvoyer.
5.2.6 Rsum
Ce chapitre a trait quelques unes des mthodes communes de gestion de types dirents de
projets Git que vous pourrez rencontrer et a introduit un certain nombre de nouveaux outils pour
vous aider grer ces processus. Dans la section suivante, nous allons voir comment travailler de
lautre ct de la barrire : en tant que mainteneur de projet Git. Vous apprendrez comment travailler
comme dictateur bnvole ou gestionnaire dintgration.
124
Ou bien, si vous voulez aussi basculer immdiatement dessus, vous pouvez utiliser loption
checkout -b :
Vous voil maintenant prt ajouter les modications sur cee branche thmatique et dterminer si cest prt tre fusionn dans les branches au long cours.
Les chiers dans votre copie de travail sont modis. Cest quasiment identique la commande
patch -p1 qui applique directement les patchs mais en plus paranoaque et moins tolrant sur les
concordances approximatives. Les ajouts, eacements et renommages de chiers sont aussi grs
sils sont dcrits dans le format git diff, ce que patch ne supporte pas. Enn, git apply
fonctionne en mode applique tout ou refuse tout dans lequel toutes les modications proposes
sont appliques si elles le peuvent, sinon rien nest modi l o patch peut nappliquer que partiellement les patchs, laissant le rpertoire de travail dans un tat intermdiaire. git apply est
par dessus tout plus paranoaque que patch. Il ne crera pas une validation votre place : aprs
lavoir lanc, vous devrez indexer et valider les modications manuellement.
Vous pouvez aussi utiliser git apply pour voir si un patch sapplique proprement avant de
rellement lappliquer vous pouvez lancer git apply --check avec le patch :
Sil ny pas de message, le patch devrait sappliquer proprement. Cee commande se termine
avec un statut non-nul si la vrication choue et vous pouvez donc lutiliser dans des scripts.
Application dun pat avec am
Si le contributeur est un utilisateur de Git qui a t assez gentil dutiliser la commande formatpatch pour gnrer ses patchs, votre travail sera facilit car le patch contient alors dj linformation
125
dauteur et le message de validation. Si possible, encouragez vos contributeurs utiliser formatpatch au lieu de patch pour gnrer les patchs quils vous adressent. Vous ne devriez avoir
nutiliser git apply que pour les vrais patchs.
Pour appliquer un patch gnr par format-patch, vous utilisez git am. Techniquement,
git am saend lire un chier au format mbox, qui est un format texte simple permeant de
stocker un ou plusieurs messages e-mail dans un unique chier texte. Un chier ressemble ceci :
Cest le dbut de ce que la commande format-patch ache, comme vous avez vu dans
la section prcdente. Cest aussi un format e-mail mbox parfaitement valide. Si quelquun vous a
envoy par e-mail un patch correctement format en utilisant git send-mail et que vous le
tlchargez en format mbox, vous pouvez pointer git am sur ce chier mbox et il commencera
appliquer tous les patchs contenus. Si vous utilisez un client e-mail qui sait sauver plusieurs messages
au format mbox, vous pouvez sauver la totalit de la srie de patchs dans un chier et utiliser git
am pour les appliquer tous en une fois.
Nanmoins, si quelquun a dpos un chier de patch gnr via format-patch sur un
systme de suivi de faits techniques ou quelque chose similaire, vous pouvez toujours sauvegarder
le chier localement et le passer git am pour lappliquer :
$ git am 0001-limite-la-fonction-de-log.patch
Applying:
Vous remarquez quil sest appliqu proprement et a cr une nouvelle validation pour vous.
Linformation dauteur est extraite des enttes From et Date tandis que le message de validation
est repris du champ Subject et du corps (avant le patch) du message. Par exemple, si le patch est
appliqu depuis le chier mbox ci-dessus, la validation gnre ressemblerait ceci :
Il reste la possibilit que le patch ne sapplique pas proprement. Peut-tre votre branche principale a dj trop diverg de la branche sur laquelle le patch a t construit, ou le patch dpend dun
autre patch qui na pas encore t appliqu. Dans ce cas, le processus de git am chouera et vous
demandera ce que vous souhaitez faire :
$ git am 0001-seeing-if-this-helps-the-gem.patch
Applying: seeing if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Patch failed at 0001.
When you have resolved this problem run "git am --resolved".
If you would prefer to skip this patch, instead run "git am --skip".
To restore the original branch and stop patching run "git am --abort".
Cee commande introduit des marqueurs de conit dans tous les chiers qui ont gnr un
problme, de la mme manire quun conit de fusion ou de rebasage. Vous pouvez rsoudre les
problmes de manire identique ditez le chier pour rsoudre les conits, indexez le nouveau
chier, puis lancez git am --resolved pour continuer avec le patch suivant :
$ (correction du fichier)
$ git add ticgit.gemspec
$ git am --resolved
Applying: seeing if this helps the gem
Si vous souhaitez que Git essaie de rsoudre les conits avec plus dintelligence, vous pouvez
passer loption -3 qui demande Git de tenter une fusion trois sources. Cee option nest pas
active par dfaut parce quelle ne fonctionne pas si le commit sur lequel le patch indique tre bas
nexiste pas dans votre dpt. Si par contre, le patch est bas sur un commit public, loption -3 est
gnralement beaucoup plus ne pour appliquer des patchs conictuels :
$ git am -3 0001-seeing-if-this-helps-the-gem.patch
Applying: seeing if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
No changes -- Patch already applied.
Dans ce cas, je cherchais appliquer un patch qui avait dj t intgr. Sans loption -3, cela
aurait ressembl un conit.
Si vous appliquez des patchs partir dun chier mbox, vous pouvez aussi lancer la commande am en mode interactif qui sarrte chaque patch trouv et vous demande si vous souhaitez
lappliquer :
127
$ git am -3 -i mbox
Commit Body is:
-------------------------seeing if this helps the gem
-------------------------Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all
Cest agrable si vous avez un certain nombre de patchs sauvegards parce que vous pouvez
voir les patchs pour vous rafrachir la mmoire et ne pas les appliquer sils ont dj t intgrs.
and tous les patchs pour votre sujet ont t appliqus et valids dans votre branche, vous
pouvez choisir si et comment vous souhaitez les intgrer dans une branche au long cours.
Si elle vous envoie un autre mail indiquant une autre branche contenant une autre fonctionnalit gniale, vous pouvez la rcuprer et la tester simplement partir de votre rfrence distante.
Cest dautant plus utile si vous travaillez en continu avec une personne. Si quelquun na quun
seul patch contribuer de temps en temps, laccepter via e-mail peut savrer moins consommateur
en temps de prparation du serveur public, dajout et retrait de branches distantes juste pour tirer
quelques patchs. Vous ne souhaiteriez srement pas devoir grer des centaines de dpts distants
pour intgrer chaque fois un ou deux patchs. Nanmoins, des scripts et des services hbergs
peuvent rendre cee tche moins ardue. Cela dpend largement de votre manire de dvelopper et
de celle de vos contributeurs.
Cee approche a aussi lavantage de vous fournir lhistorique des validations. Mme si vous
pouvez rencontrer des problmes de fusion lgitimes, vous avez linformation dans votre historique
de la base ayant servi pour les modications contribues. La fusion trois sources est choisie par
dfaut plutt que davoir spcier loption -3 en esprant que le patch a t gnr partir dun
instantan public auquel vous auriez accs.
Si vous ne travaillez pas en continu avec une personne mais souhaitez tout de mme tirer les
modications de cee manire, vous pouvez fournir lURL du dpt distant la commande git
pull. Cela permet de raliser un tirage unique sans sauver lURL comme rfrence distante :
128
HEAD
-> FETCH_HEAD
Pour visualiser les modications que chaque commit introduit, souvenez-vous que vous pouvez
passer loption -p git log et elle ajoutera le di introduit chaque commit.
Pour visualiser un di complet de ce qui arriverait si vous fusionniez cee branche thmatique
avec une autre branche, vous pouvez utiliser un truc bizarre pour obtenir les rsultats corrects. Vous
pourriez penser lancer ceci :
Cee commande ache un di mais elle peut tre trompeuse. Si votre branche master a
avanc depuis que vous en avez cr la branche thmatique, vous obtiendrez des rsultats apparemment tranges. Cela arrive parce que Git compare directement linstantan de la dernire validation
sur la branche thmatique et celui de la dernire validation sur la branche master. Par exemple, si
vous avez ajout une ligne dans un chier sur la branche master, une comparaison directe donnera
limpression que la branche thmatique va retirer cee ligne.
Si master est un anctre directe de la branche thmatique, ce nest pas un problme. Si les
deux historiques ont diverg, le di donnera limpression que vous ajoutez toutes les nouveauts de
129
la branche thmatique et retirez tout ce qui a t fait depuis dans la branche master.
Ce que vous souhaitez voir en fait, ce sont les modications ajoutes sur la branche thmatique le travail que vous introduirez si vous fusionnez cee branche dans master. Vous obtenez ce
rsultat en demandant Git de comparer le dernier instantan de la branche thmatique avec son
anctre commun la branch master le plus rcent.
Techniquement, cest ralisable en dterminant exactement lanctre commun et en lanant la
commande di dessus :
Nanmoins, comme ce nest pas trs commode, Git fournit un raccourci pour raliser la mme
chose : la syntaxe trois points. Dans le contexte de la commande diff, vous pouvez placer trois
points aprs une autre branche pour raliser un diff entre le dernier instantan de la branche sur
laquelle vous vous trouvez et son anctre commun avec une autre branche :
Cee commande ne vous montre que les modications que votre branche thmatique a introduites depuis son anctre commun avec master. Cest une syntaxe trs utile se souvenir.
Ainsi, lorsque lon clone le dpt de votre projet, on peut soit extraire la branche master pour
construire la dernire version stable et mere jour facilement ou on peut extraire le branche
develop qui reprsente le nec plus ultra du dveloppement.
Vous pouvez aussi continuer ce concept avec une branche dintgration o tout le travail est
fusionn. Alors, quand la base de code sur cee branche est stable et que les tests passent, vous la
fusionnez dans la branche develop. and cela sest avr stable pendant un certain temps, vous
meez jour la branche master en avance rapide.
Gestions avec nombreuses fusions
Le projet Git dispose de quatre branches au long cours : master, next, pu (proposed updates :
propositions) pour les nouveaux travaux et maint pour les backports de maintenance. and une
nouvelle contribution est propose, elle est collecte dans des branches thmatiques dans le dpt
131
du mainteneur dune manire similaire ce que jai dcrit (voir gure 5-24). A ce point, les fonctionnalits sont values pour dterminer si elles sont stables et prtes tre consommes ou si elles
ncessitent un peaunage. Si elles sont stables, elles sont fusionnes dans next et cee branche est
pousse sur le serveur public pour que tout le monde puisse essayer les fonctionnalits intgres
ensemble.
Si les fonctionnalits ncessitent encore du travail, elles sont fusionnes plutt dans pu. and
elles sont considres comme totalement stables, elles sont re-fusionnes dans master et sont alors
reconstruites partir fonctionnalits qui rsidaient dans next mais nont pu intgrer master. Cela
132
signie que master volue quasiment toujours en mode avance rapide, tandis que next est rebas
assez souvent et pu est rebas encore plus souvent (voir gure 5-25).
Figure 5.25: Fusion des branes thmatiques dans les branes long terme.
and une branche thmatique a nalement t fusionne dans master, elle est eace du
dpt. Le projet Git a aussi une branche maint qui est cre partir de la dernire version pour
fournir des patchs correctifs en cas de besoin de version de maintenance. Ainsi, quand vous clonez
le dpt de Git, vous avez quatre branches disponibles pour valuer le projet direntes tapes
de dveloppement, selon le niveau dveloppement que vous souhaitez utiliser ou pour lequel vous
souhaitez contribuer. Le mainteneur a une gestion structure qui lui permet dvaluer et slectionner
les nouvelles contributions.
Gestion par rebasage et slection de commit
Dautres mainteneurs prrent rebaser ou slectionner les contributions sur le sommet de la
branche master, plutt de les fusionner, de manire conserver un historique peu prs linaire.
Lorsque plusieurs modications sont prsentes dans une branche thmatique et que vous souhaitez
les intgrer, vous vous placez sur cee branche et vous lancer la commande rebase pour reconstruire
les modications partir du sommet courant de la branche master (ou develop, ou autre). Si
cela fonctionne correctement, vous pouvez faire une avance rapide sur votre branche master et
vous obtenez au nal un historique de projet linaire.
Lautre moyen de dplacer des modications introduites dans une branche vers une autre consiste les slectionner (cherry-pick). Une slection dans Git ressemble un rebasage appliqu
133
un commit unique. Cela consiste prendre le patch qui a t introduit lors dune validation et
essayer de lappliquer sur la branche sur laquelle on se trouve. Cest trs utile si on a un certain
nombre de commits sur une branche thmatique et que lon veut nen intgrer quun seul, ou si on
na quun commit sur une branche thmatique et quon prre le slectionner plutt que de lancer
rebase. Par exemple, supposons que vous ayez un projet ressemblant la gure 5-26.
Si vous souhaitez tirer le commit e43a6 dans votre branche master, vous pouvez lancer
La mme modication que celle introduite en e43a6 est tire mais vous obtenez une nouvelle
valeur de SHA-1 car les dates dapplication sont direntes. prsent, votre historique ressemble
la gure 5-27.
Figure 5.27: Historique aprs slection dun commit dans une brane thmatique.
Maintenant, vous pouvez eacer votre branche thmatique et abandonner les commits que
vous navez pas tirs dans master.
134
Si vous signez vos balises, vous rencontrerez le problme de la distribution de votre cl publique
PGP permeant de vrier la signature. Le mainteneur du projet Git a rsolu le problme en incluant
la cl publique comme blob dans le dpt et en ajoutant une balise qui pointe directement sur ce
contenu. Pour faire de mme, vous dterminez la cl de votre trousseau que vous voulez publier en
lanant gpg --list-keys :
$ gpg --list-keys
/Users/schacon/.gnupg/pubring.gpg
--------------------------------pub
uid
sub
Ensuite, vous pouvez importer la cl directement dans la base de donne Git en lexportant de
votre trousseau et en la redirigeant dans git hash-object qui crit une nouveau blob avec son
contenu dans Git et vous donne en sortie le SHA-1 du blob :
prsent, vous avez le contenu de votre cl dans Git et vous pouvez crer une balise qui pointe
directement dessus en spciant la valeur SHA-1 que la commande hash-object vous a fournie :
Si vous lancez git push --tags, la balise mainteneur-pgp-pub sera partage publiquement. Un tiers pourra vrier une balise aprs import direct de votre cl publique PGP, en extrayant
le blob de la base de donne et en limportant dans GPG :
135
Il pourra alors utiliser cee cl pour vrier vos balises signes. Si de plus, vous incluez des
instructions dutilisation pour la vrication de signature dans le message de balisage, lutilisateur
aura accs ces informations en lanant la commande git show <balise>.
Lorsquon ouvre larchive, on obtient le dernier instantan du projet sous un rpertoire projet. On peut aussi crer une archive au format zip de manire similaire en passant loption -format=zip la commande git archive :
Voil deux belles archives tar.gz et zip de votre projet prtes tre tlcharges sur un site web
ou envoyes par e-mail.
136
5.3.9 Shortlog
Il est temps denvoyer une annonce la liste de diusion des annonces relatives votre projet.
Une manire simple dobtenir rapidement une sorte de liste des modications depuis votre dernire
version ou e-mail est dutiliser la commande git shortlog. Elle rsume toutes le validations
dans lintervalle qui vous lui spciez. Par exemple, ce qui suit vous donne un rsum de toutes les
validations depuis votre dernire version si celle-ci se nomme v1.0.1 :
Vous obtenez ainsi un rsum clair de toutes les validations depuis v1.0.1, regroupes par auteur, prt tre envoy sur la liste de diusion.
5.4 Rsum
Vous devriez prsent vous sentir laise pour contribuer un projet avec Git, mais aussi
pour maintenir votre propre projet et intgrer les contributions externes. Flicitations, vous tes
un dveloppeur Git ecace ! Au prochain chapitre, vous dcouvrirez des outils plus puissants pour
grer des situations complexes, qui feront de vous un matre de Git.
137
Chapitre 6
Utilitaires Git
A prsent, vous avez appris les commandes et modes de fonctionnements usuels requis pour
grer et maintenir un dpt Git pour la gestion de votre code source. Vous avez droul les routines
de suivi (traing) et de consignation (commiing) de chiers, vous avez exploit la puissance de la
zone daente (staging area), de la cration et de la fusion de branches locales de travail.
Maintenant, vous allez explorer un certain nombre de fonctionnalits particulirement ecaces, fonctionnalits que vous nutiliserez que rarement mais dont vous pourriez avoir lusage un
moment ou un autre.
$ git log
commit 734713bc047d87bf7eac9674765ae793478c50d3
Author: Scott Chacon <schacon@gmail.com>
Date:
139
commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Merge: 1c002dd... 35cfb2b...
Author: Scott Chacon <schacon@gmail.com>
Date:
Pour cet exemple, choisissons 1c002dd.... Si vous achez le contenu de ce commit via
git show, les commandes suivantes sont quivalentes (en partant du principe que les SHA-1
courts ne sont pas ambigs).
Git peut dterminer un SHA tout la fois le plus court possible et non ambig. Ajoutez loption
--abbrev-commit la commande git log et le rsultat ach utilisera des valeurs plus
courtes mais uniques; par dfaut git retiendra 7 caractres et augmentera au besoin :
En rgle gnrale, entre 8 et 10 caractres sont largement susant pour assurer lunicit dans un
projet. Un des plus gros projets utilisant Git, le kernel Linux, ncessite de plus en plus frquemment
12 caractres sur les 40 possibles pour assurer lunicit.
1
2160 ).
milliards. Cela reprsente 1200 fois le nombre de grains de sable sur terre.
Voici un exemple pour vous donner une ide de ce qui pourrait provoquer une collision du
SHA-1. Si tous les 6,5 milliards dhumains sur Terre programmait et que chaque seconde, chacun
produisait du code quivalent lhistorique entier du noyaux Linux (1 million dobjets Git) et le
poussait sur un norme dpt Git, cela prendrait 5 ans pour que ce dpt contienne assez dobjets
pour avoir une probabilit de 50% quune seule collision SHA-1 existe. Il y a une probabilit plus
grande que tous les membres de votre quipe de programmation serait aaqus et tus par des loups
dans des incidents sans relation la mme nuit.
Pour connatre lempreinte SHA sur lequel pointe une branche, ou pour savoir parmi tous les
exemples prcdents ce que cela donne en terme de SHA, vous pouvez utiliser la commande de
plomberie nomme rev-parse. Se rfrer au chapitre 9 pour plus dinformations sur les commandes de plomberie; en rsum, rev-parse est l pour les oprations de bas niveau et nest pas
conue pour tre utilise au jour le jour. oi quil en soit, cela peut se rvler utile pour comprendre
ce qui se passe. Je vous invite tester rev-parse sur votre propre branche.
$ git reflog
734713b... HEAD@{0}: commit: fixed refs handling, added gc auto, updated
d921970... HEAD@{1}: merge phedders/rdocs: Merge made by recursive.
1c002dd... HEAD@{2}: commit: added some blame and merge stuff
1c36188... HEAD@{3}: rebase -i (squash): updating HEAD
95df984... HEAD@{4}: commit: # This is a combination of two commits.
1c36188... HEAD@{5}: rebase -i (squash): updating HEAD
7e05da5... HEAD@{6}: rebase -i (pick): updating HEAD
141
chaque fois que lextrmit de votre branche est modie, Git enregistre cee information
pour vous dans son historique temporaire. Vous pouvez rfrencer danciens commits avec cee
donne. Si vous souhaitez consulter le n-ime antcdent de votre HEAD, vous pouvez utiliser la
rfrence @n du reog, 5 dans cet exemple :
Vous pouvez galement remonter le temps et savoir o en tait une branche un moment
donn. Par exemple, pour savoir o en tait la branche master hier (yesterday en anglais), tapez :
Cee technique fonctionne uniquement si linformation est encore prsente dans le reog, vous
ne pourrez donc pas consulter les commits trop anciens.
Pour consulter le reog au format git log, excutez: git log -g :
Veuillez noter que le reog ne stocke que des informations locales, cest un historique de ce
que vous avez fait dans votre dpt. Les rfrences ne sont pas copies dans un autre dpt; et juste
aprs le clone dun dpt, votre reog sera vide, puisque quaucune activit ne sy sera produite.
Excuter git show HEAD@{2.months.ago} ne fonctionnera que si vous avez dupliqu ce projet
depuis au moins 2 mois si vous lavez dupliqu il y a 5 minutes, vous nobtiendrez rien.
142
|\
| * 35cfb2b modifs minor rdoc
* | 1c002dd ajout blame and merge
|/
* 1c36188 ignore *.gem
* 9b29157 ajout open3_detach la liste des fichiers gemspcec
Alors, vous pouvez consulter le commit prcdent en spciant HEAD, ce qui signie le
parent de HEAD :
Vous pouvez galement spcier un nombre aprs par exemple, d9219702 signie le
second parent de d921970. . Cee syntaxe ne sert que pour les commits de fusion, qui ont plus dun
parent. Le premier parent est la branche o vous avez fusionn, et le second est le commit de la
branche que vous avez fusionne :
Une autre solution courante pour spcier une rfrence est le ~. Il fait galement rfrence
au premier parent, donc HEAD~ et HEAD sont quivalents. La dirence se fait sentir si vous
spciez un nombre. HEAD~2 signie le premier parent du premier parent, ou bien le grandparent ; a remonte les premiers parents autant de fois que demand. Par exemple, dans lhistorique
prcdemment prsent, HEAD~3 serait :
143
ignore *.gem
Cela aura bien pu tre crit HEAD, qui l encore est le premier parent du premier parent
du premier parent :
ignore *.gem
Vous pouvez galement combiner ces syntaxes vous pouvez obtenir le second parent de la
rfrence prcdente (en supposant que ctait un commit de fusion) en utilisant HEAD~32, etc.
Si vous voulez savoir ce que na pas encore t fusionn sur votre branche master depuis votre
branche experiment, vous pouvez demandez Git de vous montrer un listing des commits avec
master..experiment ce qui signie tous les commits accessibles par experiment qui ne
le sont pas par master. . Dans un souci de brivet et de clart de ces exemples, je vais utiliser les
leres des commits issus du diagramme la place du vrai listing dans lordre o ils auraient d tre
achs :
144
Dun autre ct, si vous souhaitez voir loppos tous les commits dans master mais pas encore dans experiment vous pouvez inverser les noms de branches, experiment..master
vous montre tout ce que master accde mais quexperiment ne voit pas :
Cest pratique si vous souhaitez maintenir experiment jour et anticiper les fusions. Une
autre cas dutilisation frquent et de voir ce que vous vous apprter pousser sur une branche
distante :
Cee commande vous ache tous les commits de votre branche courante qui ne sont pas sur
la branche master du dpt distant origin. Si vous excutez git push et que votre branche
courante suit origin/master, les commits lists par git log origin/master..HEAD sont
les commits qui seront transfrs sur le serveur. Vous pouvez galement laisser tomber une borne
de la syntaxe pour faire comprendre Git que vous parlez de HEAD. Par exemple, vous pouvez
obtenir les mmes rsultats que prcdemment en tapant git log origin/master.. Git
utilise HEAD si une des bornes est manquante.
Emplacements multiples
La syntaxe double-point est pratique comme raccourci; mais peut-tre souhaitez-vous utiliser
plus dune branche pour spcier une rvision, comme pour voir quels commits sont dans plusieurs
branches mais qui sont absents de la branche courante. Git vous permets cela avec or --not
en prxe de toute rfrence de laquelle vous ne souhaitez pas voir les commits. Les 3 commandes
ci-aprs sont quivalentes :
Cest utile car cela vous permets de spcier plus de 2 rfrences dans votre requte, ce que
vous ne pouvez accomplir avec la syntaxe double-point. Par exemple, si vous souhaitez voir les
commits qui sont accessibles depuis refA et refB mais pas depuis refC, vous pouvez taper ces 2
commandes :
145
Ceci vous fournit un systme de requtage des rvisions trs puissant, pour vous aider saisir
ce qui se trouve sur vos branches.
Triple point
La dernire syntaxe majeure de slection de plage de commits est la syntaxe triple-point, qui
spcie tous les commits accessible par lune des deux rfrence, exclusivement. Toujours avec
lexemple dhistorique la gure 6-1, si vous voulez voir ce qui ce trouve sur master ou experiment mais pas sur les 2, excutez :
Encore une fois, cela vous donne un log normal mais ne vous montre les informations que
pour ces quatre commits, dans lordre naturel des dates de commit.
Une option courante utiliser avec la commande log dans ce cas est --left-right qui
vous montre de quelle borne de la plage ce commit fait partie. Cela rend les donnes plus utiles :
Avec ces outils, vous pourrez utiliser Git pour savoir quels commits inspecter.
146
$ git add -i
staged
unstaged path
1:
unchanged
+0/-1 TODO
2:
unchanged
+1/-1 index.html
3:
unchanged
+5/-1 lib/simplegit.rb
2: update
3: revert
4: add untracked
5: patch
6: diff
7: quit
8: help
What now>
Vous vous apercevrez que cee commande propose une vue bien dirente de votre zone
daente; en gros, cest la mme information que vous auriez obtenue avec git status mais en
plus succint et plus instructif. Cela liste les modications que vous avez mises en aente gauche,
et celles en cours droite.
En dessous vient la section des commandes (* Commands*). Vous pourrez y faire bon nombre
de choses, notamment mere en aente des chiers, les enlever de la zone daente, mere en
aente des parties de chiers, ajouter des chiers non indexs, et vrier les dirences de ce que
vous avez mis en aente.
What now> 2
staged
unstaged path
1:
unchanged
+0/-1 TODO
2:
unchanged
+1/-1 index.html
3:
unchanged
+5/-1 lib/simplegit.rb
Update>>
Pour mere en aente les chiers TODO et index.html, vous pouvez taper ces nombres :
Update>> 1,2
staged
unstaged path
* 1:
unchanged
+0/-1 TODO
* 2:
unchanged
+1/-1 index.html
3:
unchanged
+5/-1 lib/simplegit.rb
Update>>
Le caractre * au dbut de la ligne de chaque chier indique que celui-ci est slectionn. Si
vous tapez Entre sur une invite Update>> vide, Git prend tout ce qui est slectionn et le met en
aente pour vous :
147
Update>>
updated 2 paths
*** Commands ***
1: status
2: update
3: revert
4: add untracked
5: patch
6: diff
7: quit
8: help
What now> 1
staged
unstaged path
1:
+0/-1
nothing TODO
2:
+1/-1
nothing index.html
3:
unchanged
+5/-1 lib/simplegit.rb
prsent, vous pouvez voir que les chiers TODO et index.html sont mis en aente (staged
en anglais) et que simplgit.rb ne lest toujours pas. Si vous souhaitez enlever de la zone daente le
chier TODO, utilisez 3 (ou r pour revert en anglais) :
2: update
3: revert
4: add untracked
5: patch
6: diff
7: quit
8: help
What now> 3
staged
unstaged path
1:
+0/-1
nothing TODO
2:
+1/-1
nothing index.html
3:
unchanged
+5/-1 lib/simplegit.rb
Revert>> 1
staged
unstaged path
+0/-1
nothing TODO
2:
+1/-1
nothing index.html
3:
unchanged
* 1:
+5/-1 lib/simplegit.rb
Revert>> [enter]
reverted one path
Un aperu rapide votre statut Git et vous pouvez voir que vous avez enlever de la zone
daente le chier TODO :
2: update
3: revert
4: add untracked
5: patch
6: diff
7: quit
8: help
What now> 1
staged
1:
unchanged
2:
+1/-1
3:
unchanged
unstaged path
+0/-1 TODO
nothing index.html
+5/-1 lib/simplegit.rb
Pour voir la modication que vous avez mise en aente, utilisez 6 ou d (pour di en anglais).
Cela vous ache la liste des chiers en aente et vous pouvez choisir ceux pour lesquels vous voulez
consulter la dirence. Cest quivalent git diff --cached en ligne de commande :
148
2: update
3: revert
4: add untracked
5: patch
6: diff
7: quit
8: help
What now> 6
staged
1:
+1/-1
unstaged path
nothing index.html
Review diff>> 1
diff --git a/index.html b/index.html
index 4d07108..4335f49 100644
--- a/index.html
+++ b/index.html
@@ -16,7 +16,7 @@ Date Finder
<p id="out">...</p>
-<div id="footer">contact : support@github.com</div>
+<div id="footer">contact : email.support@github.com</div>
<script type="text/javascript">
Avec ces commandes lmentaires, vous pouvez utiliser lajout interactif pour manipuler votre
zone daente un peu plus facilement.
A cee tape, vous disposez de bon nombre doptions. ? vous liste les actions possibles, voici
une traduction :
149
En rgle gnrale, vous choisirez y ou n pour mere en aente ou non chacun des blocs, mais
tout mere en aente pour certains chiers ou remere plus tard le choix pour un bloc peut
galement tre utile. Si vous meez en aente une partie dun chier et laissez une autre partie non
en aente, vous statut ressemblera peu prs ceci :
What now> 1
staged
1:
unchanged
2:
+1/-1
3:
+1/-1
unstaged path
+0/-1 TODO
nothing index.html
+4/-0 lib/simplegit.rb
Le statut pour le chier simplegit.rb est intressant. Il vous montre que quelques lignes sont
en aente et dautres non. Vous avez mis partiellement ce chier en aente. Ds lors, vous pouvez
quier lajout interactif et excuter git commit pour commiter les chiers partiellement en
aente.
Enn, vous pouvez vous passer du mode interactif pour mere partiellement un chier en
aente; vous pouvez faire de mme avec git add -p ou git add --patch en ligne de
commande.
6.3 La remise
Souvent, lorsque vous avez travaill sur une partie de votre projet, les choses sont dans un
tat instable mais vous voulez changer de branches pour un peu de travailler sur autre chose. Le
problme est que vous ne voulez pas consigner (commit) un travail moiti fait seulement pour
pouvoir y revenir plus tard. La rponse cee problmatique est la commande git stash.
Remiser prend ltat en cours de votre rpertoire de travail, cest--dire les chiers modis et la
zone daente, et lenregistre dans la pile des modications non nies que vous pouvez rappliquer
nimporte quel moment.
150
$ git status
# On branch master
# Changes to be committed:
#
#
#
modified:
index.html
#
# Changed but not updated:
#
#
#
modified:
lib/simplegit.rb
ce moment l, vous voulez changer de branche, mais vous ne voulez pas encore consigner
ce travail; vous allez donc remiser vos modications. Pour crer une nouvelle remise sur votre pile,
excutez git stash :
$ git stash
Saved working directory and index state \
"WIP on master: 049d078 added the index file"
HEAD is now at 049d078 added the index file
(To restore them type "git stash apply")
$ git status
# On branch master
nothing to commit (working directory clean)
ce moment, vous pouvez facilement changer de branche et travailler autre part; vos modications sont conserves dans votre pile. Pour voir quelles remises vous avez sauvegardes, vous
pouvez utiliser la commande git stash list :
Dans ce cas, deux remises on t cres prcdemment, vous avez donc accs trois travaux
remiss dirents. Vous pouvez rappliquer celui que vous venez juste de remis en utilisant la
151
commande ache dans la sortie daide de la premire commande de remise : git stash apply.
Si vous voulez appliquer une remise plus ancienne, vous pouvez la spcier en la nommant, comme
ceci : git stash apply stash@2. Si vous ne spcier pas une remise, Git prsume que vous
voulez la remise la plus rcente et essayes de lappliquer.
#
#
modified:
index.html
modified:
lib/simplegit.rb
Vous pouvez observer que Git remodie les chiers non consigns lorsque vous avez cr la
remise. Dans ce cas, vous aviez un rpertoire de travail propre lorsque vous avez essayer dappliquer
la remise, et vous lavez fait sur la mme branche que celle o vous laviez cre; mais avoir un
rpertoire de travail propre et lappliquer sur la mme branche nest pas ncessaire pour russir
appliquer une remise. Vous pouvez trs bien crer une remise sur une branche, changer de branche
et essayer dappliquer les modications. Vous pouvez mme avoir des chiers modis et non consigns dans votre rpertoire de travail quand vous appliquez une remise, Git vous fournit les conits
de fusions si quoique ce soit ne sapplique pas proprement.
Par dfaut, les modications de vos chiers sont rappliqus, mais pas les mises en aente.
Pour cela, vous devez excutez la commande git stash apply avec loption --index pour
demandez Git dessayer de rappliquer les modications de votre zone daente. Si vous excutez
cela la place de la commande prcdente, vous vous retrouvez dans la position dorigine de la
remise :
#
#
modified:
index.html
#
# Changed but not updated:
#
#
#
modified:
lib/simplegit.rb
Loption apply essaye seulement dappliquer le travail remis, vous aurez toujours la remise
dans votre pile. Pour la supprimer, vous pouvez excuter git stash drop avec le nom de la
remise supprimer :
152
Vous pouvez galement excutez git stash pop pour appliquer et supprimer immdiatement la remise de votre pile.
#
#
modified:
index.html
#
# Changed but not updated:
#
#
#
modified:
lib/simplegit.rb
#
Dropped refs/stash@{0} (f0dfc4d5dc332d1cee34a634182e168c4efc3359)
Cest un bon raccourci pour rcuprer du travail remis facilement et de pouvoir travailler
dessus dans une nouvelle branche.
rassembler ou sparer des commits, ou supprimer compltement des commits; tout ceci avant de les
partager avec les autres.
Danc cee section, nous expliquerons comment accomplir ces tches trs utiles pour que vous
pussiez faire ressembler votre historique de consignation de la manire que vous voulez avant de le
partager avec autrui.
Cela vous ouvre votre diteur de texte contenant votre dernier message, prt tre modi.
Lorsque vous sauvegardez et fermez lditeur, Git enregistre la nouvelle consignation contenant le
message et en fait votre dernier commit.
Si vous avez vouler modier le contenu de votre consignation, en ajoutant ou modiant des
chiers, srement parce que vous avez oubli dajouter les chiers nouvellement crs quand vous
avez consign la premire fois, la procdure fonctionne grosso-modo de la mme manire. Vous
meez les modications que vous voulez en aente en excutant git add ou git rm, et le
prochain git commit --amend prendra votre zone daente courante et en fera le contenu de
votre nouvelle consignation.
Vous devez tre prudent avec cee technique car votre modication modie galement le SHA1 du commit. Cela ressemble un tout petit rebase. Ne modiez pas votre dernire consignation
si vous lavez dj publi !
Souvenez-vous galement que ceci est une commande de rebasement, chaque commit include
dans lintervalle HEAD~3..HEAD sera rcrit, que vous changiez le message ou non. Nincluez
pas dans cee commande de commit que vous avez dj pouss sur un serveur central. Le faire
entrainera la confusion chez les autres dveloppeurs en leur fournissant une version altre des
mmes modications.
Excuter cee commande vous donne la liste des consignations dans votre diteur de texte, ce
qui ressemble :
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
Il est important de signaler que les commits sont lists dans lordre oppos que vous voyez normalement en utilisant la commande log. Si vous excutez la commande log, vous verrez quelque
chose de ce genre :
155
Au moment o vous sauvegardez et quiez lditeur, Git revient au dernier commit de cee
liste et vous laisse sur une ligne de commande avec le message suivant :
Cee commande appliquera les deux autres commits automatiquement, cest fait. Si vous remplacez pick en edit sur plusieurs lignes, vous pouvez rpter ces tapes pour chaque commit
que vous avez remplac pour modication. Chaque fois, Git sarrtera, vous laissant modier le
commit et continuera lorsque vous aurez ni.
Lorsque vous sauvegardez et quiez lditeur, Git remet votre branche au niveau du parent de
ces commits, applique 310154e puis f7f3f6d et sarrte. Vous venez de modier lordre de ces
commits et de supprimer entirement le commit added cat-le .
#
# Commands:
#
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
Si, la place de pick ou edit , vous spciez squash , Git applique cee modication
et la modication juste prcdente et fusionne les messages de consignation. Donc, si vous voulez
faire un seul commit de ces trois consignations, vous faites en sorte que le script ressemble ceci :
Lorsque vous sauvegardez et quiez lditeur, Git applique ces trois modications et vous remontre lditeur contenant maintenant la fusion des 3 messages de consignation :
157
Lorsque vous sauvegardez cela, vous obtenez un seul commit amenant les modications des
trois commits prcdents.
Puis, lorsque le script vous laissera accs la ligne de commande, vous annulerez (reset) ce commit, vous reprendrez les modications que vous voulez pour crer plusieurs commits. En reprenant
lexemple, lorsque vous sauvegardez et quiez lditeur, Git revient au parent de votre premier
commit de votre liste, applique le premier commit (f7f3f6d), applique le deuxime (310154e),
et vous laisse accs la console. L, vous pouvez faire une rinitialisation mlange (mixed reset)
de ce commit avec git reset HEAD, qui dfait ce commit et laisse les chiers modis non
mis en aente. Maintenant, vous pouvez mere en aente et consigner les chiers sur plusieurs
consignations, et excuter git rebase --continue quand vous avez ni :
Git applique le dernier commit (a5f4a0d) de votre script, et votre historique ressemblera
alors :
Une fois encore, ceci modie les empreintes SHA de tous les commits dans votre liste, soyez
donc sr quaucun commit de cee liste ait t pouss dans un dpt partag.
158
Loption --tree-filter excute la commande spcie pour chaque commit et les reconsigne ensuite Dans le cas prsent, vous supprimez le chier nomm passwords.txt de chaque
contenu, quil existait ou non. Si vous voulez supprimez tous les chiers temporaires des diteurs
consigns accidentellement, vous pouvez excuter une commande telle que git filter-branch
--tree-filter 'rm -f *~' HEAD.
Vous pourrez alors regarder Git rcrire larbre des commits et reconsigner chaque fois, pour
nir en modiant la rfrence de la branche. Cest gnralement une bonne ide de le faire dans
un branche de test puis de faire une forte rinitialisation (hard-reset) de votre branche master si
le rsultat vous convient. Pour excuter filter-branch sur toutes vos branches, vous pouvez
ajouter --all la commande.
Faire dun sous-rpertoire la nouvelle racine
Supposons que vous avez importer votre projet depuis un autre systme de gestion de conguration et que vous avez des sous-rpertoires qui nont aucun sens (trunk, tags, etc). Si vous voulez
faire en sorte que le sous-rpertoire trunk soit la nouvelle racine de votre projet pour tous les
commits, filter-branch peut aussi vous aider le faire :
Maintenant votre nouvelle racine est remplac par le contenu du rpertoire trunk. De plus,
Git supprimera automatiquement les commits qui naectent pas ce sous-rpertoire.
159
Cela passe sur chaque commit et le rcrit pour avoir votre nouvelle adresse. Mais puisque les
commits contiennent lempreinte SHA-1 de leur parent, cee commande modie tous les commits
dans votre historique, pas seulement ceux correspondant votre adresse mail.
160
end
Remarquez que le premier champ est le SHA-1 partiel du dernier commit a avoir modi la
ligne. Les deux champs suivants sont des valeurs extraites du commit : lauteur et la date du commit,
vous pouvez donc facilement voir qui a modi la ligne et quand. Ensuite arrive le numro de ligne
et son contenu. Remarquez galement les lignes dont le commit est 4832fe2, elles dsignent les
lignes qui taient dans la version du chier lors du premier commit de ce chier. Ce commit contient
le premier ajout de ce chier, et ces lignes nont pas t modies depuis. Tout a est un peu confus,
parce que vous connaissez maintenant au moins trois faons direntes que Git interprte pour
modier lempreinte SHA, mais au moins, vous savez ce quil signie ici.
Une autre chose sympa sur Git, cest quil ne suit pas explicitement les renommages de chier.
Il enregistre les contenus puis essaye de deviner ce qui a t renomm implicitement, aprs coup.
Ce qui nous permet dutiliser cee fonctionnalit intressante pour suivre toute sorte de mouvement de code. Si vous passez -C git blame, Git analyse le chier que vous voulez annoter
et essaye de devenir do les bouts de code proviennent par copie ou dplacement. Rcemment,
jai remani un chier nomm GITServerHandler.m en le divisant en plusieurs chiers, dont
le chier GITPackUpload.m. En annotant GITPackUpload.m avec loption -C, je peux voir
quelles sections de code en est originaire :
//NSLog(@"GATHER COMMI
ad11ac80 GITPackUpload.m
ad11ac80 GITPackUpload.m
NSString *parentSha;
ad11ac80 GITPackUpload.m
GITCommit *commit = [g
ad11ac80 GITPackUpload.m
ad11ac80 GITPackUpload.m
ad11ac80 GITPackUpload.m
//NSLog(@"GATHER COMMI
if(commit) {
[refDict setOb
Cest vraiment utile, non ? Normalement, vous obtenez comme commit original, celui dont
votre code a t copi, puisque ce fut la premire fois que vous avez touch ces lignes dans ce
chier. Git vous montre le commit dorigine, celui o vous avez crit ces lignes, mme si ctait dans
un autre chier.
Disons que vous venez juste de pousser une version nale de votre code en production, vous
rcuprez un rapport de bogue propos de quelque chose qui narrivait pas dans votre environnement de dveloppement, et vous narrivez pas trouver pourquoi votre code le fait. Vous retournez sur votre code, et il apparait que vous pouvez reproduire le bogue, mais vous ne savez pas
ce qui se passe mal. Vous pouvez faire une recherche par dichotomie pour trouver ce qui ne va pas.
Dabord, excutez git bisect start pour dmarrer la procdure, puis utilisez la commande
git bisect bad pour dire que le commit courant est bogu. Ensuite, dites bisect quand le
code fonctionnait, en utilisant git bisect good [bonne_version] :
Git trouve quil y a environ 12 commits entre celui que vous avez marqu comme le dernier bon
connu (v1.0) et la version courante qui nest pas bonne, et il a rcupr le commit au milieu votre
place. ce moment, vous pouvez drouler vos tests pour voir si le bogue existait dans ce commit.
Si cest le cas, il a t introduit quelque part avant ce commit mdian, sinon, il la t videmment
introduit aprs. Il apparait que le bogue ne se reproduit pas ici, vous le dites Git en tapant git
bisect good et continuez votre priple :
Vous tes maintenant sur un autre commit, mi-chemin entre celui que vous venez de tester et
votre commit bogu. Vous excutez une nouvelle fois votre test et trouvez que ce commit est bogu,
vous le dites Git avec git bisect bad :
Ce commit-ci est bon, et Git a maintenant toutes les informations dont il a besoin pour dterminer o le bogue a t cr. Il vous ache le SHA-1 du premier commit bogu, quelques informations du commit et quels chiers ont t modis dans celui-ci, vous pouvez donc trouver ce qui
sest pass pour crer ce bogue :
162
Date:
config
Lorsque vous avez ni, vous devez excuter git bisect reset pour rinitialiser votre
HEAD o vous tiez avant de commencer, ou vous travaillerez dans un rpertoire de travail non
clairement dni :
Cest un outil puissant qui vous aidera vrier des centaines de commits en quelques minutes. En ralit, si vous avez un script qui sort avec une valeur 0 sil est bon et autre chose sinon,
vous pouvez mme automatiser git bisect. Premirement vous lui spciez lintervalle en lui
fournissant les bon et mauvais commits connus. Vous pouvez faire cela en une ligne en les entrant
la suite de la commande bisect start, le mauvais commit dabord :
Cela excute automatiquement test-error.sh sur chaque commit jusqu ce que Git trouve
le premier commit bogu. Vous pouvez galement excuter des commandes comme make ou make
tests ou quoique ce soit qui excute des tests automatiss votre place.
6.6 Sous-modules
Il arrive souvent lorsque vous travaillez sur un projet, que vous devez utilisez un autre projet
comme dpendance. Cela peut tre une librairie qui est dveloppe par une autre quipe ou que
vous dveloppez sparemment pour lutiliser dans plusieurs projets parents. Ce scnario provoque
un problme habituel : vous voulez tre capable de grer deux projets spars tout en utilisant un
dans lautre.
Voici un exemple. Supposons que vous dveloppez un site web et que vous crez des ux Atom.
Plutt que dcrire votre propre code de gnration Atom, vous dcidez dutiliser une librairie. Vous
allez vraisemblablement devoir soit inclure ce code depuis un gestionnaire partag comme CPAN
ou Ruby gem, soit copier le code source dans votre propre arborescence de projet. Le problme
dinclure la librairie en tant que librairie externe est quil est dicile de la personnaliser de quelque
manire que ce soit et encore plus de la dployer, car vous devez vous assurer de la disponibilit de
la librairie chez chaque client. Mais le problme dinclure le code dans votre propre projet est que
nimporte quelle personnalisation que vous faites est dicile fusionner lorsque les modications
du dveloppement principal arrivent.
163
Git gre ce problme avec les sous-modules. Les sous-modules vous permeent de grer un
dpt Git comme un sous-rpertoire dun autre dpt Git. Cela vous laisse la possibilit de cloner
un dpt dans votre projet et de garder isols les commits de ce dpt.
Vous avez maintenant le projet Rack dans le sous-rpertoire rack lintrieur de votre propre
projet. Vous pouvez aller dans ce sous-rpertoire, eectuer des modications, ajouter votre propre
dpt distant pour y pousser vos modications, rcuprer et fusionner depuis le dpt originel, et
plus encore. Si vous excutez git status juste aprs avoir ajouter le sous-module (donc dans le
rpertoire parent du rpertoire rack), vous verrez deux choses :
$ git status
# On branch master
# Changes to be committed:
#
#
#
new file:
.gitmodules
new file:
rack
$ cat .gitmodules
[submodule "rack"]
path = rack
url = git://github.com/chneukirchen/rack.git
Si vous avez plusieurs sous-modules, vous aurez plusieurs entres dans ce chier. Il est important de noter que ce chier est en gestion de version comme vos autres chiers, linstar de
votre chier .gitignore. Il est pouss et tir comme le reste de votre projet. Cest galement le
164
moyen que les autres personnes qui clonent votre projet peuvent savoir o rcuprer le projet du
sous-module.
Lautre information dans la sortie de git status est lentre rack. Si vous excutez git
diff, vous verrez quelque chose dintressant :
Mme si rack est un sous rpertoire de votre rpertoire de travail, Git le voit comme un
sous-module et ne suit pas son contenu (si vous ntes pas dans ce rpertoire). En change, Git
lenregistre comme un commit particulier de ce dpt. Lorsque vous faites des modications et des
consignations dans ce sous-rpertoire, le super-projet (le projet contenant le sous-module) remarque
que la branche HEAD a chang et enregistre le commit exacte dans lequel il se trouve ce moment.
De cee manire, lorsque dautre clone ce super-projet, ils peuvent recrer exactement le mme
environnement.
Un autre point important avec les sous-modules : Git enregistre le commit exact o ils se trouvent. Vous ne pouvez pas enregistrer un module comme tant en branche master ou nimporte
quelle autre rfrence symbolique.
Au moment de commiter, vous voyez quelque chose comme :
Remarquez le mode 160000 pour lentre rack. Cest un mode spcial de Git qui signie globalement que vous tes en train denregistrer un commit comme un rpertoire plutt quun sousrpertoire ou un chier.
Vous pouvez traiter le rpertoire rack comme un projet spar et mere jour votre superprojet de temps en temps avec une rfrence au dernier commit de ce sous-projet. Toutes les commandes Git fonctionnent indpendamment dans les deux rpertoires :
$ git log -1
commit 0550271328a0038865aad6331e620cd7238601bb
Author: Scott Chacon <schacon@gmail.com>
Date:
165
$ git log -1
commit 08d709f78b8c5b0fbeb7821e37fa53e69afcf433
Author: Christian Neukirchen <chneukirchen@gmail.com>
Date:
1 schacon
drwxr-xr-x
admin
2 schacon
admin
3 Apr
9 09:11 README
68 Apr
9 09:11 rack
$ ls rack/
$
Le rpertoire rack est prsent mais vide. Vous devez excuter deux commandes : git submodule init pour initialiser votre chier local de conguration, et git submodule update
pour tirer toutes les donnes de ce projet et rcuprer le commit appropri tel que list dans votre
super-projet :
Votre rpertoire rack est maintenant dans ltat exacte dans lequel il tait la dernire fois
que vous avez consign. Si un autre dveloppeur modie le code de rack et consigne, que vous
rcupriez (pull) cee rfrence et que vous fusionniez, vous obtiendrez quelque chose dun peu
trange :
166
2 +-
#
#
modified:
rack
En ralit, vous navez fusionn que la modication de la rfrence de votre sous-module, mais
Git na pas mis jour le code dans le rpertoire du sous-module, de ce fait, cela ressemble un tat
en cours dans votre rpertoire de travail :
$ git diff
diff --git a/rack b/rack
index 6c5e70b..08d709f 160000
--- a/rack
+++ b/rack
@@ -1 +1 @@
-Subproject commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
+Subproject commit 08d709f78b8c5b0fbeb7821e37fa53e69afcf433
La cause de tout cela, cest que la rfrence pour votre sous-module ne correspond pas ce
quil y a actuellement dans son rpertoire. Pour corriger a, vous devez excuter un nouvelle fois
git submodule update :
master
-> origin/master
Vous devez faire cela chaque fois que vous rcuprez une modication du sous-module dans
le projet principal. Cest trange, mais a fonctionne.
Un problme habituel peut survenir lorsquun dveloppeur modie localement un sous-module,
mais ne le pousse pas sur un serveur public. Puis, il consigne une rfrence cet tat non public et
pousse le super-projet. Lorsque les autres dveloppeurs excutent git submodule update, le
systme dans le sous-module ne trouve pas le commit qui est rfrenc, car il existe uniquement sur
le systme du premier dveloppeur. Dans ce cas, vous verrez une erreur de ce style :
167
6.6.3 Superprojects
Parfois, les dveloppeurs dsirent sparer un gros projet en sous-rpertoires en fonction de
lquipe qui travaille dessus. Cest logique que si vous venez de CVS ou de Subversion, o vous
aviez lhabitude de dnir un module ou un ensemble de sous-rpertoires, que vous vouliez garder
ce type de workow.
Une bonne manire de le faire avec Git est de crer un dpt Git pour chaque sous-dossiers,
et de crer un super-projet contenant les dirents modules. Le bnce de cee approche est de
pouvoir spcier les relations entre les projets avec des tiquees et des branches depuis le superprojet.
Commuter de branches qui contiennent des sous-modules peut galement savrer dicile. Si
vous crez une nouvelle branche, y ajoutez un sous-module, et revenez ensuite une branche sans
ce sous-module, vous aurez toujours le rpertoire de ce sous-module comme un rpertoire non suivi
:
#
#
rack/
Vous devez soit dplacer ce rpertoire hors de votre dpt local, soit le supprimer, dans ce
dernier ca, vous devrait le clner une nouvelle fois lorsque vous recommuterez et vous pouvez donc
perdre des modications ou des branches locales si vous ne les avez pas pousses.
Le dernier pige dans lequel beaucoup tombe est de passer des sous-rpertoires des sousmodules. Si vous suiviez des chiers dans votre projet et que vous voulez les dplacer dans un sousmodule, vous devez tre trs prudent, ou Git vous mangera. Prsumons que vous avez des chiers
rack dans un sous-rpertoire de votre projet, et que vous voulez les transformer en un sous-module.
Si vous supprimez le sous-rpertoire et que vous excutez submodule add, Git vous hurle dessus
avec :
$ rm -Rf rack/
$ git submodule add git@github.com:schacon/rack.git rack
'rack' already exists in the index
Vous devez dabord supprimer le rpertoire rack de la zone daente. Vous pourrez ensuite
ajouter le sous-module :
$ git rm -r rack
$ git submodule add git@github.com:schacon/rack.git rack
Initialized empty Git repository in /opt/testsub/rack/.git/
remote: Counting objects: 3184, done.
169
Maintenant, supposons que vous avez fait cela dans une branche. Si vous essayer de commuter
dans une ancienne branche o ces chiers sont toujours dans larbre de projet plutt que comme
sous-module, vous aurez cee erreur :
Vous devez dplacer le rpertoire du sous-module rack en dehors de votre dpt local avant
de pouvoir commuter vers une branche qui ne la pas :
$ mv rack /tmp/
$ git checkout master
Switched to branch "master"
$ ls
README rack
Puis, lorsque vous recommutez, vous aurez un rpertoire rack vide. Vous pouvez soit excuter git submodule update pour clner une nouvelle fois, ou vous pouvez remere votre
rpertoire /tmp/rack dans votre rpertoire vide.
you specify a subtree merge, Git is smart enough to gure out that one is a subtree of the other and
merge appropriately cest assez bluant.
Premirement, vous ajoutez lapplication Rack votre projet. Vous ajoutez le projet Rack comme
une rfrence distante dans votre propre projet et rcuprez dans un branche personnelle :
build
* [new branch]
master
-> rack_remote/build
-> rack_remote/master
* [new branch]
rack-0.4
-> rack_remote/rack-0.4
* [new branch]
rack-0.9
-> rack_remote/rack-0.9
Vous avez maintenant la racine du projet Rack dans votre branche rack_branch et votre
propre projet dans la branche master. Si vous rcuprez lune puis lautre branche, vous pouvez
voir que vous avez direntes racines de projet :
$ ls
AUTHORS
KNOWN-ISSUES
Rakefile
contrib
lib
COPYING
README
bin
example
test
Pour tirer le projet Rack dans votre projet master comme un sous rpertoire, vous pouvez
utiliser la commande git read-tree. Vous apprendrez davantage sur read-tree et compagnie dans le Chapitre 9, mais pour le moment, sachez quil lit la racine dune de vos branche
et linscrit dans votre zone daente et votre rpertoire de travail. Vous venez juste de commuter
vers votre branche master, et vous tirez la branche rack vers le sous-rpertoire rack de votre
branche master de votre projet principal :
Au moment de consigner, vous verrez tout les chiers de Rack de ce sous-rpertoire, comme si
vous les aviez copi depuis une archive. Ce qui est intressant, cest que vous pouvez assez facilement
fusionner les changements dune branche lautre. Par consquence, sil y a des mises jour pour
171
le projet Rack, vous pouvez les tirez depuis le dpt principal en commutant dans cee branche et
tirant les modications :
Puis, vous pouvez fusionner ces changements dans votre branche principale. Vous pouvez
utiliser git merge -s subtree et cela fonctionnera, mais Git fusionnera galement les historiques ensemble, ce que vous ne voulez probablement pas. Pour tirer les changements et prremplir le message de consignation, utilisez les options --squash et --no-commit avec loption de
stratgie -s subtree :
Toutes les modications de votre projet Rack sont fusionn et prtes tre consignes localement. Vous pouvez galement faire le contraire, faire des modications dans le sous-rpertoire rack
de votre branche principale et les fusionner plus tard dans votre branche rack_branch pour les
envoyer aux mainteneurs du projet Rack ou les pousser dans le dpt principal.
Pour voir les dirences entre ce que vous avez dans le sous-rpertoire rack et le code de
la branche rack_branch (pour savoir si vous devez les fusionner), vous ne pouvez pas utiliser
la commande diff habituelle. Vous devez plutt excutez git diff-tree en renseignant la
branche avec laquelle vous voulez comparer :
Ou, pour comparer ce quil y a dans votre rpertoire rack avec ce quil y avait sur le server la
dernire fois que vous avez vri, vous pouvez excuter :
6.8 Rsum
Vous venez de voir certains des outils avancs vous permeant de manipuler vos consignations
et votre zone daente plus prcisemment. Lorsque vous remarquez des bogues, vous devriez tre
capable de facilement trouver quelle consignation les a introduits, quand et par qui. Si vous voulez
utiliser des sous-projets dans votre projet, vous avez appris plusieurs faons de les grer. partir
de maintenant, vous devez tre capable de faire la majorit de ce que vous avez besoin avec Git en
ligne de commande et de vous y sentir laise.
172
Chapitre 7
Personnalisation de Git
Jusquici, nous avons trait les bases du fonctionnement et de lutilisation de Git et introduit
un certain nombre doutils fournis par Git pour travailler plus facilement et plus ecacement.
Dans ce chapitre, nous aborderons quelques oprations permeant dutiliser Git de manire plus
personnalise en vous prsentant quelques paramtres de conguration importants et le systme
dinterceptions. Grce ces outils, il devient enfantin de faire fonctionner Git exactement comme
vous, votre socit ou votre communaut en avez besoin.
prsent, vous allez apprendre quelques unes des options similaires les plus intressantes pour
paramtrer votre usage de Git.
Vous avez vu des dtails de conguration simple de Git au premier chapitre, mais nous allons
les rviser. Git utilise une srie de chiers de conguration pour dterminer son comportement
selon votre personnalisation. Le premier endroit que Git visite est le chier /etc/gitconfig
qui contient des valeurs pour tous les utilisateurs du systme et tous leurs dpts. Si vous passez
loption --system git config, il lit et crit ce chier.
Lendroit suivant visit par Git est le chier ~/.gitconfig qui est spcique chaque utilisateur. Vous pouvez faire lire et crire Git dans ce chier au moyen de loption --global.
Enn, Git recherche des valeurs de conguration dans le chier de conguration du rpertoire
Git (.git/config) du dpt en cours dutilisation. Ces valeurs sont spciques un unique dpt.
Chaque niveau surcharge le niveau prcdent, ce qui signie que les valeurs dans .git/config
crasent celles dans /etc/gitconfig. Vous pouvez positionner ces valeurs manuellement en
ditant le chier et en utilisant la syntaxe correcte, mais il reste gnralement plus facile de lancer
la commande git config.
173
La page de manuel pour git config liste aussi les options disponibles avec un bon niveau
de dtail.
core.editor
Par dfaut, Git utilise votre diteur par dfaut ou se replie sur lditeur Vi pour la cration et
ldition des messages de validation et de balisage. Pour modier ce comportement par dfaut pour
un autre, vous pouvez utiliser le paramtre core.editor :
Maintenant, quelque soit votre diteur par dfaut, Git dmarrera Emacs pour diter les messages.
commit.template
Si vous rglez ceci sur le chemin dun chier sur votre systme, Git utilisera ce chier comme
message par dfaut quand vous validez. Par exemple, supposons que vous crez un chier modle
dans $HOME/.gitmessage.txt qui ressemble ceci :
ligne de sujet
description
[ticket: X]
Pour indiquer Git de lutiliser pour le message par dfaut qui apparatra dans votre diteur
quand vous lancerez git commit, rglez le paramtre de conguration commit.template :
174
Ainsi, votre diteur ouvrira quelque chose ressemblant ceci comme modle de message de
validation :
ligne de sujet
description
[ticket: X]
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
#
#
# modified:
lib/test.rb
#
~
~
".git/COMMIT_EDITMSG" 14L, 297C
Si vous avez une rgle de messages de validation, placer un modle de cee rgle sur votre
systme et congurer Git pour quil lutiliser par dfaut amliorera les chances que cee rgle soit
eectivement suivie.
core.pager
Le paramtre core.pager dtermine quel pager est utilis lorsque des pages de Git sont
mises, par exemple lors dun log ou dun diff. Vous pouvez le xer more ou votre pager
favori (par dfaut, il vaut less) ou vous pouvez le dsactiver en xant sa valeur une chane vide :
si vous lancez cela, Git achera la totalit du rsultat de toutes les commandes dune traite,
quelle que soit sa longueur.
user.signingkey
Si vous fates des balises annotes signes (comme dcrit au chapitre 2), simpliez-vous la vie
en dnissant votre cl GPG de signature en paramtre de conguration. Dnissez votre ID de cl
ainsi :
Maintenant, vous pouvez signer vos balises sans devoir spcier votre cl chaque fois la
commande git tag :
175
core.excludesle
Comme dcrit au chapitre 2, vous pouvez ajouter des patrons dans le chier .gitignore
de votre projet pour indiquer Git de ne pas considrer certains chiers comme non suivis ou les
indexer lorsque vous lancez git add sur eux. Cependant, si vous souhaitez quun autre chier
lextrieur du projet contiennent ces informations ou dautres supplmentaires, vous pouvez indiquer Git o se trouve ce chier grce au paramtre core.excludesfile. Fixez le simplement
sur le chemin du chier qui contient les informations similaires celles de .gitignore.
help.autocorrect
Cee option nest disponible qu partir de la version 1.6.1. Si vous avez fait une faute de frappe
en tapant une commande dans Git 1.6, il vous achera une liste de commandes ressemblantes :
$ git com
git: 'com' is not a git-command. See 'git --help'.
Did you mean this?
commit
Avec cee valeur du paramtre, Git colorise sa sortie si celle-ci est destine un terminal.
Dautres rglages possibles sont false qui dsactive compltement la colorisation et always qui
active la colorisation, mme si vous envoyez la commande Git dans un chier ou lentre dune autre
commande. Ce rglage a t ajout dans Git 1.5.5. Si vous avez une version antrieure, vous devrez
spcier les rgles de colorisation individuellement.
176
color.ui = always est rarement utile. Dans les plupart des cas, si vous tenez vraiment
coloriser vos sorties rediriges, vous pourrez passer le drapeau --color la commande Git pour
la forcer utiliser les codes de couleur. Le rglage color.ui = true est donc le plus utilis.
color.*
Si vous souhaitez tre plus spcique concernant les commandes colorises ou si vous avez
une ancienne version, Git propose des paramtres de colorisation par action. Chacun peut tre x
true, false ou always.
color.branch
color.diff
color.interactive
color.status
De plus, chacun dentre eux dispose dun sous-ensemble de paramtres qui permeent de surcharger les couleurs pour des parties des achages. Par exemple, pour rgler les couleurs de mtainformations du di avec une criture en bleu gras (bold en anglais) sur fond noir :
La couleur peut prendre les valeurs suivantes : normal, bla, red, green, yellow, blue, magenta,
cyan ou white. Si vous souhaitez ajouter un aribut de casse, les valeurs disponibles sont bold (gras),
dim (lger), ul (underlined, soulign), blink (clignotant) et reverse (invers).
Rfrez-vous la page de manuel de git config pour tous les sous-rglages disponibles.
177
$ cat /usr/local/bin/extMerge
#!/bin/sh
/Applications/p4merge.app/Contents/MacOS/p4merge $*
Lenveloppe di sassure que sept arguments ont t fournis et en passe deux votre script de
fusion. Par dfaut, Git passe au programme de di les arguments suivants :
$ cat /usr/local/bin/extDiff
#!/bin/sh
[ $# -eq 7 ] && /usr/local/bin/extMerge "$2" "$5"
Vous devez aussi vous assurer que ces outils sont excutables :
prsent, vous pouvez rgler votre chier de conguration pour utiliser vos outils personnaliss de rsolution de fusion et de dirence. Pour cela, il faut un certain nombre de personnalisations : merge.tool pour indiquer Git quelle stratgie utiliser, mergetool.*.cmd pour spcier comment lancer cee commande, mergetool.trustExitCode pour indiquer Git si le
code de sortie du programme indique une rsolution de fusion russie ou non et diff.external
pour indiquer Git quelle commande lancer pour les dirences. Ainsi, vous pouvez lancer les
quatre commandes
ou vous pouvez diter votre chier ~/.gitconfig pour y ajouter ces lignes :
[merge]
tool = extMerge
[mergetool "extMerge"]
178
Aprs avoir rgl tout ceci, si vous lancez des commandes de di telles que celle-ci :
Au lieu dobtenir la sortie du di dans le terminal, Git lance P4Merge, ce qui ressemble la
Figure 7.1.
Si vous essayez de fusionner deux branches et crez des conits de fusion, vous pouvez lancer
la commande git mergetool qui dmarrera P4Merge pour vous laisser rsoudre les conits au
moyen dun outil graphique.
Le point agrable avec cee mthode denveloppe est que vous pouvez changer facilement
doutils de di et de fusion. Par exemple, pour changer vos outils extDiff et extMerge pour
une utilisation de loutil KDi3, il vous sut dditer le chier extMerge :
$ cat /usr/local/bin/extMerge
#!/bin/sh
/Applications/kdiff3.app/Contents/MacOS/kdiff3 $*
prsent, Git va utiliser loutil KDi3 pour visualiser les dirences et rsoudre les conits de
fusion.
Git est livr prrgl avec un certain nombre dautres outils de rsolution de fusion pour vous
viter davoir grer la conguration cmd. Vous pouvez slectionner votre outil de fusion parmi
kdiff3, opendiff, tkdiff, meld, xxdiff, emerge, vimdiff ou gvimdiff. Si KDi3 ne
vous intresse pas pour grer les dirences mais seulement pour la rsolution de fusion et quil est
prsent dans votre chemin dexcution, vous pouvez lancer
179
Si vous lancez ceci au lieu de modier les chiers extMerge ou extDiff, Git utilisera KDif3
pour les rsolutions de fusion et loutil di normal de Git pour les dirences.
Si vous utilisez un systme Linux ou Mac qui utilise les ns de ligne LF, vous ne souhaitez srement pas que Git les convertisse automatiquement lorsque vous extrayez des chiers. Cependant,
si un chier contenant des CRLF est accidentellement introduit en version, vous souhaitez que Git
le corrige . Vous pouvez indiquer Git de convertir CRLF en LF lors de la validation mais pas dans
lautre sens en xant core.autocrlf input :
Ce rglage devrait donner des ns de ligne en CRLF lors dextraction sous Windows mais en
LF sous Mac et Linux et dans le dpt.
180
Si vous tes un programmeur Windows grant un projet spcique Windows, vous pouvez
dsactiver cee fonctionnalit et forcer lenregistrement des retour chariot dans le dpt en
rglant la valeur du paramtre false :
core.whitespace
Git est paramtr par dfaut pour dtecter et corriger certains problmes de blancs. Il peut
rechercher quatre problmes de base de blancs. La correction de deux problmes est active par
dfaut et peut tre dsactive et celle des deux autres nest pas active par dfaut mais peut tre
active.
Les deux actives par dfaut sont trailing-space qui dtecter les espaces en n de ligne
et space-before-tab qui recherche les espaces avant les tabulations au dbut dune ligne.
Les deux autres qui sont dsactives par dfaut mais peuvent tre actives sont indentwith-non-tab qui recherche des lignes qui commencent par huit espaces ou plus au lieu de
tabulations et cr-at-eol qui indique Git que les retour chariot en n de ligne sont accepts.
Vous pouvez indiquer Git quelle correction vous voulez activer en xant core.whitespace
avec les valeurs que vous voulez ou non, spares par des virgules. Vous pouvez dsactiver des
rglages en les liminant de la chane de paramtrage ou en les prxant avec un -. Par exemple, si
vous souhaiter activer tout sauf cr-at-eol, vous pouvez lancer ceci :
Git va dtecter ces problmes quand vous lancez une commande git diff et essayer de les
coloriser pour vous permere de les rgler avant de valider. Il utilisera aussi ces paramtres pour
vous aider quand vous appliquerez des patchs avec git apply. and vous appliquez des patchs,
vous pouvez paramtrer Git pour quil vous avertisse sil doit appliquer des patchs qui prsentent
les dfauts de blancs :
Ces options sappliquent aussi git rebase. Si vous avez valid avec des problmes de
blancs mais navez pas encore pouss en amont, vous pouvez lancer un rebase avec loption -whitespace=fix pour faire corriger Git les erreurs de blancs pendant quil rcrit les patchs.
181
Maintenant, Git va vrier lintgrit de votre dpt avant que chaque pousse ne soit accepte
pour sassurer que des clients dfectueux nintroduisent pas des donnes corrompues.
receive.denyNonFastForwards
Si vous rebasez des commits que vous avez dj pousss, puis essayez de pousser nouveau,
ou inversemement, si vous essayez de pousser un commit sur une branche distante qui ne contient
pas le commit sur lequel la branche distante pointe, votre essai chouera. Cest gnralement une
bonne politique, mais dans le cas dun rebasage, vous pouvez dcider que vous savez ce que vous
fates et forcer la mise jour de la branche distante en ajoutant loption -f votre commande.
Pour dsactiver la possibilit de forcer la mise jour des branches distantes vers des rfrences
pas en avance rapide, rglez receive.denyNonFastForwards :
Lautre moyen dobtenir ce rsultat rside dans les crochets de rception ct-serveur, qui
seront abords en seconde partie. Cee approche vous permet de faire des choses plus complexes
tel quinterdire les modications sans avance rapide un certain groupe dutilisateurs.
receive.denyDeletes
Un contournement possible de la politique denyNonFastForwards consiste eacer la
branche puis la repousser avec ses nouvelles rfrences. Dans les versions les plus rcentes de Git
( partir de la version 1.6.1), vous pouvez rgler receive.denyDeletes true :
Cela interdit totalement leacement de branche et de balise. Aucun utilisateur nen a le droit.
Pour pouvoir eacer des branches distantes, vous devez eacer manuellement les chiers de rfrence
182
sur le serveur. Il existe aussi des moyens plus intressants de grer cee politique utilisateur par
utilisateur au moyen des listes de contrle daccs, point qui sera abord la n de ce chapitre.
prsent, Git nessaiera pas de convertir ou de corriger les problmes des CRLF, ni de calculer
ou dacher les dirences pour ces chiers quand vous lancez git show ou git di sur votre projet.
Dans la branche 1.6 de Git, vous pouvez aussi utiliser une macro fournie qui signie -crlf -diff :
*.pbxproj binary
183
$ git diff
diff --git a/chapter1.doc b/chapter1.doc
index 88839c4..4afcb7c 100644
Binary files a/chapter1.doc and b/chapter1.doc differ
Vous ne pouvez pas comparer directement les versions moins de les extraire et de les parcourir
manuellement. En fait, vous pouvez faire la mme chose plutt bien en utilisant les aributs Git.
Ajoutez la ligne suivante dans votre chier .gitattributes :
*.doc diff=word
Cee ligne indique Git que tout chier correspondant au patron (.doc) doit utiliser le ltre
word pour visualiser le di des modications. est-ce que le ltre word ? Nous devons le
dnir. Vous allez congurer Git utiliser le programme strings pour convertir les documents
Word en chiers texte lisibles quil pourra alors comparer correctement :
prsent, Git sait que sil essaie de faire un di entre deux instantans et quun des chiers
nit en .doc, il devrait faire passer ces chiers par le ltre word dnit comme le programme
strings. Cee mthode fait eectivement des jolies versions texte de vos chiers Word avant
dessayer de les comparer.
Voici un exemple. Jai mis le chapitre 1 de ce livre dans Git, ajout du texte un paragraphe et
sauvegard le document. Puis, jai lanc git diff pour visualiser ce qui a chang :
$ git diff
diff --git a/chapter1.doc b/chapter1.doc
index c1c8a0a..b93c9e4 100644
--- a/chapter1.doc
+++ b/chapter1.doc
184
@@ -8,7 +8,8 @@ re going to cover Version Control Systems (VCS) and Git basics
re going to cover how to get it and set it up for the first time if you don
t already have it on your system.
In Chapter Two we will go over basic Git usage - how to use Git for the 80%
-s going on, modify stuff and contribute changes. If the book spontaneously
+s going on, modify stuff and contribute changes. If the book spontaneously
+Let's see if this works.
Git russit mindiquer succinctement que jai ajout la chane Lets see if this works , ce qui
est correct. Ce nest pas parfait, car il y a toujours un tas de donnes alatoires la n, mais cest
susant. Si vous tes capable dcrire un convertisseur Word vers texte qui fonctionne susamment
bien, cee solution peut savrer trs ecace. Cependant, strings est disponible sur la plupart
des systmes Mac et Linux et peut donc constituer un bon dbut pour de nombreux formats binaires.
Un autre problme intressant concerne la comparaison de chiers dimages. Une mthode
consiste faire passer les chiers JPEG travers un ltre qui extrait les donnes EXIF, les mtadonnes enregistres avec la plupart de formats dimage. Si vous tlchargez et installez le programme exiftool, vous pouvez lutiliser pour convertir vos images en texte de mta-donnes
de manire que le di puisse au moins montrer une reprsentation textuelle des modications pratiques :
Si vous remplacez une image dans votre projet et lancez git diff, vous verrez ceci :
: 7.74
-File Size
: 70 kB
: 2009:04:21 07:02:45-07:00
+File Size
: 94 kB
: 2009:04:21 07:02:43-07:00
File Type
: PNG
MIME Type
: image/png
-Image Width
: 1058
-Image Height
: 889
+Image Width
: 1056
+Image Height
: 827
Bit Depth
: 8
Color Type
Vous pouvez raliser rapidement que la taille du chier et les dimensions des images ont toutes
deux chang.
185
$ rm text.txt
$ git checkout -- text.txt
$ cat test.txt
$Id: 42812b7653c7b88933f8a9d6cad0ca16714b9bb3 $
Nanmoins, ce rsultat na que peu dintrt. Si vous avez utilis la substitution avec CVS ou
Subversion, il est possible dinclure la date. Le code SHA nest pas des plus utiles car il est plutt
alatoire et ne vous permet pas de distinguer si tel SHA est plus rcent ou ancien que tel autre.
Il apparat que vous pouvez crire vos propres ltres pour raliser des substitutions dans les
chiers lors des validations/extractions. Ces ltres sappellent clean et smudge . Dans le chier
.gitattributes, vous pouvez indiquer un ltre pour des chemins particuliers puis crer des
scripts qui traiterons ces chiers avant quils soient valids ( clean , voir gure 7-2) et juste avant
quil soient extraits ( smudge , voir gure 7-3). Ces ltres peuvent servir faire toutes sortes de
choses arayantes.
186
Figure 7.3: Le ltre clean est lanc lorsque les iers sont indexs.
Le message de validation dorigine pour cee fonctionnalit donne un exemple simple permeant de passer tout votre code C par le programme indent avant de valider. Vous pouvez le faire
en rglant laribut filter dans votre chier .gitattributes pour ltrer les chiers *.c
avec le ltre indent :
*.c
filter=indent
Ensuite, indiquez Git ce que le ltre indent fait sur smudge et clean :
Dans ce cas, quand vous validez des chiers qui correspondent *.c, Git les fera passer par
le programme indent avant de les valider et les fera passer par le programme cat avant de les
extraire sur votre disque. Le programme cat ne fait rien : il se contente de rgurgiter les donnes
telles quil les a lues. Cee combinaison ltre eectivement tous les chiers de code source C par
indent avant leur validation.
Un autre exemple intressant fournit lexpansion du mot-cl $Date$ dans le style RCS. Pour
le raliser correctement, vous avez besoin dun petit script qui prend un nom de chier, calcule la
date de la dernire validation pour le projet et linsre dans le chier. Voici un petit script Ruby qui
le fait :
#! /usr/bin/env ruby
data = STDIN.read
last_date = `git log --pretty=format:"%ad" -1`
puts data.gsub('$Date$', '$Date: ' + last_date.to_s + '$')
Tout ce que le script fait, cest rcuprer la date de la dernire validation partir de la commande
git log, la coller dans toutes les chanes $Date$ quil trouve et acher le rsultat. Ce devrait
tre simple dans nimporte quel langage avec lequel vous tes laise. Si vous appelez ce chier
expand_date et que vous le placez dans votre chemin. prsent, il faut paramtrer un ltre dans
187
Git (appelons le dater) et lui indiquer dutiliser le ltre expand_date en tant que smudge sur
les chiers extraire. Nous utiliserons une expression Perl pour neoyer lors dune validation :
Cee commande Perl extrait tout ce quelle trouve dans une chane $Date$ et la rinitialise.
Le ltre prt, on peut le tester en crivant le mot-cl $Date$ dans un chier, puis en crant un
aribut Git pour ce chier qui fait rfrence au nouveau ltre :
Si vous validez ces modications et extrayez le chier nouveau, vous remarquez le mot-cl
correctement substitu :
Vous pouvez voir quel point cee technique peut tre puissante pour des applications personnalises. Il faut rester nanmoins vigilant car le chier .gitattributes est valid et inclus
dans le projet tandis que le gestionnaire (ici, dater) ne lest pas. Du coup, a ne marchera pas
partout. Lorsque vous crez ces ltres, ils devraient pouvoir avoir un mode dgrad qui nempche
pas le projet de fonctionner.
188
test/ export-ignore
prsent, quand vous lancez git archive pour crer une archive tar de votre projet, ce rpertoire ne sera plus inclus dans larchive.
export-subst
Une autre chose faire pour vos archives est une simple substitution de mots-cls. Git vous
permet de placer la chane $Format:$ dans nimporte quel chier avec nimporte quel code de
format du type --pretty=format que vous avez pu voir au chapitre 2. Par exemple, si vous
voulez inclure un chier appel LAST_COMMIT dans votre projet et y injecter automatiquement la
date de dernire validation lorsque git archive est lanc, vous pouvez crer un chier comme
ceci :
and vous lancez git archive, le contenu de ce chier inclus dans larchive ressemblera
ceci :
$ cat LAST_COMMIT
Last commit date: $Format:Tue Apr 21 08:38:48 2009 -0700$
database.xml merge=ours
Si vous fusionnez dans une autre branche, plutt que de rencontrer des conits de fusion avec
le chier database.xml, vous verrez quelque chose comme :
189
Dans ce cas, database.xml reste dans ltat dorigine, quel quil soit.
dfaut avant que lauteur ne le voit. Ce crochet accepte quelques options : le chemin du chier qui
contient le message de validation actuel, le type de validation et le SHA-1 du commit si cest un
commit amend. Ce crochet ne sert gnralement rien pour les validations normales. Par contre,
il est utile pour les validations o le message par dfaut est gnr, tel que les modles de message
de validation, les validations de fusion, les commits crass ou amends. Vous pouvez lutiliser en
conjonction avec un modle de messages pour insrer de linformation par programme.
Le crochet commit-msg accepte un paramtre qui est encore le chemin du chier temporaire
qui contient le message de validation actuel. Si ce script rend un code de sortie non nul, Git abandonne le processus de validation, ce qui vous permet de vrier ltat de votre projet ou du message
de validation avant de laisser passer un commit. Dans la dernire section de ce chapitre, lutilisation
de ce crochet permera de vrier que le message de validation est conforme un format obligatoire.
Aprs lexcution du processus complet de validation, le crochet post-commit est appel.
Il naccepte aucun argument mais vous pouvez facilement accder au dernier commit grce git
log -1 HEAD. Gnralement, ce script sert raliser des notications ou des choses similaires.
Les scripts de gestion de validation ct client peuvent tre utiliss pour nimporte quelle mthode de travail. Ils sont souvent utiliss pour mere en uvre certaines politiques, bien quil faille
noter que ces scripts ne sont pas transfrs lors dun clonage. Vous pouvez faire appliquer les politiques de gestion au niveau serveur pour rejeter les pousses de commits qui ne sont pas conformes
certaines rgles, mais il reste compltement du ressort du dveloppeur de les utiliser ct client.
Ce sont des scripts destins aider les dveloppeurs et ils doivent tre mis en place et maintenus
par ces derniers qui peuvent tout aussi bien les outrepasser ou les modier tout moment.
Croets de gestion e-mail
Vous pouvez rgler trois crochets ct client pour la gestion base de-mail. Ils sont tous invoqus par la commande git am, donc si vous ntes pas habitus utiliser cee commande dans
votre mode de gestion, vous pouvez simplement passer la prochaine section. Si vous acceptez des
patchs prpars par git format-patch par e-mail, alors certains de ces crochets peuvent vous
tre trs utiles.
Le premier crochet lanc est applypatch-msg. Il accepte un seul argument : le nom du
chier temporaire qui contient le message de validation propos. Git abandonne le patch si ce script
sort avec un code non nul. Vous pouvez lutiliser pour vrier que la message de validation est
correctement format ou pour normaliser le message en lditant sur place par script.
Le crochet lanc ensuite lors de lapplication de patchs via git am sappelle pre-applypatch.
Il naccepte aucun argument et est lanc aprs que le patch a t appliqu, ce qui vous permet
dinspecter linstantan avant de raliser la validation. Vous pouvez lancer des tests ou inspecter
larborescence active avec ce script. Sil manque quelque chose ou que les tests ne passent pas, un
code de sortie non nul annule la commande git am sans valider le patch.
Le dernier crochet lanc pendant lopration git am sappelle post-applypatch. Vous
pouvez lutiliser pour notier un groupe ou lauteur du patch que vous venez de lappliquer. Vous
ne pouvez plus arrter le processus de validation avec ce script.
Autres croets ct client
Le crochet pre-rebase est invoque avant que vous ne rebasiez et peut interrompre le processus sil sort avec un code derreur non nul. Vous pouvez utiliser ce crochet pour empcher de
191
rebase tout commit qui a dj t pouss. Cest ce que fait le crochet dexemple pre-rebase que
Git installe, mme sil considre que la branche cible de publication sappelle next. Il est trs probable que vous ayez changer ce nom pour celui que vous utilisez rellement en branche publique
stable.
Aprs avoir eectu avec succs un git checkout, la crochet post-chechout est lanc.
Vous pouvez lutiliser pour paramtrer correctement votre environnement projet dans votre copie
de travail. Cela peut signier y dplacer des gros chiers binaires que vous ne souhaitez pas voir en
gestion de source, gnrer automatiquement la documentation ou quelque chose dans le genre.
Enn, le crochet post-merge sexcute la suite dune commande merge russie. Vous
pouvez lutiliser pour restaurer certaines donnes non gres par Git dans le copie de travail telles
que les informations de permission. Ce crochet permet de mme de valider la prsence de chiers
externes au contrle de Git que vous souhaitez voir recopis lorsque la copie de travail change.
#!/usr/bin/env ruby
$nomref
= ARGV[0]
$anciennerev
= ARGV[1]
$nouvellerev
= ARGV[2]
$utilisateur
= ENV['USER']
puts
"Vrification
des
rgles...
\n(#{$nomref})
(#{$anciennerev[0,
6]}) (#{$nouvellerev[0,6]})"
Et oui, jutilise des variables globales. Cest seulement pour simplier la dmonstration.
Application dune politique de format du message de validation
Notre premire tche consiste forcer que chaque message de validation adhre un format
particulier. En guise dobjectif, obligeons chaque message contenir une chane de caractre qui
ressemble ref: 1234 parce que nous souhaitons que chaque validation soit lie une tche de
notre systme de tickets. Nous devons donc inspecter chaque commit pouss, vrier la prsence
de la chane et sortir avec un code non-nul en cas dabsence pour rejeter la pousse.
Vous pouvez obtenir une liste des valeurs SHA-1 de tous les commits en cours de pousse
en passant les valeurs $nouvellerev et $anciennerev une commande de plomberie Git
193
appele git-rev-list. Cest comme la commande git log mais elle nache par dfaut que
les valeurs SHA-1, sans autre information. Donc, pour obtenir une liste de tous les SHA des commits
introduits entre un SHA de commit et un autre, il sut de lancer quelque chose comme :
Vous pouvez rcuprer la sortie, boucler sur chacun de ces SHA de commit, en extraire le message et tester la conformance du message avec une structure au moyen dune expression rationnelle.
Vous devez trouver comment extraire le message de validation partir de chacun des commits
tester. Pour accder aux donnes brutes du commit, vous pouvez utiliser une autre commande de
plomberie appele git cat-file. Nous traiterons en dtail toutes ces commandes de plomberie
au chapitre 9 mais pour linstant, voici ce que cee commande ache:
Un moyen simple dextraire le message de validation dun commit partir de son SHA-1 consiste rechercher la premire ligne vide et slectionner tout ce qui suit. Cela peut tre facilement
ralis avec la commande sed sur les systmes Unix :
Vous pouvez utiliser cee ligne pour rcuprer le message de validation de chaque commit en
cours de pousse et sortir si quelque chose ne correspond ce qui est aendu. Pour sortir du script
et rejeter la pousse, il faut sortir avec un code non nul. La fonction complte ressemble ceci :
194
Placer ceci dans un script update rejeera les mises jour contenant des commits dont les
messages ne suivent pas la rgle.
Mise en place dun systme dACL par utilisateur
Supposons que vous souhaitiez ajouter un mcanisme base de liste de contrle daccs (access
control list : ACL) qui permee de spcier quel utilisateur a le droit de pousser des modications
vers quelle partie du projet. Certains personnes ont un accs complet tandis que dautres nont accs
que pour mere jour certains sous-rpertoires ou certains chiers. Pour faire appliquer ceci, nous
allons crire ces rgles dans un chier appel acl situ dans le dpt brut Git sur le serveur. Le
crochet update examinera ces rgles, listera les chiers impacts par la pousse et dterminera si
lutilisateur qui pousse a eectivement les droits ncessaires sur ces chiers.
crivons en premier le chier dACL. Nous allons utiliser un format trs proche de celui des
ACL de CVS. Le chier est compos de lignes dont le premier champ est avail ou unavail, le
second est une liste des utilisateurs concerns spars par des virgules t le dernier champ indique
le chemin pour lequel la rgle sapplique (le champ vide indiquant une rgle gnrale). Tous les
champs sont dlimits par un caractre pipe | .
Dans notre cas, il y a quelques administrateurs, des auteurs de documentation avec un accs au
rpertoire doc et un dveloppeur qui na accs quaux rpertoires lib et tests. Le chier ACL
ressemble donc ceci :
avail|nickh,pjhyett,defunkt,tpw
avail|usinclair,cdickens,ebronte|doc
avail|schacon|lib
avail|schacon|tests
Le traitement consiste lire le chier dans une structure utilisable. Dans notre cas, pour simplier, nous ne traiterons que les directives avail. Voici une fonction qui cre partir du chier
un tableau associatif dont la cl est lutilisateur et la valeur une liste des chemins pour lesquels
lutilisateur a les droits en criture :
def get_acl_access_data(nom_fichier_acl)
# lire le fichier ACL
fichier_acl = File.read(nom_fichier_acl).split("\n").reject { |ligne| ligne == '' }
acces = {}
fichier_acl.each do |ligne|
avail, utilisateurs, chemin = ligne.split('|')
next unless avail == 'avail'
utilisateurs.split(',').each do |utilisateur|
195
acces[utilisateur] ||= []
acces[utilisateur] << chemin
end
end
acces
end
Pour le chier dACL dcrit plus haut, le fonction get_acl_access_data retourne une
structure de donnes qui ressemble ceci :
{"defunkt"=>[nil],
"tpw"=>[nil],
"nickh"=>[nil],
"pjhyett"=>[nil],
"schacon"=>["lib", "tests"],
"cdickens"=>["doc"],
"usinclair"=>["doc"],
"ebronte"=>["doc"]}
En plus des permissions, il faut dterminer les chemins impacts par la pousse pour sassurer
que lutilisateur a bien droit dy toucher.
La liste des chiers modis est assez simplement obtenue par la commande git log complte par loption --name-only mentionne au chapitre 2.
Chaque chier des commits doit tre vri par rapport la structure ACL retourne par la
fonction get_acl_access_data pour dterminer si lutilisateur a le droit de pousser tous ses
commits :
196
acces_permis = true
end
end
if !acces_permis
puts "[ACL] Vous n'avez pas le droit de pousser sur #{path}"
exit 1
end
end
end
end
verif_perms_repertoire
Lalgorithme ci-dessus reste simple. Pour chaque lment de la liste des nouveaux commits
pousser obtenue au moyen de git rev-list, on vrie que lutilisateur qui pousse a accs au
chemin de chacun des chiers modis. Lexpression chemin.index(chemin_acces) ==
0 est un Rubyisme qui nest vrai que si chemin commence comme chemin_acces. Ce script
sassure non pas quun chemin fait partie des chemins permis, mais que tous les chemins accds
font bien partie des chemins permis.
prsent, les utilisateurs ne peuvent plus pousser de commits comprenant un message incorrectement format ou des modications des chiers hors de leur zone rserve.
Application des pousses en avance rapide
Il ne reste plus qu forcer les pousses en avance rapide uniquement. partir de la version
1.6, les paramtres receive.denyDeletes et receive.denyNonFastForwards rglent
le problme. Cependant, lutilisation dun crochet permet de fonctionner avec des versions antrieures de Git et mme aprs modication, des permissions par utilisateur ou toute autre volution.
Lalgorithme consiste vrier sil y a des commits accessibles depuis lancienne rvision qui
ne sont pas accessibles depuis la nouvelle. Sil ny en a aucun alors la pousse est eectivement en
avance rapide. Sinon, il faut le rejeter :
Tout est en place. En lanant chmod u+x .git/hooks/update, update tant le chier
dans lequel tout le code prcdent rside, puis en essayant de pousser une rfrence qui nest pas
en avance rapide, on obtient ceci :
197
Il y a plusieurs point relever ici. Premirement, une ligne indique lendroit o le crochet est
appel.
Le script update ache ces lignes sur stdout au tout dbut. Tout ce que le script crit sur stdout
sera transmis au client.
La ligne suivante remarquer est le message derreur.
Le premire ligne a t crite par le script, les deux autres lont t par Git pour indiquer que
le script update a rendu un code de sortie non nul, ce qui a caus lchec de la pousse. Enn, il y
a ces lignes :
To git@gitserver:project.git
! [remote rejected] master -> master (hook declined)
error: failed to push some refs to 'git@gitserver:project.git'
Il y a un message dchec distant pour chaque rfrence que le crochet a rejete et une indication que lchec est d spciquement un chec du crochet.
Par ailleurs, si la marque ref nest pas prsente dans le message de validation, le message
derreur spcique est ach :
198
Ou si quelquun cherche modier un chier auquel il na pas les droits daccs lors dune
pousse, il verra quelque chose de similaire. Par exemple, si un auteur de documentation essaie de
pousser un commit qui modie quelque chose dans le rpertoire lib, il verra
Cest tout. partir de maintenant, tant que le script update est en place et excutable, votre
dpt ne peut plus subir de pousses hors avance rapide, naccepte plus de messages sans format
et vos utilisateurs sont brids.
#!/usr/bin/env ruby
fichier_message = ARGV[0]
message = File.read(fichier_message)
$regex = /\[ref: (\d+)\]/
if !$regex.match(message)
puts "[REGLE] Le message de validation ne suit pas le format"
exit 1
end
199
La validation na pas abouti. Nanmoins, si le message contient la bonne forme, Git accepte la
validation :
Ensuite, il faut sassurer des droits sur les chiers modis. Si le rpertoire .git du projet
contient une copie du chier dACL prcdemment utilis, alors le script pre-commit suivant
appliquera ses rgles :
#!/usr/bin/env ruby
$utilisateur
= ENV['USER']
Cest grossirement le mme script que celui ct serveur, mais avec deux dirences majeures.
Premirement, le chier ACL est un endroit dirent parce que le script sexcute depuis le copie
de travail et non depuis le rpertoire Git. Il faut donc changer le chemin vers le chier dACL de
acces = get_acl_access_data('acl')
pour
acces = get_acl_access_data('.git/acl')
200
Lautre dirence majeure rside dans la manire dobtenir la liste des chiers modis. La
fonction sur le serveur la recherche dans le journal des commits mais comme dans le cas actuel, le
commit na pas encore t enregistr, il faut chercher la liste dans la zone dindex. Donc au lieu de
on utilise
Mais ces deux dirences prs, le script fonctionne de manire identique. Ce script a aussi
une autre limitation : il saend ce que lutilisateur qui le lance localement soit identique celui
sur le serveur distant. Sils sont dirents, il faudra positionner manuellement la variable $utilisateur.
La dernire action raliser consiste vrier que les rfrences pousses sont bien en avance
rapide, mais linverse est plutt rare. Pour obtenir une rfrence qui nest pas en avance rapide, il
faut soit rebaser aprs un commit qui a dj t pouss, soit essayer de pousser une branche locale
dirente vers la mme branche distante.
Comme le serveur indiquera quon ne peut pas pousser sans avance rapide de toute faon et
que le crochet empche les pousses forces, la seule action accidentelle quil faut intercepter reste
le rebasage de commits qui ont dj t pousss.
Voici un exemple de script pre-rebase qui fait cee vrication. Ce script rcupre une
liste de tous les commits quon est sur le point de rcrire et vrie sils existent dans une rfrence
distante. Sil en trouve un accessible depuis une des rfrences distantes, il interrompt le rebasage :
#!/usr/bin/env ruby
branche_base = ARGV[0]
if ARGV[1]
branche_thematique = ARGV[1]
else
branche_thematique = "HEAD"
end
sha_cibles = `git rev-list #{branche_base}..#{branche_thematique}`.split("\n")
refs_distantes = `git branch -r`.split("\n").map { |r| r.strip }
shas_cibles.each do |sha|
refs_distantes.each do |ref_distante|
shas_pousses = `git rev-list ^#{sha}^@ refs/remotes/#{ref_distante}`
if shas_pousses.split(\n).include?(sha)
puts "[REGLE] Le commit #{sha} a dj t pouss sur #{ref_distante}"
exit 1
end
end
end
201
Ce script utilise une syntaxe qui na pas t aborde la section slection de rvision du
chapitre 6. La liste des commits dj pousss est obtenue avec cee commande :
La syntaxe SHA@ fait rfrence tous le parents du commit. Les commits recherchs sont accessibles depuis le dernier commit distant et inaccessibles depuis nimporte quel parent de nimporte
quel SHA quon cherche pousser. Cest la dnition davance rapide.
La limitation de cee approche reste quelle peut savrer trs lente et non ncessaire. Si vous
nessayez pas de forcer pousser avec loption -f, le serveur vous avertira et nacceptera pas la
pousse. Cependant, cela reste un exercice intressant qui peut aider thoriquement viter un
rebasage qui devra tre annul plus tard.
7.5 Rsum
Nous avons trait la plupart des moyens principaux de personnaliser le client et le serveur
Git pour mieux ladapter toutes les mthodes et les projets. Nous avons couvert toutes sortes de
rglages de congurations, daributs dans des chiers et de crochets dvnement et nous avons
construit un exemple de politique de gestion de serveur. Vous voil prt rgler Git sadapter
quasiment toutes les gestions dont vous avez rv.
202
Chapitre 8
linaire possible en rebasant votre travail et en vitant des activits telles que dinteragir dans le
mme temps avec un dpt Git distant.
Ne rcrivez pas votre historique avant dessayer de pousser nouveau et ne poussez pas en
parallle dans un dpt Git pour collaborer avec vos collgues dveloppant avec Git. Subversion ne
supporte quun historique linaire et lgarer est trs facile. Si vous travaillez avec une quipe dont
certains membres utilisent svn et dautres utilisent Git, assurez-vous que tout le monde nutilise que
le serveur svn pour collaborer, cela vous rendra service.
8.1.2 Installation
Pour montrer cee fonctionnalit, il faut un serveur svn sur lequel vous avez des droits en
criture. Pour copier ces exemples, faites une copie inscriptible de mon dpt de test. Dans cee optique, vous pouvez utiliser un outil appel svnsync qui est livr avec les versions les plus rcentes
de Subversion il devrait tre distribu avec les versions partir de 1.4. Pour ces tests, jai cr sur
Google code un nouveau dpt Subversion qui tait une copie partielle du projet protobuf qui
est un outil qui encode les donnes structures pour une transmission par rseau.
En prparation, crez un nouveau dpt local Subversion :
$ mkdir /tmp/test-svn
$ svnadmin create /tmp/test-svn
Ensuite, autorisez tous les utilisateurs changer les revprops le moyen le plus simple consiste
ajouter un script pre-revprop-change que rend toujours 0 :
$ cat /tmp/test-svn/hooks/pre-revprop-change
#!/bin/sh
exit 0;
$ chmod +x /tmp/test-svn/hooks/pre-revprop-change
Vous pouvez prsent synchroniser ce projet sur votre machine locale en lanant svnsync
init avec les dpts sources et cibles.
Cela initialise les proprits ncessaires la synchronisation. Vous pouvez ensuite cloner le
code en lanant
204
Bien que cee opration ne dure que quelques minutes, si vous essayez de copier le dpt
original sur un autre dpt distant au lieu dun dpt local, le processus durera prs dune heure,
en dpit du fait quil y a moins de 100 commits. Subversion doit cloner rvision par rvision puis
pousser vers un autre dpt cest ridiculement inecace mais cest la seule possibilit.
8.1.3 Dmarrage
Avec des droits en criture sur un dpt Subversion, vous voici prt exprimenter une mthode typique. Commenons par la commande git svn clone qui importe un dpt Subversion
complet dans un dpt Git local. Souvenez-vous que si vous importez depuis un dpt Subversion
hberg sur internet, il faut remplacer lURL file://tmp/test-svn ci-dessous par lURL de
votre dpt Subversion :
m4/acx_pthread.m4
m4/stl_hash.m4
...
r75 = d1957f3b307922124eec6314e15bcda59e3d9610 (trunk)
Found possible branch point: file:///tmp/test-svn/trunk => \
file:///tmp/test-svn /branches/my-calc-branch, 75
Found branch parent: (my-calc-branch) d1957f3b307922124eec6314e15bcda59e3d9610
Following parent with do_switch
Successfully followed parent
r76 = 8624824ecc0badd73f40ea2f01fce51894189b01 (my-calc-branch)
Checked out HEAD:
file:///tmp/test-svn/branches/my-calc-branch r76
Cela quivaut lancer git svn init suivi de git svn fetch sur lURL que vous avez
fournie. Cela peut prendre un certain temps. Le projet de test ne contient que 75 commits et la taille
du code nest pas extraordinaire, ce qui prend juste quelques minutes. Cependant, Git doit extraire
chaque version, une par une et les valider individuellement. Pour un projet contenant des centaines
ou des milliers de commits, cela peut prendre liralement des heures ou mme des jours terminer.
La partie -T trunk -b branches -t tags indique Git que ce dpt Subversion suit les
conventions de base en matire dembranchement et de balisage. Si vous nommez votre trunk, vos
branches ou vos balises diremment, vous pouvez modier ces options. Comme cee organisation
est la plus commune, ces options peuvent tre simplement remplaces par -s qui signie structure
standard. La commande suivante est quivalente :
prsent, vous disposez dun dpt Git valide qui a import vos branches et vos balises :
$ git branch -a
* master
205
my-calc-branch
tags/2.0.2
tags/release-2.0.1
tags/release-2.0.2
tags/release-2.0.2rc1
trunk
Il est important de remarquer comment cet outil sous-classe vos rfrences distantes diremment. and vous clonez un dpt Git normal, vous obtenez toutes les branches distantes localement
sous la forme origin/[branch] avec un espace de nom correspondant au dpt distant. Cependant, git svn assume que vous naurez pas de multiples dpts distants et enregistre toutes ses
rfrences pour quelles pointent sur le dpt distant. Cependant, vous pouvez utiliser la commande
Git de plomberie show-ref pour visualiser toutes vos rfrences.
$ git show-ref
1cbd4904d9982f386d87f88fce1c24ad7c0f0471 refs/heads/master
aee1ecc26318164f355a883f5d99cff0c852d3c4 refs/remotes/my-calc-branch
03d09b0e2aad427e34a6d50ff147128e76c0e0f5 refs/remotes/tags/2.0.2
50d02cc0adc9da4319eeba0900430ba219b9c376 refs/remotes/tags/release-2.0.1
4caaa711a50c77879a91b8b90380060f672745cb refs/remotes/tags/release-2.0.2
1c4cb508144c513ff1214c3488abe66dcb92916f refs/remotes/tags/release-2.0.2rc1
1cbd4904d9982f386d87f88fce1c24ad7c0f0471 refs/remotes/trunk
$ git show-ref
83e38c7a0af325a9722f2fdc56b10188806d83a1 refs/heads/master
3e15e38c198baac84223acfc6224bb8b99ff2281 refs/remotes/gitserver/master
0a30dd3b0c795b80212ae723640d4e5d48cabdff refs/remotes/origin/master
25812380387fdd55f916652be4881c6f11600d6f refs/remotes/origin/testing
Ici, vous disposez de deux serveurs distants : un nomm gitserver avec une branche master et un autre nomm origin avec deux branches master et testing.
Remarquez comme dans cet exemple de rfrences distantes importes via git svn, les balises
sont ajoutes comme des branches distantes et non comme des vraies balises Git. Votre importation
Subversion indique plutt quil a un serveur distant appel tags prsentant des branches.
206
Ensuite, vous avez besoin de pousser vos modications en amont. Remarquez que cela modie
la manire de travailler par rapport Subversion vous pouvez ralisez plusieurs validations en
mode dconnect pour ensuite les pousser toutes en une fois sur le serveur Subversion. Pour pousser
sur un serveur Subversion, il faut lancer la commande git svn dcommit :
README.txt
Committed r79
M
README.txt
Cee commande rassemble tous les commits que vous avez valids par dessus le code du
serveur Subversion et ralise un commit sur le serveur pour chacun, puis rcrit lhistorique Git
local pour y ajouter un identiant unique. Cee tape est souligner car elle signie que toutes les
sommes de contrle SHA-1 de vos commits locaux ont chang. Cest en partie pour cee raison que
cest une ide trs prilleuse de vouloir travailler dans le mme temps avec des serveurs Git distants.
Lexamen du dernier commit montre que le nouveau git-svn-id a t ajout :
$ git log -1
commit 938b1a547c2cc92033b74d32030e86468294a5c8
Author: schacon <schacon@4c93b258-373f-11de-be05-5f7a86268029>
Date:
Remarquez que la somme de contrle SHA qui commenait par 97031e5 quand vous avez
valid commence prsent par 938b1a5. Si vous souhaitez pousser la fois sur un serveur Git
et un serveur Subversion, il faut obligatoirement pousser (dcommit) sur le serveur Subversion en
premier, car cee action va modier vos donnes des commits.
Pour rsoudre cee situation, vous pouvez lancer la commande git svn rebase qui tire
depuis le serveur toute modication apparue entre temps et rebase votre travail sur le sommet de
lhistorique du serveur :
README.txt
prsent, tout votre travail se trouve au del de lhistorique du serveur et vous pouvez eectivement raliser un dcommit :
README.txt
Committed r81
M
README.txt
Il est important de se souvenir qu la dirence de Git qui requiert une fusion avec les modications distantes non prsentes localement avant de pouvoir pousser, git svn ne vous y contraint
que si vos modications provoquent un conit. Si une autre personne pousse une modication un
chier et que vous poussez une modication un autre chier, votre dcommit passera sans problme :
configure.ac
Committed r84
M
autogen.sh
configure.ac
208
autogen.sh
Il faut sen souvenir car le rsultat de ces actions est un tat du dpt qui nexistait pas sur
aucun des ordinateurs quand vous avez pouss. Si les modications sont incompatibles mais ne
crent pas de conits, vous pouvez crer des dfauts qui seront trs diciles diagnostiquer. Cest
une grande dirence avec un serveur Git dans Git, vous pouvez tester compltement ltat du
projet sur votre systme client avant de le publier, tandis quavec SVN, vous ne pouvez jamais tre
totalement certain que les tats avant et aprs validation sont identiques.
Vous devrez aussi lancer cee commande pour tirer les modications depuis le serveur Subversion, mme si vous ntes pas encore prt valider. Vous pouvez lancer git svn fetch pour
tirer les nouveaux commits, mais git svn rebase tire non seulement les commits distants mais
rebase aussi vos commit locaux.
generate_descriptor_proto.sh
Lancer git svn rebase de temps en temps vous assure que votre travail est toujours
synchronis avec le serveur. Vous devrez cependant vous assurer que votre copie de travail est
propre quand vous la lancez. Si vous avez des modications locales, il vous faudra soit remiser votre
travail, soit valider temporairement vos modications avant de lancer git svn rebase, sinon
la commande sarrtera si elle dtecte que le rebasage provoquerait un conit de fusion.
CHANGES.txt
Committed r85
M
CHANGES.txt
209
COPYING.txt
INSTALL.txt
Committed r86
M
INSTALL.txt
COPYING.txt
Lancer dcommit sur une branche avec un historique fusionn fonctionne correctement,
lexception que lexamen de lhistorique du projet Git indique quil na rcrit aucun des commits
raliss sur la branche experience, mais que toutes les modications introduites apparaissent
dans la version SVN de lunique commit de fusion.
and quelquun dautre clone ce travail, tout ce quil voit, cest le commit de la fusion avec
toutes les modications injectes en une fois. Il ne voit aucune information sur son origine ni sur
sa date de validation.
Si vous souhaitez travailler simultanment sur plusieurs branches, vous pouvez rgler vos
branches locales pour que le dcommit arrive sur une branche Subversion spcique en les dmarrant sur le commit de cee branche importe depuis Subversion. Si vous voulez une branche
opera sur laquelle travailler sparment, vous pouvez lancer
prsent, si vous voulez fusionner votre branche opera dans trunk (votre branche master), vous pouvez le faire en ralisant un git merge normal. Mais vous devez prciser un message
de validation descriptif (via -m), ou la fusion indiquera simplement Merge branch opera au lieu
dun message plus informatif.
Souvenez-vous que bien que vous utilisez git merge qui facilitera lopration de fusion par
rapport Subversion (Git dtectera automatiquement lanctre commun pour la fusion), ce nest
pas un commit de fusion normal de Git. Vous devrez pousser ces donnes nalement sur le serveur
Subversion qui ne sait pas tracer les commits possdant plusieurs parents. Donc, ce sera un commit
unique qui englobera toutes les modications de lautre branche. Aprs avoir fusionn une branche
dans une autre, il est dicile de continuer travailler sur cee branche, comme vous le feriez normalement dans Git. La commande dcommit qui a t lance eace toute information sur la branche
qui a t fusionne, ce qui rend faux tout calcul dantriorit pour la fusion. dcommit fait ressembler le rsultat de git merge celui de git merge --squash. Malheureusement, il ny a pas
de moyen ecace de remdier ce problme Subversion ne stocke pas cee information et vous
serez toujours contraints par ses limitations si vous lutilisez comme serveur. Pour viter ces problmes, le mieux reste deacer la branche locale (dans notre cas, opera) ds quelle a t fusionne
dans trunk.
211
Deux choses importantes connatre sur git svn log : premirement, la dirence de
la commande relle svn log qui interroge le serveur, cee commande fonctionne hors connexion
; deuximement, elle ne montre que les commits qui ont t eectivement remonts sur le serveur
Subversion. Les commits locaux qui nont pas encore t remonts via dcommit napparaissent
pas, pas plus que ceux qui auraient t pousss sur le serveur par des tiers entre deux git svn
rebase. Cela donne plutt le dernier tat connu des commits sur le serveur Subversion.
Les annotations SVN
De la mme manire que git svn log simule une commande svn log dconnecte, vous
pouvez obtenir lquivalent de svn annotate en lanant git svn blame [FICHIER]. Le
rsultat ressemble ceci :
temporal http://code.google.com/apis/protocolbuffers/
temporal
22
22
2
79
78
temporal To build and install the C++ Protocol Buffer runtime and the Protocol
temporal
Ici aussi, tous les commits locaux dans Git ou ceux pouss sur Subversion dans lintervalle
napparaissent pas.
Linformation sur la serveur SVN
Vous pouvez aussi obtenir le mme genre dinformation que celle fournie par svn info en
lanant git svn info :
212
Comme blame et log, cee commande travaille hors connexion et nest jour qu la dernire
date laquelle vous avez communiqu avec le serveur Subversion.
De cee manire, vous ne parsemez pas le projet de chiers .gitignore. Cest une option
optimale si vous tes le seul utilisateur de Git dans une quipe Subversion et que vos coquipiers
ne veulent pas voir de chiers .gitignore dans le projet.
8.2.1 Importer
Nous allons dtailler la manire dimporter des donnes partir de deux des plus grands systmes SCM utiliss en milieu professionnel, Subversion et Perforce, pour les raisons combines quils
regroupent la majorit des utilisateurs que je connais migrer vers Git et que des outils de grande
qualit pour ces deux systmes sont distribus avec Git.
8.2.2 Subversion
Si vous avez lu la section prcdente sur lutilisation de git svn, vous pouvez facilement
utiliser ces instructions pour raliser un git svn clone du dpt. Ensuite, arrtez dutiliser le
serveur Subversion, poussez sur un nouveau serveur Git et commencez lutiliser. Si vous voulez
lhistorique, vous pouvez lobtenir aussi rapidement que vous pourrez tirer les donnes du serveur
Subversion (ce qui peut prendre un certain temps).
Cependant, limport nest pas parfait ; et comme cela prend autant de temps, autant le faire
bien. Le premier problme est linformation dauteur. Dans Subversion, chaque personne qui valide
dispose dun compte sur le systme qui est enregistr dans linformation de validation. Les exemples
de la section prcdente montrent schacon certains endroits, tels que la sortie de blame ou de
git svn log. Si vous voulez transposer ces donnes vers des donnes dauteur au format Git,
vous avez besoin dune correspondance entre les utilisateurs Subversion et les auteurs Git. Crez
un chier appel users.txt contenant cee quivalence dans le format suivant :
Pour rcuprer la liste des noms dauteurs utiliss par SVN, vous pouvez utiliser la ligne suivante :
$ svn log --xml | grep author | sort -u | perl -pe 's/.>(.?)<./$1 = /'
Cela gnre une sortie au format XML vous pouvez visualiser les auteurs, crer une liste
unique puis liminer lXML. videmment, cee ligne ne fonctionne que sur une machine disposant
des commandes grep, sort et perl. Ensuite, redirigez votre sortie dans votre chier users.txt
pour pouvoir y ajouter en correspondance les donnes quivalentes Git.
Vous pouvez alors fournir ce chier git svn pour laider convertir les donnes dauteur
plus prcisment. Vous pouvez aussi indiquer git svn de ne pas inclure les mta-donnes que
Subversion importe habituellement en passant loption --no-metadata la commande clone
ou init. Au nal, votre commande dimport ressemble ceci :
214
Maintenant, limport depuis Subversion dans le rpertoire my_project est plus prsentable.
En lieu et place de commits qui ressemblent ceci :
commit 37efa680e8473b615de980fa935944215428a35a
Author: schacon <schacon@4c93b258-373f-11de-be05-5f7a86268029>
Date:
commit 03a8785f44c8ea5cdb0e8834b7c8e6c469be2ff2
Author: Scott Chacon <schacon@geemail.com>
Date:
Non seulement le champ auteur a meilleure mine, mais de plus le champ git-svn-id a
disparu.
Il est encore ncessaire de faire un peu de mnage post-import. Dj, vous devriez neoyer
les rfrences bizarres que git svn cre. Premirement, dplacez les balises pour quelles soient
de vraies balises plutt que des branches distantes tranges, ensuite dplacez le reste des branches
pour quelles deviennent locales.
Pour dplacer les balises et en faire de vraies balises Git, lancez
Cela rcupre les rfrences dclares comme branches distantes commenant par tags/ et
les transforme en vraies balises (lgres).
Ensuite, dplacez le reste des rfrences sous refs/remotes en branches locales :
215
prsent, toutes les vieilles branches sont des vraies branches Git et toutes les vieilles balises
sont de vraies balises Git. La dernire activit consiste ajouter votre nouveau serveur Git comme
serveur distant et y pousser votre projet transform. Pour pousser tout, y compris branches et
balises, lancez :
Toutes vos donnes, branches et tags sont prsent disponibles sur le serveur Git comme
import propre et naturel.
8.2.3 Perforce
Lautre systme duquel on peut souhaiter importer les donnes est Perforce. Un outil dimport
Perforce est aussi distribu avec Git, mais seulement dans la section contrib du code source. Il
nest pas disponible par dfaut comme git svn. Pour le lancer, il vous faut rcuprer le code
source de Git que vous pouvez tlcharger partir de git.kernel.org :
Dans ce rpertoire fast-import, vous devriez trouver une script excutable Python appel
git-p4. Python et loutil p4 doivent tre installs sur votre machine pour que cet import fonctionne. Par exemple, nous importerons le projet Jam depuis le Perforce Public Depot. Pour installer
votre client, vous devez exporter la variable denvironnement P4PORT qui pointe sur le dpt Perforce :
$ export P4PORT=public.perforce.com:1666
Lancez la commande git-p4 clone pour importer la projet Jam depuis le serveur Perforce,
en fournissant le dpt avec le chemin du projet et le chemin dans lequel vous souhaitez importer
le projet :
Si vous vous rendez dans le rpertoire /opt/p4import et lancez la commande git log,
vous pouvez examiner votre projet import :
216
$ git log -2
commit 1fd4ec126171790efd2db83548b85b1bbbc07dc2
Author: Perforce staff <support@perforce.com>
Date:
Si vous lancez git log, vous vous rendez compte que toutes les sommes de contrle SHA-1
des commits ont chang, mais aussi que plus aucune chane git-p4 napparat dans les messages
de validation :
$ git log -2
commit 10a16d60cffca14d454a15c6164378f4082bc5b0
Author: Perforce staff <support@perforce.com>
Date:
217
Votre import est n prt pour tre pouss sur un nouveau serveur Git.
$ ls /opt/import_depuis
back_2009_01_02
back_2009_01_04
back_2009_01_14
back_2009_02_03
en_cours
Pour importer un rpertoire dans Git, vous devez savoir comment Git stocke ses donnes.
Comme vous pouvez vous en souvenir, Git est la base une liste chane dobjets de commits qui
pointent sur un instantan de contenu. Tout ce quil y a faire donc, et dindiquer fast-import
ce que sont les instantans de contenu, quelles donnes de commit pointent dessus et lordre dans
lequel ils senchanent. La stratgie consistera parcourir les instantans un par un et crer des
commits avec le contenu de chaque rpertoire, en le reliant son prdcesseur.
Comme dj fait dans la section Un exemple de rgle applique par Git du chapitre 7, nous
lcrirons en Ruby parce que cest le langage avec lequel je travaille en gnral et quil est assez facile
lire. Vous pouvez facilement retranscrire cet exemple dans votre langage de prdilection, la seule
contrainte tant quil doit pouvoir acher les informations appropries sur stdout. Si vous travaillez
sous Windows, cela signie que vous devrez faire particulirement aention ne pas introduire de
retour chariot la n de vos lignes. git fast-import naccepte particulirement que les sauts
de ligne (line feed LF) et pas les retour chariot saut de ligne (CRLF) utiliss par Windows.
Pour commencer, dplaons nous dans le rpertoire cible et identions chaque sous-rpertoire,
chacun reprsentant un instantan que vous souhaitez importer en tant que commit. Nous visiterons
chaque sous-rpertoire et acherons les commandes ncessaires son export. La boucle principale
ressemble ceci :
218
last_mark = nil
# loop through the directories
Dir.chdir(ARGV[0]) do
Dir.glob("*").each do |dir|
next if File.file?(dir)
# move into the target directory
Dir.chdir(dir) do
last_mark = print_export(dir, last_mark)
end
end
end
Dans chaque rpertoire, nous lanons print_export qui prend le manifest et la marque de
linstantan prcdent et retourne le manifest et la marque de lactuel ; de cee manire, vous pouvez
les chaner correctement. Marque est le terme de fast-import pour nommer un identiant
que vous donnez un commit. Au fur et mesure de la cration des commits, vous leur aribuez
une marque individuelle qui pourra tre utilise pour y faire rfrence depuis dautres commits. La
premire chose faire dans print_export est donc de gnrer une marque partir du nom du
rpertoire :
mark = convert_dir_to_mark(dir)
Cela sera ralis en crant un tableau des rpertoires et en utilisant lindice comme marque,
celle-ci devant tre un nombre entier. Votre mthode ressemble ceci :
$marks = []
def convert_dir_to_mark(dir)
if !$marks.include?(dir)
$marks << dir
end
($marks.index(dir) + 1).to_s
end
Aprs une reprsentation entire de votre commit, vous avez besoin dune date pour les mtadonnes du commit. La date est prsente dans le nom du rpertoire, alors analysons-le. La ligne
suivante du chier print_export est donc
date = convert_dir_to_date(dir)
219
def convert_dir_to_date(dir)
if dir == 'en_cours'
return Time.now().to_i
else
dir = dir.gsub('back_', '')
(year, month, day) = dir.split('_')
return Time.local(year, month, day).to_i
end
end
Elle retourne une nombre entier pour la date de chaque rpertoire. La dernire partie des mtainformations ncessaires chaque commit est linformation du validateur qui sera stocke en dur
dans une variable globale :
Nous voil prt commencer crire les informations de commit du script dimport. La premire information indique quon dnit un objet commit et la branche sur laquelle il se trouve, suivi
de la marque qui a t gnre, linformation du validateur et le message de validation et enn le
commit prcdent, sil existe. Le code ressemble ceci :
Nous codons en dur le fuseau horaire (0700) car cest simple. Si vous importez depuis un autre
systme, vous devez spcier le fuseau horaire comme un dcalage. Le message de validation doit
tre exprim dans un format spcial :
data (taille)\n(contenu)
Le format est compos du mot data , la taille des donnes lire, un caractre saut de ligne, et
nalement les donnes. Ce format est rutilis plus tard, alors autant crer une mthode auxiliaire,
export_data :
def export_data(string)
print "data #{string.size}\n#{string}"
end
220
Il reste seulement spcier le contenu en chiers de chaque instantan. Cest facile, car vous
les avez dans le rpertoire. Git va alors enregistrer de manire approprie chaque instantan :
puts 'deleteall'
Dir.glob("**/*").each do |file|
next if !File.file?(file)
inline_data(file)
end
Note: Comme de nombreux systmes conoivent leurs rvisions comme des modications dun
commit lautre, fast-import accepte aussi avec chaque commit des commandes qui spcient quels
chiers ont t ajouts, eacs ou modis et ce que sont les nouveaux contenus. Vous pourriez
calculer les dirences entre chaque instantan et ne fournir que ces donnes, mais cela est plus
complexe vous pourriez tout aussi bien fournir Git toutes les donnes et lui laisser faire le
travail. Si cest ce qui convient mieux vos donnes, rfrez-vous la page de manuel de fastimport pour savoir comment fournir les donnes de cee faon.
Le format pour lister le contenu dun nouveau chier ou spcier le nouveau contenu dun
chier modi est comme suit :
Ici, 644 est le mode (si vous avez des chiers executables, vous devez le dtecter et spcier
plutt 755), inline signie que le contenu du chier sera list immdiatement aprs cee ligne.
La mthode inline_data ressemble ceci :
Nous rutilisons la mthode export_data dnie plus tt, car cest la mme mthode que
pour spcier les donnes du message de validation.
La dernire chose faire consiste retourner le marque actuelle pour pouvoir la passer la
prochaine itration :
return mark
NOTE : si vous utilisez Windows, vous devrez vous assurer dajouter une tape supplmentaire.
Comme mentionn auparavant, Windows utilise CRLF comme caractre de retour la ligne tandis
que git fast-import saend LF. Pour contourner ce problme et satisfaire git fast-import, il faut
forcer ruby utiliser LF au lieu de CRLF :
221
$stdout.binmode
Et voil. Si vous lancez ce script, vous obtiendrez un contenu qui ressemble ceci :
Pour lancer loutil dimport, redirigez cee sortie dans git fast-import alors que vous
vous trouvez dans le rpertoire Git dans lequel vous souhaitez importer. Vous pouvez crer un
nouveau rpertoire, puis linitialiser avec git init, puis lancer votre script :
$ git init
Initialized empty Git repository in /opt/import_to/.git/
$ ruby import.rb /opt/import_from | git fast-import
git-fast-import statistics:
--------------------------------------------------------------------Alloc'd objects:
Total objects:
5000
18 (
1 duplicates
blobs
7 (
1 duplicates
0 deltas)
trees
6 (
0 duplicates
1 deltas)
commits:
5 (
0 duplicates
0 deltas)
tags
0 (
0 duplicates
0 deltas)
1 (
1 loads
5 unique
Total branches:
marks:
1024 (
atoms:
Memory total:
2255 KiB
pools:
2098 KiB
objects:
156 KiB
--------------------------------------------------------------------pack_report: getpagesize()
222
4096
pack_report: core.packedGitWindowSize =
33554432
pack_report: core.packedGitLimit
268435456
pack_report: pack_used_ctr
pack_report: pack_mmap_calls
pack_report: pack_open_windows
1 /
pack_report: pack_mapped
1356 /
1356
---------------------------------------------------------------------
Comme vous pouvez le remarquer, lorsquil se termine avec succs, il ache quelques statistiques sur ses ralisations. Dans ce cas, 18 objets ont t imports en 5 validations dans 1 branche.
prsent, git log permet de visualiser le nouvel historique :
$ git log -2
commit 10bfe7d22ce15ee25b60a824c8982157ca593d41
Author: Scott Chacon <schacon@example.com>
Date:
Et voil ! Un joli dpt Git tout propre. Il est important de noter que rien na t extrait. Prsentement, aucun chier nest prsent dans votre copie de travail. Pour les avoir, vous devez rinitialiser
votre branche sur master :
$ ls
$ git reset --hard master
HEAD is now at 10bfe7d imported from en_cours
$ ls
file.rb
lib
Vous pouvez faire bien plus avec loutil fast-import grer dirents modes, les donnes
binaires, les branches multiples et la fusion, les balises, les indicateurs de progrs, et plus encore.
Des exemples de scnarios plus complexes sont disponibles dans le rpertoire contrib/fastimport du code source Git ; un des meilleurs est justement le script git-p4 trait prcdemment.
8.3 Rsum
Vous devriez tre laise lutilisation de Git avec Subversion ou pour limport de quasiment
toutes le sortes de dpts dans un nouveau Git sans perdre de donnes. Le chapitre suivant traitera
des structures internes de Git pour vous permere den retailler chaque octet, si le besoin sen fait
sentir.
223
Chapitre 9
and vous excutez git init dans un nouveau rpertoire ou un rpertoire existant, Git
cre un rpertoire .git qui contient presque tout ce que Git stocke et manipule. Si vous voulez
sauvegarder ou cloner votre dpt, copier ce seul rpertoire surait presque. Ce chapitre traite
principalement de ce que contient ce rpertoire. Voici quoi il ressemble :
$ ls
HEAD
branches/
config
description
hooks/
index
info/
objects/
refs/
Vous y verrez sans doute dautres chiers, mais ceci est un dpt qui vient dtre cre avec git
init, et cest ce que vous verrez par dfaut. Le rpertoire branches nest pas utilis par les versions rcentes de Git, et le chier description est utilis uniquement par le programme GitWeb,
il ne faut donc pas sen soucier. Le chier config contient les options de conguration spciques
votre projet, et le rpertoire info contient un chier listant les motifs que vous souhaitez ignorer
et que vous ne voulez pas mere dans un chier .gitignore. Le rpertoire hooks contient les scripts
de procdures automatiques ct client ou serveur, ils sont dcrits en dtail dans le chapitre 6.
Il reste quatre lments importants : les chiers HEAD et index, ainsi que les rpertoires
objects et refs. Ce sont les parties centrales de Git. Le rpertoire objects stocke le contenu
de votre base de donnes, le rpertoire refs stocke les pointeurs vers les objets commit de ces
donnes (branches), le chier HEAD pointe sur la branche qui est en cours dans votre rpertoire
de travail (checkout), et le chier index est lendroit o Git stocke les informations sur la zone
daente. Vous allez maintenant plonger en dtail dans chacune de ces sections et voir comment Git
fonctionne.
$ mkdir test
$ cd test
$ git init
Initialized empty Git repository in /tmp/test/.git/
$ find .git/objects
226
.git/objects
.git/objects/info
.git/objects/pack
$ find .git/objects -type f
$
Git a initialis le rpertoire objects et y a cre les sous-rpertoires pack et info, mais ils
ne contiennent pas de chier rgulier. Maintenant, stockez du texte dans votre base de donnes Git
:
Loption -w spcie hash-object de stocker lobjet, sinon la commande rpondrait seulement quelle serait la cl. --stdin spcie la commande de lire le contenu depuis lentre standard, sinon hash-object saend trouver un chemin vers un chier. La sortie de la commande
est une empreinte de 40 caractres. Cest lempreinte SHA-1 : une somme de contrle du contenu du
chier que vous stockez plus une en-tte, dont les dtails sont un peu plus bas. Voyez maintenant
comment Git a stock vos donnes :
Vous pouvez voir un chier dans le rpertoire objects. Cest comme cela que Git stocke initialement du contenu : un chier par contenu, nomm daprs la somme de contrle SHA-1 du contenu et de son en-tte. Le sous-rpertoire est nomm daprs les 2 premiers caractres de lempreinte
et le chier daprs les 38 caractres restants.
Vous pouvez rcuprer le contenu avec la commande cat-file. Cee commande est un
peu le couteau suisse pour linspection des objets Git. Utiliser -p avec cat-file vous permet de
connatre le type de contenu et de lacher clairement :
Vous pouvez maintenant ajouter du contenu Git et le rcuprer. Vous pouvez aussi faire ceci
avec des chiers. Par exemple, vous pouvez mere en uvre une gestion de version simple dun
chier. Dabord, crez un nouveau chier et enregistrez son contenu dans la base de donnes :
227
Votre base de donnes contient les 2 versions du chier, ainsi que le premier contenu que vous
avez stock ici :
ou sa seconde version :
Ce souvenir de la cl SHA-1 de chaque version de votre chier nest pas pratique. En plus, vous
ne stockez pas le chier lui-mme, mais seulement son contenu, dans votre base. Ce type dobjets
est appel un blob (Binary Large OBject, soit en franais : Gros Objet Binaire). Git peut vous donnez
le type dobjet de nimporte quel objet Git, tant donn sa cl SHA-1, avec cat-file -t :
daccs (N.d.t mode), le type et le nom de chier. Larbre le plus rcent du projet simplegit pourrai
ressembler, par exemple ceci :
README
Rakefile
lib
La syntaxe mastertree signie lobjet arbre qui est point par le dernier commit de la
branche master. Remarquez que le sous-rpertoire lib nest pas un blob, mais un pointeur vers
un autre arbre :
simplegit.rb
Vous pouvez crer votre propre arbre. Git cre habituellement un arbre partir de ltat de la
zone daente ou de lindex. Pour crer un objet arbre, vous devez donc dabord mere en place un
index en meant quelques chiers en aente. Pour crer un index contenant une entre, la premire
version de votre chier text.txt par exemple, en utilisant la commande de plomberie updateindex. Vous pouvez utiliser cee commande pour ajouter articiellement une version plus ancienne une nouvelle zone daente. Vous devez utiliser les options --add car le chier nexiste pas
encore dans votre zone daente (vous navez mme pas encore mis en place une zone daente) et
--cacheinfo car le chier que vous ajoutez nest pas dans votre rpertoire, mais dans la base de
donnes. Vous pouvez ensuite prciser le mode, SHA-1, et le nom de chier :
Dans ce cas, vous prcisez le mode 100644, qui signie que cest un chier normal. Les alternatives sont 100755, qui signie que cest un excutable et 120000, qui prcise que cest un lien
229
symbolique. Le concept de mode a t repris des mode UNIX, mais est beaucoup moins exible
: ces trois modes sont les seuls valides pour Git, pour les chiers (blobs) (bien que dautres modes
soient utiliss pour les rpertoires et sous-modules).
Vous pouvez maintenant utiliser la commande write-tree pour crire la zone daente
dans un objet arbre. Loption -w est inutile (appeler write-tree cre automatiquement un objet
arbre partir de ltat de lindex si cet arbre nexiste pas) :
$ git write-tree
d8329fc1cc938780ffdd9f94e0d364e0ea74f579
$ git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579
100644 blob 83baae61804e65cc73a7201a7252750c76066a30
test.txt
Vous allez crer maintenant un nouvel arbre avec la seconde version de test.txt et un nouveau
chier :
Votre zone daente contient maintenant la nouvelle version de test.txt ainsi quun nouveau
chier new.txt. Enregistrez cet arbre (i.e. enregistrez ltat de la zone daente ou de lindex dans
un objet arbre) :
$ git write-tree
0155eb4229851634a0f03eb265b69f5a2d56f341
$ git cat-file -p 0155eb4229851634a0f03eb265b69f5a2d56f341
100644 blob fa49b077972391ad58037050f2a75f74e3671e92
new.txt
test.txt
Remarquez que cet arbre contient des entres pour les deux chiers et que lempreinte SHA
de test.txt est lempreinte de la version 2 de tout lheure (1f7a7a). Pour le plaisir, ajoutez le
premier arbre celui-ci, en tant que sous-rpertoire. Vous pouvez maintenant rcuprer un arbre
de votre zone daente en excutant read-tree. Dans ce cas, vous pouvez rcuprer un arbre
existant dans votre zone daente comme tant un sous-arbre en utilisant loption --prefix de
read-tree :
230
bak
new.txt
test.txt
Si vous crez un rpertoire de travail partir du nouvel arbre que vous venez denregistrer,
vous aurez deux chiers la racine du rpertoire de travail, ainsi quun sous-rpertoire appel bak
qui contient la premire version du chier test.txt. Vous pouvez vous reprsenter les donnes que
Git utilise pour ces structures comme sur la Figure 9.2.
231
Le format dun commit est simple : il contient larbre racine de linstantan du projet ce moment, les informations sur lauteur et le commiteur qui sont extraites des variables de conguration
user.name et user.email accompagnes dun horodatage, une ligne vide et le message de
commit.
Ensuite, vous enregistrez les deux autres objets commit, chacun rfrenant le commit dont il
est issu :
1a410efbd13591db07496601ebc7a059dd55cfe9
Chacun des trois objets commit pointe sur un arbre de linstantan que vous avez crez. Curieusement, vous disposez maintenant dun historique Git complet que vous pouvez visualiser avec la
commande git log, si vous la lancez sur le SHA-1 du dernier commit :
third commit
bak/test.txt |
1 +
second commit
new.txt
test.txt |
1 +
2 +-
first commit
test.txt |
1 +
232
Fantastique. Vous venez deectuer les oprations bas niveaux pour construire un historique
Git sans avoir utilis aucune des commandes haut niveau. Cest lessence de ce que fait Git quand
vous excutez les commandes git add et git commit. Il stocke les blobs correspondant aux
chiers modis, met jour lindex, crit les arbres et ajoute les objets commit qui rfrencent les
arbres racines venant juste avant eux. Ces trois objets principaux (le blob, larbre et le commit) sont
initialement stocks dans des chiers spars du rpertoire .git/objects. Voici tous les objets
contenus dans le rpertoire exemple, comments daprs leur contenu :
Si vous suivez les pointeurs internes de ces objets, vous obtenez un graphe comme celui de la
Figure 9.3.
233
Git construit un en-tte qui commence avec le type de lobjet, ici un blob. Ensuite, il ajoute un
espace suivi de taille du contenu, et enn un octet nul :
Git concatne len-tte avec le contenu original et calcule lempreinte SHA-1 du nouveau contenu. En Ruby, vous pouvez calculer lempreinte SHA-1 dune chane, en incluant la bibliothque
digest/SHA-1 via la commande require, puis en appelant Digest::SHA1.hexdigest()
sur la chane :
Git compresse le nouveau contenu avec zlib, ce que vous pouvez faire avec la bibliothque zlib
de Ruby. Vous devez inclure la bibliothque et excuter Zlib::Deflate.deflate() sur le
contenu :
Finalement, vous enregistrerez le contenu compress dans un objet sur le disque. Vous dterminerez le chemin de lobjet que vous voulez enregistrer (les deux premiers caractres de lempreinte
SHA-1 formeront le nom du sous-rpertoires, et les 38 derniers formeront le nom du chier dans ce
rpertoire). En Ruby, on peut utiliser la fonction FileUtils.mkdir_p() pour crer un sousrpertoire sil nexiste pas. Ensuite, ouvrez le chier avec File.open() et enregistrez le contenu
compress en appelant la fonction write() sur la rfrence du chier :
Cest tout ! Vous venez juste de crer un objet Blob valide. Tout les objets Git sont stocks de
la mme faon, mais avec des types dirents : len-tte commencera par commit ou arbre
234
au lieu de la chane blob . Bien que le contenu dun blob puisse tre presque nimporte quoi, le
contenu dun commit ou dun arbre est format dune faon particulire.
$ find .git/refs
.git/refs
.git/refs/heads
.git/refs/tags
$ find .git/refs -type f
$
Pour crer une nouvelle rfrence servant ce souvenir du dernier commit, vous pouvez simplement faire ceci :
Vous pouvez maintenant utiliser la rfrence principale que vous venez de crer la place de
lempreinte SHA-1 dans vos commandes Git :
master
Il nest pas conseill dditer directement les chiers des rfrences. Git propose une manire
sre de mere jour une rfrence, cest la commande update-ref :
Cest simplement ce quest une branche dans Git : un simple pointeur ou rfrence sur le dernier
tat dune suite de travaux. Pour crer une branche partir du deuxime commit, vous pouvez faire
ceci :
235
La base de donne Git ressemble maintenant quelque chose comme la Figure 9.4.
Figure 9.4: Le rpertoire dobjet de Git y compris la rfrence au dernier tat de la brane.
$ cat .git/HEAD
ref: refs/heads/master
Si vous excutez git checkout test, Git met jour ce chier, qui ressemblera ceci :
$ cat .git/HEAD
ref: refs/heads/test
236
and vous excutez git commit, il cre lobjet commit en spciant le parent du commit
comme tant lempreinte SHA-1 point par la rfrence du chier HEAD :
On peut diter manuellement ce chier, mais encore une fois, il existe une commande supplmentaire pour le faire : symbolic-ref. Vous pouvez lire le contenu de votre chier HEAD avec
cee commande :
Vous ne pouvez pas initialiser une rfrence symbolique une valeur non contenu dans refs :
9.3.2 tiquettes
Nous venons de parcourir les trois types dobjet utilis par Git, mais il existe un quatrime objet.
Lobjet tiquee (tag en anglais) ressemble beaucoup un objet commit. Il contient un tiqueteur,
une date, un message, et un pointeur. La principale dirence est que ltiquee pointe vers un
commit plutt quun arbre. Cest comme une rfrence une branche, mais elle ne bouge jamais :
elle pointe toujours vers le mme commit, lui donnant un nom plus sympathique.
Comme prsent au chapitre 2, il existe deux types dtiquees : annote et lgre. Vous pouvez
crer une tiquee lgre comme ceci :
Cest tout ce quest une tiquee lgre : une branche qui nest jamais modie. Une tiquee
annote annot est plus complexe. and on cre une tiquee annote, Git cre un objet tiquee,
puis enregistre une rfrence qui pointe vers lui plutt que directement vers le commit. Vous pouvez
voir ceci en crant une tiquee annote (-a spcie que cest une tiquee annote) :
$ cat .git/refs/tags/v1.1
9585191f37f7b0fb9444f35a9bf50de191beadc2
Remarquez que le contenu de lobjet pointe vers lempreinte SHA-1 du commit que vous avez
tiquet. Remarquez quil nest pas ncessaire quil pointe vers un commit. On peut tiqueter nimporte
quel objet. Par exemple, dans le code source de Git, le mainteneur a ajout ses cl GPG dans un blob
et la tiquet. Vous pouvez voir la cl publique en excutant :
dans le code source de Git. Le noyau linux contient aussi une tiquee ne pointant pas vers un
commit : la premire tiquee cre pointe vers larbre initial lors de limportation du code source.
Ensuite, vous pouvez voir ltat de la branche master dans la rfrence distante origin la
dernire fois que vous avez communiqu avec le serveur en regardant le chier refs/remotes/
origin/master :
238
$ cat .git/refs/remotes/origin/master
ca82a6dff817ec66f44342007202690a93763949
Les rfrences distantes dirent des branches (rfrences refs/heads) principalement parce
quon ne peut pas les rcuprer dans le rpertoire de travail. Git les modie comme des marque pages
du dernier tat de ces branches sur le serveur.
Git compresse le contenu de ces chiers avec zlib, et on ne stocke pas grand chose, au nal, tous
ces chiers occupent seulement 925 octets. Ajoutons de plus gros contenu au dpt pour montrer
une fonctionnalit intressante de Git. Ajoutez le chier repo.rb de la bibliothque Grit que vous
avez manipuler plus tt. Il reprsente environ 12Ko de code source :
Si vous observez larbre qui en rsulte, vous verrez lempreinte SHA-1 du blob contenant le
chier repo.rb :
$ git cat-file -p master^{tree}
100644 blob fa49b077972391ad58037050f2a75f74e3671e92
new.txt
repo.rb
test.txt
239
new.txt
repo.rb
test.txt
Ce blob est un blob dirent. Bien que lon ait ajout une seule ligne la n dun chier en
faisant 400, Git enregistre ce nouveau contenu dans un objet totalement dirent :
Il y a donc deux objets de 12Ko quasiment identique sur le disque. Ne serait-ce pas bien si Git
pouvait enregistrer un objet en entier, et le deuxime ntant quun delta (une dirence) avec le
premier ?
Il se trouve que cest possible. Le format initial dans lequel Git enregistre les objets sur le disque
est appel le format brut ( loose object ). De temps en temps, Git compacte plusieurs de ces objets
en un seul chier binaire appel packle (chier group), an dconomiser de lespace et dtre
plus ecace. Git eectue cee opration quand il y a trop dobjets au format brut, ou si lon excute
manuellement la commande git gc, ou encore quand on pousse vers un serveur distant. Pour voir
cela en action, vous pouvez demander manuellement Git de compacter les objets en excutant la
commande git gc :
$ git gc
Counting objects: 17, done.
Delta compression using 2 threads.
Compressing objects: 100% (13/13), done.
Writing objects: 100% (17/17), done.
Total 17 (delta 1), reused 10 (delta 0)
240
Si lon jee un il dans le rpertoire des objets, on constatera que la plupart des objets ne sont
plus l et quun couple de chier est apparu :
Les objets restant sont des blobs qui ne sont points par aucun commit. Dans notre cas, il sagit
des blobs what is up, doc? et test content crs plus tt comme exemple. Puisquil nont t
ajout aucun commit, ils sont considrs en suspend et ne sont pas compacter dans le nouveau
chier group.
Les autres chiers sont le nouveau chier gorup et un index. Le chier group est un chier
unique contenant le contenu de tous les objets venant dtre supprims du systme de chier. Lindex
est un chier contenant les emplacements dans le chier group, pour que lon puisse accder rapidement un objet particulier. Ce qui est vraiment bien est que les objets occupaient environ 12Ko
despace disque avant gc, et que le nouveau chier group en occupe seulement 6Ko. On a divis
par deux loccupation du disque en regroupant les objets.
Comment Git ralise-t-il cela ? and Git compacte des objets, il recherche les chiers qui ont
des noms et des tailles similaires, puis enregistre seulement les deltas entre une version du chier
et la suivante. On peut regarder lintrieur du chier group et voir lespace conomis par Git.
La commande de plomberie git verify-pack vous permet de voir ce qui a t compact :
$ git verify-pack -v \
.git/objects/pack/pack-7a16e4488ae40c7d2bc56ea2bd43e25212a66c45.idx
0155eb4229851634a0f03eb265b69f5a2d56f341 tree
71 76 5400
05408d195263d853f09dca71d55116663690c27c blob
09f01cea547666f58d6a8d809583841a7c6f0130 tree
10 19 5381
3c4e9cd789d88d8d89c1073707c3585e41b0e614 tree
10 19 5362
9585191f37f7b0fb9444f35a9bf50de191beadc2 tag
9bc1dc421dcd51b4ac296e3e5b6e2a99cf44391e blob
7 18 5193 1
05408d195263d853f09dca71d55116663690c27c \
ab1afef80fac8e34258ff41fc1b867c702daa24b commit 232 157 12
cac0cab538b970a37ea1e769cbbde608743bc96d commit 226 154 473
d8329fc1cc938780ffdd9f94e0d364e0ea74f579 tree
36 46 5316
e3f094f522629ae358806b17daf78246c27c007b blob
f8f51d7d8a1760462eca26eebafde32087499533 tree
fa49b077972391ad58037050f2a75f74e3671e92 blob
9 18 856
Si on se souvient bien, le blob 9bc1d, qui est la premire version de chier repo.rb le,
241
rfrence le blob 05408, qui est la seconde version du chier. La troisime colonne de lachage
est la taille de lobjet dans le chier compact, et on peut voir que 05408 occupe 12Ko dans le chier,
mais que 9bc1d occupe seulement 7 octets. Ce qui est aussi intressant est que la seconde version
du chier est celle qui est enregistre telle quelle, tandis que la version originale est enregistre
sous forme dun delta. La raison en est que vous aurez sans doute besoin daccder rapidement aux
versions les plus rcentes du chier.
Une chose intressante propos de ceci est que lon peut recompacter tout moment. Git
recompacte votre base de donne occasionnellement, en essayant dconomiser de la place. Vous
pouvez aussi recompacter la main, en excutant la commande git gc vous-mme.
Cela ajoute une section au chier .git/config, contenant le nom du dpt distant (origin),
lURL de ce dpt, et la spcication des rfrences pour la rcupration :
[remote "origin"]
url = git@github.com:schacon/simplegit-progit.git
fetch = +refs/heads/*:refs/remotes/origin/*
Ces syntaxes sont toutes quivalentes, car Git les dveloppe en refs/remotes/origin/
master.
Si vous prfrez que Git rcupre seulement la branche master, et non chacune des branches
du serveur distant, vous pouvez remplacer la ligne fetch par :
242
fetch = +refs/heads/master:refs/remotes/origin/master
Cest la spcication des rfrences de git fetch pour ce dpt distant. Si lon veut eectuer
une action particulire une seule fois, la spcication des rfrences peut aussi tre prcise en ligne
de commande. Pour retirer la branche master du dpt distant vers la branche locale origin/
mymaster, vous pouvez excutez :
Vous pouvez indiquer des spcications pour plusieurs rfrences. En ligne de commande, vous
pouvez tirer plusieurs branches de cee faon :
master
-> origin/mymaster
* [new branch]
topic
-> origin/topic
Dans ce cas, la rcupration /* pull */ de la branche master a t refus car ce ntait pas
une avance rapide. On peut surcharger ce comportement en prcisant un + devant la spcication
de la rfrence.
On peut aussi indiquer plusieurs spcications de rfrence pour la rcupration, dans le chier
de conguration. Si vous voulez toujours rcuprer les branches master /manque les baquotes
dans la version en/ et experiment, /* idem*/ ajoutez ces deux lignes :
[remote "origin"]
url = git@github.com:schacon/simplegit-progit.git
fetch = +refs/heads/master:refs/remotes/origin/master
fetch = +refs/heads/experiment:refs/remotes/origin/experiment
Vous ne pouvez pas utiliser des jokers partiels, ce qui suit est donc invalide :
fetch = +refs/heads/qa*:refs/remotes/origin/qa*
On peut toutefois utiliser des espaces de noms pour accomplir cela. Sil existe une quipe qualit
(QA) qui publie une srie de branches, et que lon veut la branche master, les branches de lquipe
qualit et rien dautre, on peut utiliser la conguration suivante :
243
[remote "origin"]
url = git@github.com:schacon/simplegit-progit.git
fetch = +refs/heads/master:refs/remotes/origin/master
fetch = +refs/heads/qa/*:refs/remotes/origin/qa/*
Si vous utilisez des processus complexes impliquant un quipe qualit, des dveloppeurs, et des
intgrateurs qui publient des branches et qui collaborent sur des branches distantes, vous pouvez
facilement utiliser des espaces des noms de cee faon.
Si elle veut que Git le fasse automatiquement chaque excution de git push origin,
elle peut ajouter une entre push au chier de conguration :
[remote "origin"]
url = git@github.com:schacon/simplegit-progit.git
fetch = +refs/heads/*:refs/remotes/origin/*
push = refs/heads/master:refs/heads/qa/master
De mme, cela fera que, par dfaut, git push origin publiera la branche locale master
sur la branche distante qa/master.
git://. Cee section fait un tour dhorizon du fonctionnement de ces deux protocoles.
La premire chose que fait cee commande est de rcuprer le chier info/refs. Ce chier
est crit par la commande update-server-info, et cest pour cela quil faut activer le hook
post-receive, sinon le transfert HTTP ne fonctionnera pas correctement :
refs/heads/master
On possde maintenant une liste des rfrences distantes et empreintes SHA1. Ensuite, on
regarde vers quoi pointe HEAD, pour savoir sur quelle branche se placer quand on aura ni :
On aura besoin de se placer sur la branche master, quand le processus sera termin. On
est maintenant prt dmarrer le processus de parcours. Puisque votre point de dpart est lobjet
commit ca82a6 que vous avez vu dans le chier info/refs, vous commencez par le rcuprer :
Vous obtenez un objet, cet objet est dans le format brut sur le serveur, et vous lavez rcupr
travers une requte HTTP GET statique. Vous pouvez le dcompresser avec zlib, ignorer lentte,
et regarder le contenu du commit :
245
Puis, vous avez deux autres objets supplmentaires rcuprer : cfda3b qui est larbre du
contenu sur lequel pointe le commit que nous venons de rcuprer, et 085bb3 qui est le commit
parent :
Oups, on dirait que lobjet arbre nest pas au format brut sur le serveur, vous obtenez donc une
rponse 404. On peut en dduire certaines raisons : lobjet peut tre dans un dpt supplant, ou il
peut tre dans un chier group de ce dpt. Git vrie la liste des dpts supplants dabord :
Si la rponse contenait une liste dURLs supplantes, Git aurait cherch les chiers bruts et les
chiers groups ces emplacements, cest un mcanisme sympatique pour les projets qui ont drivs
dun autre pour partager les objets sur le disque. Cependant, puisquil ny a pas de supplants lists
dans ce cas, votre objet doit se trouver dans un chier group. Pour voir quels chiers groups sont
disponibles sur le serveur, vous avez besoin de rcuprer le chier objects/info/packs, qui
en contient la liste (gnre galement par update-server-info) :
Il nexiste quun seul chier group sur le serveur, votre objet se trouve videmment dedans,
but vous allez tout de mme vrier lindex pour tre sr. Cest galement utile lorsque vous avez
plusieurs chiers groups sur le serveur, vous pouvez donc voir quel chier group contient lobjet
que vous avez besoin :
Maintenant que vous avez lindex du chier group, vous pouvez voir si votre objet est bien
dedans, car lindex liste les empreintes SHA-1 des objets contenus dans ce chier group et des
emplacements de ces objets. Votre objet est l, allez donc rcuprer le chier group complet :
246
Vous avez votre objet arbre, vous continuez donc le chemin des commits. Ils sont galement
tous contenus dans votre chier group que vous venez de tlcharg, vous navez donc pas dautres
requtes faire au serveur. Git rcupre un copie de travail de votre branche master qui t
rfrenc par HEAD que vous avez tlcharg au dbut.
La sortie complte de cee procdure ressemble :
247
La valeur SHA-1 remplie de 0 signie quil ny avait rien cet endroit avant, car vous tes en
train dajouter la rfrence experiment. Si vous tiez en train de supprimer une rfrence, vous
verriez loppos : que des 0 du ct droit.
Git envoit une ligne pour chaque rfrence que lon met jour avec lancien SHA, le nouveau
SHA, et la rfrence en train dtre mise jour. La premire ligne contient galement les comptences du client. Puis, le client tlverse un chier group de tous les objets que le serveur na pas
encore. Finalement, le serveur rpond avec une indication de succs (ou dchec) :
000Aunpack ok
003fgit-upload-pack schacon/simplegit-progit.git\0host=myserver.com\0
248
Cela commence par les 4 octets dsignant la quantit de donnes qui suit, puis la commande
excuter suivi par un octet nul, puis le nom dhte du serveur suivi dun octet nul nal. Le dmon
Git vrie que la commande peut tre excute, que le dpt existe et soit accessible publiquement.
Si tout va bien, il appelle lexcutable upload-pack et lui passe la main.
Si vous tes en train de tirer (fetch) travers SSH, fetch-pack excute plutt quelque chose
du genre :
Dans tous les cas, aprs que fetch-pack se connecte, upload-pack lui rpond quelque
chose du style :
Cest trs proche de ce que rpondait receive-pack, mais les comptences sont direntes.
En plus, il vous rpond la rfrence HEAD, an que le client sache quoi rcuprez dans le cas dun
clone.
ce moment, lexcutable fetch-pack regarde quels objets il a et rpond avec les objets
dont il a besoin en envoyant want (vouloir) suivi du SHA quil veut. Il envoit tous les objets quil
a dj avec have suivi du SHA. la n de la liste, il crit done pour initialiser lexcutable
upload-pack commencer envoyer le chier group des donnes demandes :
Cest le cas basique dun protocole de transfert. Dans des cas plus complexes, le client a des
comptendes multi_ack (plusieurs rponses) ou side-band (plusieurs connexions), mais cet
exemple vous montre les bases du protocole intelligent.
9.7.1 Maintenance
De temps en temps, Git excute automatiquement une commande appele auto gc . La plupart du temps, cee commande ne fait rien. Cependant, sil y a trop dobjets bruts (des objets qui
249
ne sont pas dans des chiers groups), ou trop de chiers groups, Git lance une commande git
gc part entire. gc est labbrviation pour garbage collect (ramasse-miees), et la commande
fait plusieurs choses : elle rassemble plusieurs objets bruts et les place dans un chiers groups, elle
consolide des chiers groups en un gros chier group, et elle supprim des objets qui ne sont plus
accessibles depuis un commit et qui sont vieux de plusieurs mois.
Vous pouvez excuter auto gc manuellement :
$ git gc --auto
Encore une fois, cela ne fait gnralement rien. Vous devez avoir environ 7.000 objets bruts ou
plus de 50 chiers groups pour que Git appelle une vraie commande gc. Vous pouvez modier ces
limites avec les proprits de conguration gc.auto et gc.autopacklimit, respectivement.
gc regroupera aussi vos rfrences dans un seul chier. Supposons que votre dpt contienne
les branches et tiquees suivantes :
Si vous excutez git gc, vous naurez plus ces chiers dans votre rpertoire refs. Git les
dplacera pour le bien de lecacit dans un chier nomm .git/packed-refs qui ressemble
ceci :
$ cat .git/packed-refs
# pack-refs with: peeled
cac0cab538b970a37ea1e769cbbde608743bc96d refs/heads/experiment
ab1afef80fac8e34258ff41fc1b867c702daa24b refs/heads/master
cac0cab538b970a37ea1e769cbbde608743bc96d refs/tags/v1.0
9585191f37f7b0fb9444f35a9bf50de191beadc2 refs/tags/v1.1
^1a410efbd13591db07496601ebc7a059dd55cfe9
Si vous meez jour une rfrence, Git ne modiera pas ce chier, mais enregistrera plutt
un nouveau chier dans refs/heads. Pour obtenire lempreinte SHA appropri pour rfrence
donne, Git cherche dabord cee rfrence dans le rpertoire refs, puis dans le chier packedrefs si non trouve. Cependant, vous ne pouvez pas trouver une rfrence dans votre rpertoire
refs, elle est probablement dans votre chier packed-refs.
Remarquez la dernire ligne du chier, celle commenant par . Cela signie que ltiquee
directement au-dessus est une tiquee annote et que cee ligne est le commit que ltiquee
annote rfrence.
vail, et il se trouve que vous voulez cee branche nalement; ou vous avez rinitialiser une branche
avec suppression, en abandonnant des commits dont vous vouliez des informations. Supposons que
cela arrive, comment pouvez-vous rcuprer vos commits ?
Voici un exemple qui rinitialise la branche master avec suppression dans votre dpt de test
vers un ancien commit et qui rcupre les commits perdus. Premirement, vrions dans quel tat
est votre dpt en ce moment :
Vous avez eectivement perdu les deux commits du haut, vous navez pas de branche depuis
laquelle ces commits seraient accessibles. Vous avez besoin de trouver le SHA du dernier commit et
dajouter une branche sy rfrant. Le problme est de trouver ce SHA, ce nest pas comme si vous
laviez mmoris, hein ?
Souvent, la manire la plus rapide est dutiliser loutil git reflog Pendant que vous travaillez, Git enregistre lemplacement de votre HEAD chaque fois que vous le changez. chaque
commit ou commutation de branche, le journal des rfrences (reog) est mis jour. Le journal des
rfrences est aussi mis jour par la commande git update-ref, qui est une autre raison de
lutiliser plutt que de simplement crire votre valeur SHA dans vos chiers de rfrences, comme
mentionn dans la section Git References plus haut dans ce chapitre. Vous pouvez voir o vous
tiez nimporte quel moment en excutant git reflog :
$ git reflog
1a410ef HEAD@{0}: 1a410efbd13591db07496601ebc7a059dd55cfe9: updating HEAD
ab1afef HEAD@{1}: ab1afef80fac8e34258ff41fc1b867c702daa24b: updating HEAD
Ici, nous pouvons voir deux commits que nous avons rcuprs, cependant, il ny a pas plus
dinformation ici. Pour voir, les mmes informations dune manire plus utile, nous pouvons excuter git log -g, qui nous donnera une sortie normalise pour votre journal de rfrences
:
251
$ git log -g
commit 1a410efbd13591db07496601ebc7a059dd55cfe9
Reflog: HEAD@{0} (Scott Chacon <schacon@gmail.com>)
Reflog message: updating HEAD
Author: Scott Chacon <schacon@gmail.com>
Date:
third commit
commit ab1afef80fac8e34258ff41fc1b867c702daa24b
Reflog: HEAD@{1} (Scott Chacon <schacon@gmail.com>)
Reflog message: updating HEAD
Author: Scott Chacon <schacon@gmail.com>
Date:
On dirait que le commit du bas est celui que vous avez perdu, vous pouvez donc le rcuprer
en crant une nouvelle branche sur ce commit. Par exemple, vous crez une branche nomme
recover-branch au commit (ab1afe):
Super, maintenant vous avez une nouvelle branche appele recover-branch lemplacement
o votre branche master tait, faisant en sorte que les deux premiers commits soit nouveau accessibles.
Pour poursuivre, nous supposerons que vos pertes ne sont pas dans le journal des rfrences
pour une raison quelconque. On peut simuler cela en supprimant recover-branch et le journal
des rfrences. Maintenant, les deux premiers commits ne sont plus accessibles (encore) :
Puisque les donnes du journal de rfrence sont sauvegards dans le rpertoire .git/logs/,
vous navez eectivement plus de journal de rfrences. Comment pouvez-vous rcuprer ces commits maintenant ? Une manire de faire est dutiliser loutil git fsck, qui vrie lintgrit de
votre base de donnes. Si vous lexcutez avec loption --full, il vous montre tous les objets qui
ne sont pas rfrencs par dautres objets :
252
Dans ce cas, vous pouvez voir votre commit manquant aprs dangling commit . Vous pouvez
le restaurez de la mme manire que prcdemment, en crant une branche qui rfrence cee
empreinte SHA.
Oups, vous ne vouliez pas rajouter une norme archive votre projet. Il vaut mieux sen dbarrasser :
253
$ git rm git.tbz2
rm 'git.tbz2'
$ git commit -m 'oops - removed large tarball'
[master da3f30d] oops - removed large tarball
1 files changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 git.tbz2
Maintenant, faites un gc sur votre base de donnes, pour voir combien despace disque vous
utilisez :
$ git gc
Counting objects: 21, done.
Delta compression using 2 threads.
Compressing objects: 100% (16/16), done.
Writing objects: 100% (21/21), done.
Total 21 (delta 3), reused 15 (delta 1)
Vous pouvez excutez la commande count-objects pour voir rapidement combien despace
disque vous utilisez :
$ git count-objects -v
count: 4
size: 16
in-pack: 21
packs: 1
size-pack: 2016
prune-packable: 0
garbage: 0
Lentre size-pack est la taille de vos chiers groups en kilo-octets, vous utilisez donc
2Mo. Avant votre dernier commit, vous utilisiez environ 2Ko, clairement, supprimer le chier avec
le commit prcdent, ne la pas enlever de votre historique. chaque fois que quelquun clonera
votre dpt, il aura cloner les 2Mo pour rcuprer votre tout petit projet, parce que vous avez
accidentellement rajout un gros chier. Dbarrassons-nous en.
Premirement, vous devez le trouver. Dans ce cas, vous savez dj de quel chier il sagit. Mais
supposons que vous ne le sachiez pas, comment identieriez-vous quel(s) chier(s) prennent trop
de place ? Si vous excutez git gc, tous les objets sont des dans chiers groups; vous pouvez
identier les gros objets en utilisant une autre commande de plomberie appele git verifypack et en triant sur le troisime champ de la sortie qui est la taille des chiers. Vous pouvez
galement la faire suivre la commande tail car vous ne vous intressez quaux chiers les plus
gros :
05408d195263d853f09dca71d55116663690c27c blob
7a9eb2fba2b1811321254ac360970fc169ba2330 blob
254
Le gros objet est la n : 2Mo. Pour trouver quel chier cest, vous allez utilisez la commande rev-list, que vous avez utilis brivement dans le chapitre 7. Si vous meez loption
--objects rev-list, elle listera tous les SHA des commits et des blobs avec le chemin du
chier associs. Vous pouvez utilisez cee commande pour trouver le nom de votre blob :
Maintenant, vous voulez supprimer ce chier de toutes les arborescences passes. Vous pouvez
facilement voir quels commits ont modi ce chier :
Vous devez rcrire tous les commits qui sont lis 6df76 pour supprimer totalement ce
chier depuis votre historique Git. Pour cela, utilisez filter-branch, que vous avez utilis dans
le Chapitre 6 :
255
$ rm -Rf .git/refs/original
$ rm -Rf .git/logs/
$ git gc
Counting objects: 19, done.
Delta compression using 2 threads.
Compressing objects: 100% (14/14), done.
Writing objects: 100% (19/19), done.
Total 19 (delta 3), reused 16 (delta 1)
$ git count-objects -v
count: 8
size: 2040
in-pack: 19
packs: 1
size-pack: 7
prune-packable: 0
garbage: 0
La taille du dpt regroup est retomb 7Ko, ce qui est beaucoup que 2Mo. Vous pouvez voir
dans la valeur size que votre gros objet est toujours dans vos objets bruts, il nest donc pas parti;
mais il ne sera plus transfr lors dune pousse vers un serveur ou un clone, ce qui est limportant
dans lhistoire. Si vous voulez rellement, vous pouvez supprimer compltement lobjet en excutant
git prune --expire.
9.8 Rsum
Vous devriez avoir une plutt bonne comprhension de ce que Git fait en arrire plan, et, un
certain degr, comment cest implment. Ce chapitre a parcouru un certain nombre de commande
de plomberie, commandes qui sont un niveau plus bas et plus simple que les commandes de porcelaine que vous avez aprs dans le reste du livre. Comprendre comment Git travaille bas niveau
devrait vous aider comprendre pourquoi il fait ce quil fait et crer vos propres outils et scripts
pour que votre workow fonctionne comme vous lentendez.
Git, comme un systme de chiers adressables par contenu, est un outil puissant que vous
pouvez utilisez pour des fonctionnalits au del dun SVC. Jespre que vous pourrez utilisez votre
connaissance nouvellement acquise des trippes de Git pour implmenter votre propre super application de cee technologique et que vous vous sentirez plus laise utiliser Git de manire plus
pousse.
256