You are on page 1of 266

Pro Git

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

Table des matires


1

Dmarrage rapide

1.1

propos de la gestion de version . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.1.1

Les systmes de gestion de version locaux . . . . . . . . . . . . . . . . . . .

1.1.2

Les systmes de gestion de version centraliss . . . . . . . . . . . . . . . . .

1.1.3

Les systmes de gestion de version distribus . . . . . . . . . . . . . . . . .

1.2

Une rapide histoire de Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.3

Rudiments de Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.3.1

Des instantans, pas des dirences . . . . . . . . . . . . . . . . . . . . . . .

1.3.2

Presque toutes les oprations sont locales . . . . . . . . . . . . . . . . . . .

1.3.3

Git gre lintgrit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.3.4

Gnralement, Git ne fait quajouter des donnes . . . . . . . . . . . . . . .

1.3.5

Les trois tats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Installation de Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.4.1

Installation depuis les sources . . . . . . . . . . . . . . . . . . . . . . . . . .

1.4.2

Installation sur Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.4.3

Installation sur Mac . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.4.4

Installation sur Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Paramtrage la premire utilisation de Git . . . . . . . . . . . . . . . . . . . . . . .

1.4

1.5

1.5.1

Votre identit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

10

1.5.2

Votre diteur de texte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

10

1.5.3

Votre outil de dirences . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11

1.5.4

Vrier vos paramtres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11

1.6

Obtenir de laide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11

1.7

Rsum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

12

Les bases de Git

13

2.1

Dmarrer un dpt Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

13

2.1.1

Initialisation dun dpt Git dans un rpertoire existant . . . . . . . . . . .

13

2.1.2

Cloner un dpt existant . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

14

Enregistrer des modications dans le dpt . . . . . . . . . . . . . . . . . . . . . . .

14

2.2.1

Vrier ltat des chiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

15

2.2.2

Placer de nouveaux chiers sous suivi de version . . . . . . . . . . . . . . .

16

2.2.3

Indexer des chiers modis . . . . . . . . . . . . . . . . . . . . . . . . . . .

16

2.2.4

Ignorer des chiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

18

2.2.5

Inspecter les modications indexes et non indexes . . . . . . . . . . . . .

19

2.2.6

Valider vos modications . . . . . . . . . . . . . . . . . . . . . . . . . . . .

21

2.2

iii

2.3

2.4

2.5

2.6

2.7

2.8
3

liminer la phase dindexation . . . . . . . . . . . . . . . . . . . . . . . . . .

23

2.2.8

Eacer des chiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

23

2.2.9

Dplacer des chiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

24

Visualiser lhistorique des validations . . . . . . . . . . . . . . . . . . . . . . . . . .

25

2.3.1

Limiter la longueur de lhistorique . . . . . . . . . . . . . . . . . . . . . . .

29

2.3.2

Utiliser une interface graphique pour visualiser lhistorique . . . . . . . . .

30

Annuler des actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

31

2.4.1

Modier le dernier commit . . . . . . . . . . . . . . . . . . . . . . . . . . . .

31

2.4.2

Dsindexer un chier dj index . . . . . . . . . . . . . . . . . . . . . . . .

32

2.4.3

Rinitialiser un chier modi . . . . . . . . . . . . . . . . . . . . . . . . . .

33

Travailler avec des dpts distants . . . . . . . . . . . . . . . . . . . . . . . . . . . .

34

2.5.1

Acher les dpts distants . . . . . . . . . . . . . . . . . . . . . . . . . . . .

34

2.5.2

Ajouter des dpts distants . . . . . . . . . . . . . . . . . . . . . . . . . . .

35

2.5.3

Rcuprer et tirer depuis des dpts distants . . . . . . . . . . . . . . . . . .

35

2.5.4

Pousser son travail sur un dpt distant . . . . . . . . . . . . . . . . . . . .

36

2.5.5

Inspecter un dpt distant . . . . . . . . . . . . . . . . . . . . . . . . . . . .

36

2.5.6

Retirer et dplacer des branches distantes . . . . . . . . . . . . . . . . . . .

37

Balisage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

38

2.6.1

Lister vos balises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

38

2.6.2

Crer des balises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

38

2.6.3

Les balises annotes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

39

2.6.4

Les balises signes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

39

2.6.5

Les balises lgres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

40

2.6.6

Vrier des balises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

41

2.6.7

Baliser aprs coup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

41

2.6.8

Partager les balises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

42

Trucs et astuces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

43

2.7.1

Auto-Compltion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

43

2.7.2

Les alias Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

44

Rsum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

45

Les branes avec Git

47

3.1

Ce quest une branche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

47

3.2

Brancher et fusionner : les bases . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

52

3.2.1

Le branchement de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

52

3.2.2

Les bases de la fusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

55

3.2.3

Conits de fusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

57

3.3

Gestion de branches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

59

3.4

Travailler avec les branches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

61

3.4.1

Branches au long cours . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

61

3.4.2

Les branches de sujet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

62

Les branches distantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

63

3.5.1

Pousser vers un serveur . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

65

3.5.2

Suivre les branches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

67

3.5.3

Eacer des branches distantes . . . . . . . . . . . . . . . . . . . . . . . . . .

68

Rebaser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

68

3.5

3.6
iv

2.2.7

3.7
4

3.6.1

Les bases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

68

3.6.2

Rebasages plus intressants . . . . . . . . . . . . . . . . . . . . . . . . . . .

70

3.6.3

Les dangers de rebaser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

72

Rsum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

74

Git sur le serveur

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

Installation de Git sur un serveur . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

80

4.2.1

Copie du dpt nu sur un serveur . . . . . . . . . . . . . . . . . . . . . . . .

80

4.2.2

Petites installations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

81

Accs SSH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

81

4.3

Gnration des clefs publiques SSH . . . . . . . . . . . . . . . . . . . . . . . . . . .

82

4.4

Mise en place du serveur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

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

Cration dun compte utilisateur . . . . . . . . . . . . . . . . . . . . . . . .

95

4.9.3

Cration dun nouveau dpt . . . . . . . . . . . . . . . . . . . . . . . . . .

96

4.9.4

Import depuis Subversion . . . . . . . . . . . . . . . . . . . . . . . . . . . .

98

4.9.5

Ajout des collaborateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

98

4.9.6

Votre projet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

99

4.9.7

Duplication de projets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100

4.9.8

Rsum sur GitHub . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101

4.1.2

4.1.3

4.1.4

4.2

4.10 Rsum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101


5

Git distribu
5.1

5.2

103

Dveloppements distribus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103


5.1.1

Gestion centralise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103

5.1.2

Mode du gestionnaire dintgration . . . . . . . . . . . . . . . . . . . . . . . 104

5.1.3

Mode dictateur et ses lieutenants . . . . . . . . . . . . . . . . . . . . . . . . 105

Contribution un projet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106


v

5.3

5.2.1

Guides pour une validation . . . . . . . . . . . . . . . . . . . . . . . . . . . 106

5.2.2

Cas dune petite quipe prive . . . . . . . . . . . . . . . . . . . . . . . . . . 108

5.2.3

quipe prive importante . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114

5.2.4

Petit projet public . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117

5.2.5

Grand projet public . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121

5.2.6

Rsum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

Maintenance dun projet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124


5.3.1

Travail dans des branches thmatiques . . . . . . . . . . . . . . . . . . . . . 124

5.3.2

Application des patchs partir de-mail . . . . . . . . . . . . . . . . . . . . 125


Application dun patch avec apply . . . . . . . . . . . . . . . . . . . . . . . 125
Application dun patch avec am . . . . . . . . . . . . . . . . . . . . . . . . . 125

5.3.3

Vrication des branches distantes . . . . . . . . . . . . . . . . . . . . . . . 128

5.3.4

Dterminer les modications introduites . . . . . . . . . . . . . . . . . . . . 129

5.3.5

Intgration des contributions . . . . . . . . . . . . . . . . . . . . . . . . . . 130


Modes de fusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
Gestions avec nombreuses fusions . . . . . . . . . . . . . . . . . . . . . . . 131
Gestion par rebasage et slection de commit . . . . . . . . . . . . . . . . . . 133

5.4
6

5.3.6

Balisage de vos publications . . . . . . . . . . . . . . . . . . . . . . . . . . . 135

5.3.7

Gnration dun nom de rvision . . . . . . . . . . . . . . . . . . . . . . . . 136

5.3.8

Prparation dune publication . . . . . . . . . . . . . . . . . . . . . . . . . . 136

5.3.9

Shortlog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137

Rsum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137

Utilitaires Git
6.1

139

Slection des versions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139


6.1.1

Rvisions ponctuelles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139

6.1.2

Empreinte SHA courte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139

6.1.3

QUELQUES MOTS SUR SHA-1 . . . . . . . . . . . . . . . . . . . . . . . . . 140

6.1.4

Rfrences de branches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141

6.1.5

Raccourcis RefLog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141

6.1.6

Rfrences passes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142

6.1.7

Plages de commits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144


Double point . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
Emplacements multiples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Triple point . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146

6.2

6.3

6.4

vi

Mise en aente interactive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146


6.2.1

Mere en aente des chiers . . . . . . . . . . . . . . . . . . . . . . . . . . 147

6.2.2

Patches de Staging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149

La remise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
6.3.1

Remiser votre travail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151

6.3.2

Crer une branche depuis une remise . . . . . . . . . . . . . . . . . . . . . . 153

Rcrire lhistorique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153


6.4.1

Modier la dernire consignation . . . . . . . . . . . . . . . . . . . . . . . . 154

6.4.2

Modier plusieurs messages de consignation . . . . . . . . . . . . . . . . . . 154

6.4.3

Rordonner les commits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156

6.4.4

Rassembler des commits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157

6.4.5

Diviser un commit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158

6.4.6

Loption nuclaire : lter-branch . . . . . . . . . . . . . . . . . . . . . . . . 159


Supprimer un chier de chaque commit . . . . . . . . . . . . . . . . . . . . 159
Faire dun sous-rpertoire la nouvelle racine . . . . . . . . . . . . . . . . . . 159
Modier globalement ladresse mail . . . . . . . . . . . . . . . . . . . . . . . 160

6.5

6.6

Deboguer avec Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160


6.5.1

Fichier annot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160

6.5.2

La recherche dichotomique . . . . . . . . . . . . . . . . . . . . . . . . . . . 161

Sous-modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
6.6.1

Dmarrer un sous-module . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164

6.6.2

Cloner un projet avec des sous-modules . . . . . . . . . . . . . . . . . . . . 166

6.6.3

Superprojects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168

6.6.4

Les problmes avec les sous-modules . . . . . . . . . . . . . . . . . . . . . . 168

6.7

Fusion de sous-arborescence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170

6.8

Rsum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172

Personnalisation de Git
7.1

173

Conguration de Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173


7.1.1

Conguration de base dun client . . . . . . . . . . . . . . . . . . . . . . . . 174


core.editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
commit.template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
core.pager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
user.signingkey . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
core.excludesle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
help.autocorrect . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176

7.1.2

Couleurs dans Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176


color.ui . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
color.* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177

7.1.3

Outils externes de fusion et de dirence . . . . . . . . . . . . . . . . . . . . 177

7.1.4

Formatage and espaces blancs . . . . . . . . . . . . . . . . . . . . . . . . . . 180


core.autocrlf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
core.whitespace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181

7.1.5

Conguration du serveur . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182


receive.fsckObjects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
receive.denyNonFastForwards . . . . . . . . . . . . . . . . . . . . . . . . . . 182
receive.denyDeletes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182

7.2

Aributs Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183


7.2.1

Fichiers binaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183


Identication des chiers binaires . . . . . . . . . . . . . . . . . . . . . . . . 183
Comparaison de chiers binaires . . . . . . . . . . . . . . . . . . . . . . . . 184

7.2.2

Expansion des mots-cls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186

7.2.3

Export dun dpt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188


export-ignore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
export-subst . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189

7.2.4
7.3

Stratgies de fusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189

Crochets Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190


vii

7.3.1

Installation dun crochet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190

7.3.2

Crochets ct client . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190


Crochets de traitement de validation . . . . . . . . . . . . . . . . . . . . . . 190
Crochets de gestion e-mail . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
Autres crochets ct client . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191

7.3.3

Crochets ct serveur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192


pre-receive et post-receive . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
update . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192

7.4

Exemple de politique gre par Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193


7.4.1

Crochets ct serveur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193


Application dune politique de format du message de validation . . . . . . . 193
Mise en place dun systme dACL par utilisateur . . . . . . . . . . . . . . . 195
Application des pousses en avance rapide . . . . . . . . . . . . . . . . . . . 197

7.4.2
7.5
8

Crochets ct client . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199

Rsum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202

Git et les autres systmes


8.1

203

Git et Subversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203


8.1.1

git svn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203

8.1.2

Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204

8.1.3

Dmarrage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205

8.1.4

Valider en retour sur le serveur Subversion . . . . . . . . . . . . . . . . . . 206

8.1.5

Tirer des modications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207

8.1.6

Le problme avec les branches Git . . . . . . . . . . . . . . . . . . . . . . . 209

8.1.7

Les embranchements dans Subversion . . . . . . . . . . . . . . . . . . . . . 210


Crer une nouvelle branche SVN . . . . . . . . . . . . . . . . . . . . . . . . 210

8.1.8

Basculer de branche active . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210

8.1.9

Les commandes Subversion . . . . . . . . . . . . . . . . . . . . . . . . . . . 211


Lhistorique dans le style Subversion . . . . . . . . . . . . . . . . . . . . . . 211
Les annotations SVN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
Linformation sur la serveur SVN . . . . . . . . . . . . . . . . . . . . . . . . 212
Ignorer ce que Subversion ignore . . . . . . . . . . . . . . . . . . . . . . . . 213

8.1.10
8.2

8.3
9

viii

Rsum sur Git-Svn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213

Migrer sur Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214


8.2.1

Importer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214

8.2.2

Subversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214

8.2.3

Perforce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216

8.2.4

Un outil dimport personnalis . . . . . . . . . . . . . . . . . . . . . . . . . 218

Rsum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223

Les trippes de Git

225

9.1

Plomberie et porcelaine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225

9.2

Les objets Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226


9.2.1

Objets Arbre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228

9.2.2

Objets Commit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231

9.2.3

Stockage des objets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233

9.3

Rfrences Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235


9.3.1

La branche HEAD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236

9.3.2

tiquees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237

9.3.3

Rfrences distantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238

9.4

Fichiers groups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239

9.5

Les rfrences spciques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242

9.6

9.5.1

Publier une rfrence spcique . . . . . . . . . . . . . . . . . . . . . . . . . 244

9.5.2

Supprimer des rfrences . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244

Protocoles de transfert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244


9.6.1

Le protocole stupide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245

9.6.2

Le Protocole Intelligent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247


Tlverser des donnes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
Tlcharger des Donnes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248

9.7

9.8

Maintenance et Rcupration de Donnes . . . . . . . . . . . . . . . . . . . . . . . . 249


9.7.1

Maintenance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249

9.7.2

Rcupration de donnes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250

9.7.3

Supprimer des objets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253

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 propos de la gestion de version


est-ce que la gestion de version et pourquoi devriez-vous vous en soucier ? Un gestionnaire
de version est un systme qui enregistre lvolution dun chier ou dun ensemble de chiers au
cours du temps de manire ce quon puisse rappeler une version antrieure dun chier tout
moment. Dans les exemples de ce livre, nous utiliserons des chiers sources de logiciel comme
chiers sous gestion de version, bien quen ralit on puisse lutiliser avec pratiquement tous les
types de chiers dun ordinateur.
Si vous tes un dessinateur ou un dveloppeur web, et que vous voulez conserver toutes les
versions dune image ou dune mise en page (ce que vous souhaiteriez assurment), un systme de
gestion de version (VCS en anglais pour Version Control System) est un outil quil est trs sage
dutiliser. Il vous permet de ramener un chier un tat prcdent, ramener le projet complet
un tat prcdent, comparer les changements au cours du temps, voir qui a modi quelque chose
qui pourrait causer un problme, qui a introduit un problme et quand, et plus encore. Utiliser un
VCS signie aussi gnralement que si vous vous trompez ou que vous perdez des chiers, vous
pouvez facilement revenir un tat stable. De plus, vous obtenez tous ces avantages avec une faible
surcharge de travail.

1.1.1 Les systmes de gestion de version locaux


La mthode commune pour la gestion de version est gnralement de recopier les chiers dans
un autre rpertoire (peut-tre avec un nom incluant la date dans le meilleur des cas). Cee mthode
est la plus commune parce que cest la plus simple, mais cest aussi la moins able. Il est facile
doublier le rpertoire dans lequel vous tes et dcrire accidentellement dans le mauvais chier ou
dcraser des chiers que vous vouliez conserver.
Pour traiter ce problme, les programmeurs ont dvelopp il y a longtemps des VCSs locaux
qui utilisaient une base de donnes simple pour conserver les modications dun chier (voir gure
1

Chapitre 1 Dmarrage rapide

Sco Chacon Pro Git

1-1).

Figure 1.1: Diagramme des systmes de gestion de version locaux.

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.

1.1.2 Les systmes de gestion de version centraliss


Le problme majeur que les gens rencontrent est quils ont besoin de collaborer avec des
dveloppeurs sur dautres ordinateurs. Pour traiter ce problme, les systmes de gestion de version centraliss (CVCS en anglais pour Centralized Version Control Systems) furent dvelopps. Ces
systmes tels que CVS, Subversion, et Perforce, meent en place un serveur central qui contient
tous les chiers sous gestion de version, et des clients qui peuvent extraire les chiers de ce dpt
central. Pendant de nombreuses annes, cela a t le standard pour la gestion de version (voir gure
1-2).

Figure 1.2: Diagramme de la gestion de version centralise.

Ce schma ore de nombreux avantages par rapport la gestion de version locale. Par exemple,
2

Sco Chacon Pro Git

Section 1.1 propos de la gestion de version

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.

1.1.3 Les systmes de gestion de version distribus


Cest ce moment que les systmes de gestion de version distribus entrent en jeu (DVCSs en
anglais pour Distributed Version Control Systems). Dans un DVCS (tel que Git, Mercurial, Bazaar or
Darcs), les clients nextraient plus seulement la dernire version dun chier, mais ils dupliquent
compltement le dpt. Ainsi, si le serveur disparat, et si les systmes collaboraient via ce serveur,
nimporte quel dpt dun des clients peut tre copi sur le serveur pour le restaurer. Chaque extraction devient une sauvegarde complte de toutes les donnes (voir gure 1-3).

Figure 1.3: Diagramme de gestion de version de contrle centralise.

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

Chapitre 1 Dmarrage rapide

Sco Chacon Pro Git

1.2 Une rapide histoire de Git


Comme de nombreuses choses extraordinaires de la vie, Git est n avec une dose de destruction
crative et de controverse houleuse. Le noyau Linux est un projet libre de grande envergure. Pour la
plus grande partie de sa vie (1991-2002), les modications taient transmises sous forme de patchs et
darchives de chiers. En 2002, le projet du noyau Linux commena utiliser un DVCS propritaire
appel BitKeeper.
En 2005, les relations entre la communaut dveloppant le noyau linux et la socit en charge
du dveloppement de BitKeeper furent rompues, et le statut de gratuit de loutil fut rvoqu. Cela
poussa la communaut du dveloppement de Linux (et plus particulirement Linus Torvalds, le crateur de Linux) dvelopper leur propre outil en se basant sur les leons apprises lors de lutilisation
de BitKeeper. Certains des objectifs du nouveau systme taient les suivants :
Vitesse
Conception simple
Support pour les dveloppements non linaires (milliers de branches parallles)
Compltement distribu
Capacit grer ecacement des projets denvergure tels que le noyau Linux (vitesse et compacit des donnes)
Depuis sa naissance en 2005, Git a volu et mri pour tre facile utiliser tout en conservant ses
qualits initiales. Il est incroyablement rapide, il est trs ecace pour de grands projets et il a un
incroyable systme de branches pour des dveloppements non linaires (voir chapitre 3).

1.3 Rudiments de Git


Donc, quest-ce que Git en quelques mots ? Il est important de bien comprendre cee section,
parce que si on comprend ce que Git est et les principes sur lesquels il repose, alors utiliser ecacement Git devient simple. Au cours de lapprentissage de Git, essayez de librer votre esprit de
ce que vous pourriez connatre dautres VCS, tels que Subversion et Perforce ; ce faisant, vous vous
viterez de petites confusions lutilisation de cet outil. Git enregistre et gre linformation trs
diremment des autres systmes, mme si linterface utilisateur parat similaire ; comprendre ces
dirences vous vitera des confusions lutilisation.

1.3.1 Des instantans, pas des dirences


La dirence majeure entre Git et les autres VCS (Subversion et autres) rside dans la manire
dont Git considre les donnes. Au niveau conceptuel, la plupart des autres VCS grent linformation
comme une liste de modications de chiers. Ces systmes (CVS, Subversion, Perforce, Bazaar et
autres) considrent linformation quil grent comme une liste de chiers et les modications eectues sur chaque chier dans le temps, comme illustr en gure 1-4.
Git ne gre pas et ne stocke pas les informations de cee manire. la place, Git pense ses
donnes plus comme un instantan dun mini systme de chiers. A chaque fois que vous commitez
ou enregistrez ltat du projet dans Git, il prend eectivement un instantan du contenu de votre
espace de travail ce moment et enregistre une rfrence cet instantan. Pour tre ecace, si les
4

Sco Chacon Pro Git

Section 1.3 Rudiments de Git

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.

1.3.2 Presque toutes les oprations sont locales


La plupart des oprations de Git ne ncessite que des chiers et ressources locales - gnralement aucune information venant dun autre ordinateur du rseau nest ncessaire. Si vous tes
habitu un CVCS o toutes les oprations sont ralenties par la latence des changes rseau, cet aspect de Git vous fera penser que les dieux de la vitesse ont octroy leurs pouvoirs Git. Comme vous
disposez de lhistorique complet du projet localement sur votre disque dur, la plupart des oprations
semblent instantanes.
Par exemple, pour parcourir lhistorique dun projet, Git na pas besoin daller le chercher
sur un serveur pour vous lacher ; il na qu simplement le lire directement dans votre base de
donne locale. Cela signie que vous avez quasi-instantanment accs lhistorique du projet. Si
vous souhaitez connatre les modications introduites entre la version actuelle dun chier et son
tat un mois auparavant, Git peut rechercher ltat du chier un mois auparavant et raliser le
calcul de dirence, au lieu davoir demander cee dirence un serveur ou devoir rcuprer
lancienne version sur le serveur pour calculer la dirence localement.
Cela signie aussi quil y a trs peu de choses que vous ne puissiez raliser si vous ntes
pas connect ou hors VPN. Si vous voyagez en train ou en avion et voulez avancer votre travail,
vous pouvez continuer grer vos versions sans soucis en aendant de pouvoir de nouveau vous
5

Chapitre 1 Dmarrage rapide

Sco Chacon Pro Git

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.

1.3.3 Git gre lintgrit


Dans Git, tout est vri par une somme de contrle avant dtre stock et par la suite cee
somme de contrle, signature unique, sert de rfrence. Cela signie quil est impossible de modier
le contenu dun chier ou dun rpertoire sans que Git ne sen aperoive. Cee fonctionnalit est
ancre dans les fondations de Git et fait partie intgrante de sa philosophie. Vous ne pouvez pas
perdre des donnes en cours de transfert ou corrompre un chier sans que Git ne puisse le dtecter.
Le mcanisme que Git utilise pour raliser les sommes de contrle est appel une empreinte
SHA-1. Cest une chane de caractres compose de 40 caractres hexadcimaux (de 0 9 et de
a ) calcule en fonction du contenu du chier ou de la structure du rpertoire considr. Une
empreinte SHA-1 ressemble ceci :

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.

1.3.4 Gnralement, Git ne fait quajouter des donnes


and vous ralisez des actions dans Git, la quasi-totalit dentre elles ne font quajouter des
donnes dans la base de donnes de Git. Il est trs dicile de faire raliser au systme des actions
qui ne soient pas rversibles ou de lui faire eacer des donnes dune quelconque manire. Par
contre, comme dans la plupart des systmes de gestion de version, vous pouvez perdre ou corrompre
des modications qui nont pas encore t entres en base ; mais ds que vous avez commit un
instantan dans Git, il est trs dicile de le perdre, spcialement si en plus vous synchronisez votre
base de donnes locale avec un dpt distant.
Cela fait de lusage de Git un vrai plaisir, car on peut exprimenter sans danger de casser
dnitivement son projet. Pour une information plus approfondie sur la manire dont Git stocke
ses donnes et comment rcuprer des donnes qui pourraient sembler perdues, rfrez-vous au
chapitre 9 Sous le capot .

1.3.5 Les trois tats


Ici, il faut tre aentif. Il est primordial de se souvenir de ce qui suit si vous souhaitez que
le reste de votre apprentissage seectue sans dicult. Git gre trois tats dans lequel les chiers
peuvent rsider : commit, modi et index. Commit signie que les donnes sont stockes en
scurit dans votre base de donnes locale. Modi signie que vous avez modi le chier mais
6

Sco Chacon Pro Git

Section 1.4 Installation de Git

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.

Figure 1.6: Rpertoire de travail, zone dindex et rpertoire Git.

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.

1.4 Installation de Git


Commenons donc utiliser Git. La premire chose faire est de linstaller. Vous pouvez
lobtenir par de nombreuses manires ; les deux principales sont de linstaller partir des sources
7

Chapitre 1 Dmarrage rapide

Sco Chacon Pro Git

ou dinstaller un paquet existant sur votre plate-forme.

1.4.1 Installation depuis les sources


Si vous le pouvez, il est gnralement conseill dinstaller Git partir des sources, car vous
obtiendrez la version la plus rcente. Chaque nouvelle version de Git tend inclure des amliorations
utiles de linterface utilisateur, donc rcuprer la toute dernire version est souvent la meilleure
option si vous savez compiler des logiciels partir des sources. Comme la plupart du temps les
distributions contiennent des version trs anciennes de logiciels, moins que vous ne travailliez
sur une distribution trs rcente ou que vous nutilisiez des backports, une installation partir des
sources peut tre le meilleur choix.
Pour installer Git, vous avez besoin des bibliothques suivantes : curl, zlib, openssl, expat, libiconv. Par exemple, si vous avez un systme dexploitation qui utilise yum (tel que Fedora) ou
apt-get (tel quun systme bas sur Debian), vous pouvez utiliser lune des commandes suivantes
pour installer les dpendances :

$ yum install curl-devel expat-devel gettext-devel \


openssl-devel zlib-devel
$ apt-get install libcurl4-gnutls-dev libexpat1-dev gettext \
libz-dev libssl-dev

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 :

$ tar -zxf git-1.6.0.5.tar.gz


$ cd git-1.6.0.5
$ make prefix=/usr/local all
$ sudo make prefix=/usr/local install

Aprs ceci, vous pouvez obtenir Git par Git lui-mme pour les mises jour :

$ git clone git://git.kernel.org/pub/scm/git/git.git

1.4.2 Installation sur Linux


Si vous souhaitez installer Git sur Linux via un installateur dapplication, vous pouvez gnralement le faire via le systme de gestion de paquet de base fourni avec votre distribution. Si vous tes
sur Fedora, vous pouvez utiliser yum :

$ yum install git-core

Sco Chacon Pro Git

Section 1.5 Paramtrage la premire utilisation de Git

Si vous tes sur un systme bas sur Debian, tel quUbuntu, essayez apt-get :

$ apt-get install git-core

1.4.3 Installation sur Mac


Il y a deux moyens simples dinstaller Git sur Mac. Le plus simple et dutiliser linstallateur
graphique de Git que vous pouvez tlcharger depuis les pages Google Code (voir gure 1-7) :
http://code.google.com/p/git-osx-installer

Figure 1.7: Installateur OS X de Git.

Lautre mthode consiste installer Git par les MacPorts (http://www.macports.org).


Si vous avez install MacPorts, installez Git par :

$ sudo port install git-core +svn +doc +bash_completion +gitweb

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).

1.4.4 Installation sur Windows


Installer Git sur Windows est trs facile. Le projet msysGit fournit une des procdures dinstallation
les plus simples. Tlchargez simplement le chier exe dinstallateur depuis la page Google Code,
et lancez-le :
http://code.google.com/p/msysgit
Aprs son installation, vous avez la fois la version en ligne de commande (avec un client SSH
utile pour la suite) ou linterface graphique standard.

1.5 Paramtrage la premire utilisation de Git


Maintenant que vous avez install Git sur votre systme, vous voudrez personnaliser votre environnement Git. Vous ne devriez avoir raliser ces rglages quune seule fois ; ils persisteront lors
9

Chapitre 1 Dmarrage rapide

Sco Chacon Pro Git

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.

1.5.1 Votre identit


La premire chose faire aprs linstallation de Git est de renseigner votre nom et votre adresse
e-mail. Cest important car tous les commits Git utilisent cee information et elle est indlbile dans
tous les commits que vous pourrez manipuler :

$ git config --global user.name "John Doe"


$ git config --global user.email johndoe@example.com

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.

1.5.2 Votre diteur de texte


prsent que votre identit est renseigne, vous pouvez congurer lditeur de texte qui sera
utilis quand Git vous demande de saisir un message. Par dfaut, Git utilise lditeur congur
au niveau systme, qui est gnralement Vi ou Vim. Si vous souhaitez utiliser un diteur de texte
dirent, comme Emacs, vous pouvez entrer ce qui suit :

$ git config --global core.editor emacs

10

Sco Chacon Pro Git

Section 1.6 Obtenir de laide

1.5.3 Votre outil de dirences


Une autre option utile est le paramtrage de loutil de dirences utiliser pour la rsolution
des conits de fusion. Supposons que vous souhaitiez utiliser vimdi :

$ git config --global merge.tool vimdiff

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.

1.5.4 Vrier vos paramtres


Si vous souhaitez vrier vos rglages, vous pouvez utiliser la commande git config -list pour lister tous les rglages que Git a pu trouver jusquici :

$ git config --list


user.name=Scott Chacon
user.email=schacon@gmail.com
color.status=auto
color.branch=auto
color.interactive=auto
color.diff=auto
...

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> :

$ git config user.name


Scott Chacon

1.6 Obtenir de laide


Si vous avez besoin daide pour utiliser Git, il y a trois moyens dobtenir les pages de manuel
pour toutes les commandes de Git :

$ git help <verbe>


$ git <verbe> --help
$ man git-<verbe>

Par exemple, vous pouvez obtenir la page de manuel pour la commande cong en lanant :
11

Chapitre 1 Dmarrage rapide

Sco Chacon Pro Git

$ git help config

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

Les bases de Git


Si vous ne deviez lire quun chapitre avant de commencer utiliser Git, cest celui-ci. Ce
chapitre couvre les commandes de base ncessaires pour raliser la vaste majorit des activits
avec Git. la n de ce chapitre, vous devriez tre capable de congurer et initialiser un dpt, commencer et arrter le suivi de version de chiers, dindexer et valider des modications. Nous vous
montrerons aussi comment paramtrer Git pour quil ignore certains chiers ou patrons de chiers,
comment revenir sur les erreurs rapidement et facilement, comment parcourir lhistorique de votre
projet et voir les modications entre deux validations, et comment pousser et tirer les modications
avec des dpts distants.

2.1 Dmarrer un dpt Git


Vous pouvez principalement dmarrer un dpt Git de deux manires. La premire consiste
prendre un projet ou un rpertoire existant et limporter dans Git. La seconde consiste cloner un
dpt Git existant sur un autre serveur.

2.1.1 Initialisation dun dpt Git dans un rpertoire existant


Si vous commencer suivre un projet existant dans Git, vous navez qu vous positionner dans
le rpertoire du projet et saisir

$ 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

Chapitre 2 Les bases de Git

Sco Chacon Pro Git

$ git add *.c


$ git add README
$ git commit m 'version initiale du projet'

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.

2.1.2 Cloner un dpt existant


Si vous souhaitez obtenir une copie dun dpt Git existant par exemple, un projet auquel
vous aimeriez contribuer la commande dont vous avez besoin sappelle git clone. Si vous
tes familier avec dautres systmes de gestion de version tels que Subversion, vous noterez que la
commande est clone et non checkout. Cest une distinction importante Git reoit une copie de
quasiment toutes les donnes dont le serveur dispose. Toutes les versions de tous les chiers pour
lhistorique du projet sont tlcharges quand vous lancez git clone. En fait, si le disque du
serveur se corrompt, vous pouvez utiliser nimporte quel clone pour remere le serveur dans ltat
o il tait au moment du clonage (vous pourriez perdre quelques paramtres du serveur, mais toutes
les donnes sous gestion de version serait rcupres Cf. chapitre 4 pour de plus amples dtails).
Vous clonez un dpt avec git clone [url]. Par exemple, si vous voulez cloner la bibliothque Git Ruby appele Grit, vous pouvez le faire de manire suivante :

$ git clone git://github.com/schacon/grit.git

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 :

$ git clone git://github.com/schacon/grit.git mygrit

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.

2.2 Enregistrer des modications dans le dpt


Vous avez prsent un dpt Git valide et une extraction ou copie de travail du projet. Vous
devez faire quelques modications et valider des instantans de ces modications dans votre dpt
chaque fois que votre projet aeint un tat que vous souhaitez enregistrer.
14

Sco Chacon Pro Git

Section 2.2 Enregistrer des modications dans le dpt

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.

Figure 2.1: Le cycle de vie des tats des iers.

2.2.1 Vrier ltat des iers


Loutil principal pour dterminer quels chiers sont dans quel tat est la commande git status. Si vous lancez cee commande juste aprs un clonage, vous devriez voir ce qui suit :

$ 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

Chapitre 2 Les bases de Git

Sco Chacon Pro Git

# Untracked files:
#

(use "git add <file>..." to include in what will be committed)

#
# 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.

2.2.2 Placer de nouveaux iers sous suivi de version


Pour commencer suivre un nouveau chier, vous utilisez la commande git add. Pour
commencer suivre le chier LISEZMOI, vous pouvez entrer ceci :

$ git add LISEZMOI

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:
#

(use "git reset HEAD <file>..." to unstage)

#
# 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.

2.2.3 Indexer des iers modis


Maintenant, modions un chiers qui est dj sous suivi de version. Si vous modiez le chier
sous suivi de version appel benchmarks.rb et que vous lancez nouveau votre commande
status, vous verrez ceci :
16

Sco Chacon Pro Git

Section 2.2 Enregistrer des modications dans le dpt

$ git status
# On branch master
# Changes to be committed:
#

(use "git reset HEAD <file>..." to unstage)

#
# new file:

LISEZMOI

#
# Changed but not updated:
#

(use "git add <file>..." to update what will be committed)

#
# 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 :

$ git add benchmarks.rb


$ git status
# On branch master
# Changes to be committed:
#

(use "git reset HEAD <file>..." to unstage)

#
# 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:
#

(use "git reset HEAD <file>..." to unstage)

#
# new file:

LISEZMOI

# modified:

benchmarks.rb

#
# Changed but not updated:
#

(use "git add <file>..." to update what will be committed)

17

Chapitre 2 Les bases de Git

# modified:

Sco Chacon Pro Git

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 :

$ git add benchmarks.rb


$ git status
# On branch master
# Changes to be committed:
#

(use "git reset HEAD <file>..." to unstage)

#
# new file:

LISEZMOI

# modified:

benchmarks.rb

2.2.4 Ignorer des iers


Il apparat souvent quun type de chiers prsent dans la copie de travail ne doit pas tre ajout
automatiquement ou mme apparatre comme chier potentiel pour le suivi de version. Ce sont par
exemple des chiers gnrs automatiquement tels que les chiers de journaux ou de sauvegardes
produits par loutil que vous utilisez. Dans un tel cas, on peut numrer les patrons de noms de
chiers ignorer dans un chier .gitignore. Voici ci-dessous un exemple de chier .gitignore :

$ 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

Sco Chacon Pro Git

Section 2.2 Enregistrer des modications dans le dpt

Si le patron se termine par un slash (/), le patron dnote un rpertoire


Un patron commenant par un point dexclamation (!) est invers.
Les patrons standards de chiers sont des expressions rgulires simplies utilises par les shells.
Un astrisque (*) correspond un ou plusieurs caractres ; [abc] correspond un des trois caractres lists dans les crochets, donc a ou b ou c ; un point dinterrogation (?) correspond un unique
caractre ; des crochets entourant des caractres spars par un signe moins ([0-9]) correspond
un caractre dans lintervalle des deux caractres indiqus, donc ici de 0 9.
Voici un autre exemple de chier .gitignore :

# un commentaire, cette ligne est ignore


*.a

# pas de fichier .a

!lib.a

# mais suivre en version lib.a malgr la rgle prcdente

/TODO

# ignorer uniquement le fichier TODO la racine du projet

build/

# ignorer tous le fichiers dans le rpertoire build

doc/*.txt # ignorer doc/notes.txt, mais pas doc/server/arch.txt

2.2.5 Inspecter les modications indexes et non indexes


Si le rsultat de la commande git status est encore trop vague lorsquon dsire savoir
non seulement quels chiers ont chang mais aussi ce qui a chang dans ces chiers on peut
utiliser la commande git diff. Cee commande sera traite en dtail plus loin ; mais elle sera
vraisemblablement utilise le plus souvent pour rpondre aux questions suivantes : quest-ce qui a
t modi mais pas encore index ? elle modications a t indexe et est prte pour la validation ? L o git status rpond de manire gnrale ces questions, git diff montre les
lignes exactes qui ont t ajoutes, modies ou eaces le patch en somme.
Supposons que vous ditez et indexez le chier LISEZMOI et que vous ditez le chier benchmarks.rb sans lindexer. Si vous lancez la commande status, vous verrez ceci :

$ git status
# On branch master
# Changes to be committed:
#

(use "git reset HEAD <file>..." to unstage)

#
# new file:

LISEZMOI

#
# Changed but not updated:
#

(use "git add <file>..." to update what will be committed)

#
# modified:

benchmarks.rb

Pour visualiser ce qui a t modi mais pas encore index, tapez git diff sans autre argument :

19

Chapitre 2 Les bases de Git

Sco Chacon Pro Git

$ 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
+

run_code(x, 'commits 1') do

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 :

$ git diff --cached


diff --git a/LISEZMOI b/LISEZMOI
new file mode 100644
index 0000000..03902a1
--- /dev/null
+++ b/LISEZMOI2
@@ -0,0 +1,5 @@
+grit
+ by Tom Preston-Werner, Chris Wanstrath
+ http://github.com/mojombo/grit
+
+Grit is a Ruby library for extracting information from a Git repository

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 :

$ git add benchmarks.rb


$ echo '# test line' >> benchmarks.rb
$ git status
# On branch master

20

Sco Chacon Pro Git

Section 2.2 Enregistrer des modications dans le dpt

#
# 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

et git diff --cached pour visualiser ce qui a t index jusqu maintenant :

$ git diff --cached


diff --git a/benchmarks.rb b/benchmarks.rb
index 3cb747f..e445e28 100644
--- a/benchmarks.rb
+++ b/benchmarks.rb
@@ -36,6 +36,10 @@ def main
@commit.parents[0].parents[0].parents[0]
end
+
+
+

run_code(x, 'commits 1') do


git.commits.size
end

+
run_code(x, 'commits 2') do
log = git.commits('master', 15)
log.size

2.2.6 Valider vos modications


Votre zone dindex est dans ltat dsir, vous pouvez valider vos modications. Souvenez-vous
que tout ce qui encore non index tous les chiers qui ont t crs ou modis mais nont pas
subi de git add depuis ne feront pas partie de la prochaine validation. Ils resteront en tant que
chiers modis sur votre disque.
21

Chapitre 2 Les bases de Git

Sco Chacon Pro Git

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:
#

(use "git reset HEAD <file>..." to unstage)

#
#

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 :

$ git commit -m "Story 182: Fix benchmarks for speed"


[master]: created 463dc4f: "Fix benchmarks for speed"
2 files changed, 3 insertions(+), 0 deletions(-)
create mode 100644 LISEZMOI

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

Sco Chacon Pro Git

Section 2.2 Enregistrer des modications dans le dpt

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.

2.2.7 liminer la phase dindexation


Bien quil soit incroyablement utile de pouvoir organiser les commits exactement comme on
lentend, la gestion de la zone dindex est parfois plus complexe que ncessaire dans une utilisation
normale. Si vous souhaitez viter la phase de placement des chiers dans la zone dindex, Git fournit
un raccourcis trs simple. Lajout de loption -a la commande git commit ordonne Git de
placer automatiquement tout chier dj en suivi de version dans la zone dindex avant de raliser
la validation, vitant ainsi davoir taper les commandes git add :

$ 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.

2.2.8 Eacer des iers


Pour eacer un chier de Git, vous devez lliminer des chiers en suivi de version (plus prcisment, leacer dans la zone dindex) puis valider. La commande git rm ralise cee action mais
eace aussi ce chier de votre copie de travail de telle sorte que vous ne le verrez pas rapparatre
comme chier non suivi en version la prochaine validation.
Si vous eacez simplement le chier dans votre copie de travail, il apparat sous la section
Changed but not updated (cest--dire, non index) dans le rsultat de git status :

$ rm grit.gemspec
$ git status
# On branch master
#
# Changed but not updated:
#

(use "git add/rm <file>..." to update what will be committed)

#
#

deleted:

grit.gemspec

Ensuite, si vous lancez git rm, leacement du chier est index :


23

Chapitre 2 Les bases de Git

Sco Chacon Pro Git

$ git rm grit.gemspec
rm 'grit.gemspec'
$ git status
# On branch master
#
# Changes to be committed:
#

(use "git reset HEAD <file>..." to unstage)

#
#

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 :

$ git rm --cached readme.txt

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 \*~

Cee commande limine tous les chiers se terminant par ~.

2.2.9 Dplacer des iers


la dirence des autres VCS, Git ne suit pas explicitement les mouvements des chiers. Si
vous renommez un chier suivi par Git, aucune mta-donne indiquant le renommage nest stocke
par Git. Nanmoins, Git est assez malin pour sen apercevoir aprs coup la dtection de mouvement de chier sera traite plus loin.
24

Sco Chacon Pro Git

Section 2.3 Visualiser lhistorique des validations

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

$ git mv nom_origine nom_cible

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 :

$ git mv LISEZMOI.txt LISEZMOI


$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
# Changes to be committed:
#

(use "git reset HEAD <file>..." to unstage)

#
#

renamed:

LISEZMOI.txt -> LISEZMOI

Nanmoins, cela revient lancer les commandes suivantes :

$ 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.

2.3 Visualiser lhistorique des validations


Aprs avoir cr plusieurs commits ou si vous avez clon un dpt ayant un historique de
commits, vous souhaitez probablement revoir le l des vnements. La commande git log est
loutil le plus basique et puissant pour cet objet.
Les exemples qui suivent utilisent un projet trs simple nomm simplegit utilis pour les dmonstrations. Pour rcuprer le projet, lancez

git clone git://github.com/schacon/simplegit-progit.git

Lorsque vous lancez git log dans le rpertoire de ce projet, vous devriez obtenir un rsultat
qui ressemble ceci :
25

Chapitre 2 Les bases de Git

Sco Chacon Pro Git

$ git log
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:

Mon Mar 17 21:52:11 2008 -0700

changed the version number


commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:

Sat Mar 15 16:40:33 2008 -0700

removed unnecessary test code


commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date:

Sat Mar 15 10:31:28 2008 -0700

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:

Mon Mar 17 21:52:11 2008 -0700

changed the version number


diff --git a/Rakefile b/Rakefile
index a874b73..8f94139 100644
--- a/Rakefile
+++ b/Rakefile
@@ -5,7 +5,7 @@ require 'rake/gempackagetask'
spec = Gem::Specification.new do |s|
-

s.version

"0.1.0"

s.version

"0.1.1"

s.author

"Scott Chacon"

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:

Sat Mar 15 16:40:33 2008 -0700

removed unnecessary test code

26

Sco Chacon Pro Git

Section 2.3 Visualiser lhistorique des validations

diff --git a/lib/simplegit.rb b/lib/simplegit.rb


index a0a60ae..47c6340 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -18,8 +18,3 @@ class SimpleGit
end
end
-if $0 == __FILE__
-

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 :

$ git log --stat


commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:

Mon Mar 17 21:52:11 2008 -0700

changed the version number


Rakefile |

2 +-

1 files changed, 1 insertions(+), 1 deletions(-)


commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:

Sat Mar 15 16:40:33 2008 -0700

removed unnecessary test code


lib/simplegit.rb |

5 -----

1 files changed, 0 insertions(+), 5 deletions(-)


commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date:

Sat Mar 15 10:31:28 2008 -0700

first commit
LISEZMOI
Rakefile

|
|

lib/simplegit.rb |

6 ++++++
23 +++++++++++++++++++++++
25 +++++++++++++++++++++++++

3 files changed, 54 insertions(+), 0 deletions(-)

27

Chapitre 2 Les bases de Git

Sco Chacon Pro Git

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 :

$ git log --pretty=oneline


ca82a6dff817ec66f44342007202690a93763949 changed the version number
085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary test code
a11bef06a3f659402fe7563abf99ad00de2209e6 first commit

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 :

$ git log --pretty=format:"%h %an, %ar : %s"


ca82a6d Scott Chacon, 11 months ago : changed the version number
085bb3b Scott Chacon, 11 months ago : removed unnecessary test code
a11bef0 Scott Chacon, 11 months ago : first commit

Le tableau 2-1 liste les options de formatage les plus utiles.

Option Description du formatage


%H Somme de contrle du commit
%h Somme de contrle abrge du commit
%T Somme de contrle de l'arborescence
%t Somme de contrle abrge de l'arborescence
%P Sommes de contrle des parents
%p Sommes de contrle abrges des parents
%an Nom de l'auteur
%ae e-mail de l'auteur
%ad Date de l'auteur (au format de l'option -date=)
%ar Date relative de l'auteur
%cn Nom du validateur
%ce e-mail du validateur
%cd Date du validateur
%cr Date relative du validateur
%s Sujet

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

Sco Chacon Pro Git

Section 2.3 Visualiser lhistorique des validations

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 :

$ git log --pretty=format:"%h %s" --graph


* 2d3acf9 ignore errors from SIGCHLD on trap
*

5e3ee11 Merge branch 'master' of git://github.com/dustin/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
*

11d191e Merge branch 'defunkt' into local

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

2.3.1 Limiter la longueur de lhistorique


En complment des options de formatage de sortie, git log est pourvu de certaines options de
limitation utiles des options qui permeent de restreindre la liste un sous-ensemble de commits.
Vous avez dj vu une de ces options loption -2 qui ne montre que le deux derniers commits.
En fait, on peut utiliser -<n>, ou n correspond au nombre de commits que lon cherche visualiser
en partant des plus rcents. En vrit, il est peu probable que vous utilisiez cee option, parce que
Git injecte par dfaut sa sortie dans un outil de pagination qui permet de la visualiser page page.
Cependant, les options de limitation portant sur le temps, telles que --since (depuis) et -until (jusqu) sont trs utiles. Par exemple, le commande suivante ache la liste des commits
des deux dernires semaines :
29

Chapitre 2 Les bases de Git

Sco Chacon Pro Git

$ git log --since=2.weeks

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 :

$ git log --pretty="%h %s" --author=gitster --since="2008-10-01" \


--before="2008-11-01" --no-merges -- t/
5610e3b Fix testcase failure when extended attribute
acd3b9e Enhance hold_lock_file_for_{update,append}()
f563754 demonstrate breakage of detached checkout wi
d1a43f2 reset --hard/read-tree --reset -u: remove un
51a94af Fix "checkout --track -b newbranch" on detac
b0ad11e pull: allow "git pull origin $something:$cur

A partir des 20 000 commits constituant lhistorique des sources de Git, cee commande extrait
les 6 qui correspondent aux critres.

2.3.2 Utiliser une interface graphique pour visualiser lhistorique


Si vous prfrez utiliser un outil plus graphique pour visualiser lhistorique dun projet, vous
pourriez jeter un il un programme distribu avec Git nomm gitk. Gitk est un outil graphique
30

Sco Chacon Pro Git

Section 2.4 Annuler des actions

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.

Figure 2.2: Le visualiseur dhistorique gitk

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.

2.4 Annuler des actions


tout moment, vous pouvez dsirer annuler une de vos dernires actions. Dans cee section,
nous allons passer en revue quelques outils de base permeant dannuler des modications. Il faut
tre trs aentif car certaines de ces annulations sont dnitives (elles ne peuvent pas tre ellemme annules). Cest donc un des rares cas dutilisation de Git o des erreurs de manipulation
peuvent entraner des pertes dnitives de donnes.

2.4.1 Modier le dernier commit


Une des annulations les plus communes apparat lorsquon valide une modication trop tt
en oubliant dajouter certains chiers, ou si on se trompe dans le message de validation. Si vous
souhaitez rectier cee erreur, vous pouvez valider le complment de modication avec loption
--amend :

$ git commit --amend

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

Chapitre 2 Les bases de Git

Sco Chacon Pro Git

Lditeur de message de validation dmarre, mais il contient dj le message de la validation


prcdente. Vous pouvez diter ce message normalement, mais il crasera le message de la validation
prcdente.
Par exemple, si vous validez une version puis ralisez que vous avez oubli de spcier les
modications dun chier, vous pouvez taper les commandes suivantes :

$ git commit -m 'validation initiale'


$ git add fichier_oublie
$ git commit --amend

Les trois dernires commandes donnent lieu la cration dun unique commit la seconde
validation remplace le rsultat de la premire.

2.4.2 Dsindexer un ier dj index


Les deux sections suivantes dmontrent comment bricoler les modications dans votre zone
dindex et votre zone de travail. Un point sympathique est que la commande permeant de connatre ltat de ces deux zones vous rappelle aussi comment annuler les modications. Par exemple,
supposons que vous avez modi deux chiers et voulez les valider comme deux modications indpendantes, mais que vous ayez tap accidentellement git add * et donc index les deux.
Comment annuler lindexation dun des chiers ? La commande git status vous rappelle :

$ git add .
$ git status
# On branch master
# Changes to be committed:
#

(use "git reset HEAD <file>..." to unstage)

#
#

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 :

$ git reset HEAD benchmarks.rb


benchmarks.rb: locally modified
$ git status
# On branch master
# Changes to be committed:
#

(use "git reset HEAD <file>..." to unstage)

#
#

modified:

LISEZMOI.txt

#
# Changed but not updated:
#

32

(use "git add <file>..." to update what will be committed)

Sco Chacon Pro Git

Section 2.4 Annuler des actions

(use "git checkout -- <file>..." to discard changes in working directory)

#
#

modified:

benchmarks.rb

La commande taper peut sembler trange mais elle fonctionne. Le chier benchmark.rb est
modi mais de retour ltat non index.

2.4.3 Rinitialiser un ier modi


e faire si vous ralisez que vous ne souhaitez pas conserver les modications au chier
benchmark.rb ? Comment le rinitialiser facilement, le ramener ltat quil avait dans le dernier
instantan (ou lors du clonage, ou dans ltat dans lequel vous lavez obtenu dans votre copie de
travail) ? Heureusement, git status est secourable. Dans le rsultat de la dernire commande,
la zone de travail ressemble ceci :

# Changed but not updated:


#

(use "git add <file>..." to update what will be committed)

(use "git checkout -- <file>..." to discard changes in working directory)

#
#

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 :

$ git checkout -- benchmarks.rb


$ git status
# On branch master
# Changes to be committed:
#

(use "git reset HEAD <file>..." to unstage)

#
#

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

Chapitre 2 Les bases de Git

Sco Chacon Pro Git

2.5 Travailler avec des dpts distants


Pour pouvoir collaborer sur un projet Git, il est ncessaire de connatre comment grer les
dpts distants. Les dpts distants sont des versions de votre projet qui sont hberges sur Internet
ou le rseau. Vous pouvez en avoir plusieurs, pour lesquels vous pouvez avoir des droits soit en
lecture seule, soit en lecture/criture. Collaborer avec dautres personnes consiste grer ces dpts
distants, en poussant ou tirant des donnes depuis et vers ces dpts quand vous souhaitez partager
votre travail.
Grer des dpts distants inclut savoir comment ajouter des dpts distants, eacer des dpts
distants qui ne sont plus valides, grer des branches distantes et les dnir comme suivie ou non, et
plus encore. Dans cee section, nous traiterons des commandes de gestion distante.

2.5.1 Aer les dpts distants


Pour visualiser les serveur distants que vous avez enregistrs, vous pouvez lancer le commande
git remote. Elle liste les noms des direntes tiquees distantes que vous avez spcies. Si vous
avez clon un dpt, vous devriez au moins voir lorigine origin cest--dire le nom par dfaut
que Git donne au serveur partir duquel vous avez clon :

$ git clone git://github.com/schacon/ticgit.git


Initialized empty Git repository in /private/tmp/ticgit/.git/
remote: Counting objects: 595, done.
remote: Compressing objects: 100% (269/269), done.
remote: Total 595 (delta 255), reused 589 (delta 253)
Receiving objects: 100% (595/595), 73.31 KiB | 1 KiB/s, done.
Resolving deltas: 100% (255/255), done.
$ cd ticgit
$ git remote
origin

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

Sco Chacon Pro Git

Section 2.5 Travailler avec des dpts distants

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).

2.5.2 Ajouter des dpts distants


Jai expliqu et donn des exemples dajout de dpts distants dans les chapitres prcdents,
mais voici spciquement comment faire. Pour ajouter un nouveau dpt distant Git comme nom
court auquel il est facile de faire rfrence, lancez git remote add [nomcourt] [url] :

$ 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.

2.5.3 Rcuprer et tirer depuis des dpts distants


Comme vous venez tout juste de le voir, pour obtenir les donnes des dpts distants, vous
pouvez lancer :

$ git fetch [nom-distant]

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

Chapitre 2 Les bases de Git

Sco Chacon Pro Git

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.

2.5.4 Pousser son travail sur un dpt distant


Lorsque votre dpt vous semble prt tre partag, il faut le pousser en amont. La commande
pour le faire est simple : git push [nom-distant] [nom-de-branche]. Si vous souhaitez
pousser votre branche master vers le serveur origin (pour rappel, cloner un dpt dnit automatiquement ces noms pour vous), alors vous pouvez lancez ceci pour pousser votre travail vers le
serveur amont :

$ git push origin master

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.

2.5.5 Inspecter un dpt distant


Si vous souhaitez visualiser plus dinformations propos dun dpt distant particulier, vous
pouvez utiliser la commande git remote show [nom-distant]. Si vous lancez cee commande avec un nom court particulier, tel que origin, vous obtenez quelque chose comme :

$ git remote show origin


* remote origin
URL: git://github.com/schacon/ticgit.git
Remote branch merged with 'git pull' while on branch master
master
Tracked remote branches
master

36

Sco Chacon Pro Git

Section 2.5 Travailler avec des dpts distants

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 :

$ git remote show origin


* remote origin
URL: git@github.com:defunkt/github.git
Remote branch merged with 'git pull' while on branch issues
issues
Remote branch merged with 'git pull' while on branch master
master
New remote branches (next fetch will store in remotes/origin)
caching
Stale tracking branches (use 'git remote prune')
libwalker
walker2
Tracked remote branches
acl
apiv2
dashboard2
issues
master
postgres
Local branch pushed with 'git push'
master:master

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.

2.5.6 Retirer et dplacer des branes distantes


Si vous souhaitez renommer une rfrence, dans les versions rcentes de Git, vous pouvez
lancer git remote rename pour modier le nom court dun dpt distant. Par exemple, si vous
souhaitez renommer pb en paul, vous pouvez le faire avec git remote rename :

$ git remote rename pb paul


$ git remote
origin
paul

37

Chapitre 2 Les bases de Git

Sco Chacon Pro Git

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 :

$ git remote rm paul


$ git remote
origin

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.

2.6.1 Lister vos balises


Lister les balises existantes dans Git est trs simple. Tapez juste git tag :

$ 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 :

$ git tag -l 'v1.4.2.*'


v1.4.2.1
v1.4.2.2
v1.4.2.3
v1.4.2.4

2.6.2 Crer des balises


Git utilise deux types principaux de balises : lgres et annotes. Une balise lgre ressemble
beaucoup une branche qui ne change pas, cest juste un pointeur sur un commit spcique. Les
balises annotes, par contre sont stockes en tant quobjets part entire dans la base de donnes
de Git. Elles ont une somme de contrle, contiennent le nom et ladresse e-mail du crateur, la date,
un message de balisage et peuvent tre signes et vries avec GNU Privacy Guard (GPG). Il est
38

Sco Chacon Pro Git

Section 2.6 Balisage

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.

2.6.3 Les balises annotes


Crer des balises annotes est simple avec Git. Le plus simple est de spcier loption -a la
commande tag :

$ git tag -a v1.4 -m 'my version 1.4'


$ git tag
v0.1
v1.3
v1.4

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 :

$ git show v1.4


tag v1.4
Tagger: Scott Chacon <schacon@gee-mail.com>
Date:

Mon Feb 9 14:45:11 2009 -0800

my version 1.4
commit 15027957951b64cf874c3557a0f3547bd83b3ff6
Merge: 4a447f7... a6b4c97...
Author: Scott Chacon <schacon@gee-mail.com>
Date:

Sun Feb 8 19:02:46 2009 -0800

Merge branch 'experiment'

Cee commande ache le nom du crateur, la date de cration de la balise et le message


dannotation avant de montrer eectivement linformation de validation.

2.6.4 Les balises signes


Vous pouvez aussi signer vos balises avec GPG, condition davoir une cl prive. Il sut de
spcier loption -s au lieu de -a :

$ git tag -s v1.5 -m 'my signed 1.5 tag'


You need a passphrase to unlock the secret key for
user: "Scott Chacon <schacon@gee-mail.com>"
1024-bit DSA key, ID F721C45A, created 2009-02-09

39

Chapitre 2 Les bases de Git

Sco Chacon Pro Git

En lanant git show sur cee balise, on peut visualiser la signature GPG aache :

$ git show v1.5


tag v1.5
Tagger: Scott Chacon <schacon@gee-mail.com>
Date:

Mon Feb 9 15:22:20 2009 -0800

my signed 1.5 tag


-----BEGIN PGP SIGNATURE----Version: GnuPG v1.4.8 (Darwin)
iEYEABECAAYFAkmQurIACgkQON3DxfchxFr5cACeIMN+ZxLKggJQf0QYiQBwgySN
Ki0An2JeAVUCAiJ7Ox6ZEtK+NvZAj82/
=WryJ
-----END PGP SIGNATURE----commit 15027957951b64cf874c3557a0f3547bd83b3ff6
Merge: 4a447f7... a6b4c97...
Author: Scott Chacon <schacon@gee-mail.com>
Date:

Sun Feb 8 19:02:46 2009 -0800

Merge branch 'experiment'

Plus loin, nous verrons comment vrier une balise signe.

2.6.5 Les balises lgres


Une autre manire de baliser les commits est dutiliser les balises lgres. Celles-ci se rduisent
stocker la somme de contrle dun commit dans un chier, aucune autre information nest conserve.
Pour crer une balise lgre, il sut de nutiliser aucune des option -a, -s ou -m :

$ git tag v1.4-lw


$ git tag
v0.1
v1.3
v1.4
v1.4-lw
v1.5

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 :

$ git show v1.4-lw


commit 15027957951b64cf874c3557a0f3547bd83b3ff6
Merge: 4a447f7... a6b4c97...
Author: Scott Chacon <schacon@gee-mail.com>
Date:

Sun Feb 8 19:02:46 2009 -0800

Merge branch 'experiment'

40

Sco Chacon Pro Git

Section 2.6 Balisage

2.6.6 Vrier des balises


Pour vrier une balise signe, il faut utiliser git tag -v [nom-de-balise]. Cee
commande utilise GPG pour vrier la signature. La cl publique du signataire doit tre prsente
dans votre trousseau :

$ git tag -v v1.4.2.1


object 883653babd8ee7ea23e6a5c392bb739348b1eb61
type commit
tag v1.4.2.1
tagger Junio C Hamano <junkio@cox.net> 1158138501 -0700
GIT 1.4.2.1
Minor fixes since 1.4.2, including git-mv and git-http with alternates.
gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A
gpg: Good signature from "Junio C Hamano <junkio@cox.net>"
gpg:

aka "[jpeg image of size 1513]"

Primary key fingerprint: 3565 2A26 2040 E066 C9A7

4A7D C0C6 D9A4 F311 9B9A

Si la cl publique du signataire nest pas prsente dans le trousseau, la commande donne le


rsultat suivant :

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'

2.6.7 Baliser aprs coup


Vous pouvez aussi baliser des commits plus anciens. Supposons que lhistorique des commits
ressemble ceci :

$ git log --pretty=oneline


15027957951b64cf874c3557a0f3547bd83b3ff6 Fusion branche 'experimental'
a6b4c97498bd301d84096da251c98a07c7723e65 Dbut de l'criture support
0d52aaab4479697da7686c15f77a3d64d9165190 Un truc de plus
6d52a271eda8725415634dd79daabbc4d9b6008e Fusion branche 'experimental'
0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc ajout d'une fonction de validatn
4682c3261057305bdd616e23b64b0857d832627b ajout fichier afaire
166ae0c4d3f420721acbb115cc33848dfcc2121a dbut de l'ecriture support
9fceb02d0ae598e95dc970b74767f19372d61af8 mise jour rakefile
964f16d36dfccde844893cac5b347e7b3d44abbc validation afaire
8a5cbc430f1a9c3d00faaeffd07798508422908a mise jour lisezmoi

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

Chapitre 2 Les bases de Git

Sco Chacon Pro Git

$ git tag -a v1.2 9fceb02

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:

Mon Feb 9 15:32:16 2009 -0800

version 1.2
commit 9fceb02d0ae598e95dc970b74767f19372d61af8
Author: Magnus Chacon <mchacon@gee-mail.com>
Date:

Sun Apr 27 20:43:35 2008 -0700

mise jour rakefile


...

2.6.8 Partager les balises


Par dfaut, la commande git push ne transre pas les balises vers les serveurs distants. Il
faut explicitement pousser les balises aprs les avoir cres localement. Ce processus sapparente
pousser des branches distantes vous pouvez lancer git push origin [nom-du-tag].

$ git push origin v1.5


Counting objects: 50, done.
Compressing objects: 100% (38/38), done.
Writing objects: 100% (44/44), 4.56 KiB, done.
Total 44 (delta 18), reused 8 (delta 1)
To git@github.com:schacon/simplegit.git
* [new tag]

v1.5 -> v1.5

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.

$ git push origin --tags


Counting objects: 50, done.
Compressing objects: 100% (38/38), done.

42

Sco Chacon Pro Git

Section 2.7 Trucs et astuces

Writing objects: 100% (44/44), 4.56 KiB, done.


Total 44 (delta 18), reused 8 (delta 1)
To git@github.com:schacon/simplegit.git
* [new tag]

v0.1 -> v0.1

* [new tag]

v1.2 -> v1.2

* [new tag]

v1.4 -> v1.4

* [new tag]

v1.4-lw -> v1.4-lw

* [new tag]

v1.5 -> v1.5

A prsent, lorsquune autre personne clone ou tire depuis votre dpt, elle obtient aussi les
balises.

2.7 Trucs et astuces


Avant de clore ce chapitre sur les bases de Git, voici quelques trucs et astuces qui peuvent rendre votre apprentissage de Git plus simple, facile ou familier. De nombreuses personnes utilisent
parfaitement Git sans connatre aucun de ces trucs, et nous ny ferons pas rfrence, ni ne considrerons leur connaissance comme des pr-requis pour la suite de ce livre, mais il est prfrable de
les connatre.

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

Chapitre 2 Les bases de Git

Sco Chacon Pro Git

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 :

$ git log --s<tab>


--shortstat

--since=

--src-prefix=

--stat

--summary

Cest une astuce qui peut clairement vous viter de perdre du temps ou de lire de la documentation.

2.7.2 Les alias Git


Git ne complte pas votre commande si vous ne la tapez que partiellement. Si vous ne voulez
pas avoir taper lintgralit du texte de chaque commande, vous pouvez facilement dnir un alias
pour chaque commande en utilisant git config. Voici quelques exemples qui pourraient vous
intresser :

$ git config --global alias.co checkout


$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status

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 :

$ git config --global alias.unstage 'reset HEAD --'

Cela rend les deux commandes suivantes quivalentes :

$ git unstage fichierA


$ git reset HEAD fichierA

Cela rend les choses plus claires. Il est aussi commun dajouter un alias last, de la manire
suivante :

$ git config --global alias.last 'log -1 HEAD'

44

Sco Chacon Pro Git

Section 2.8 Rsum

Ainsi, vous pouvez visualiser plus facilement le dernier commit :

$ git last
commit 66938dae3329c7aebe598c2246a8e6af90d04646
Author: Josh Goebel <dreamer3@example.com>
Date:

Tue Aug 26 19:48:51 2008 +0800

test for current head


Signed-off-by: Scott Chacon <schacon@example.com>

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 :

$ git config --global alias.visual "!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

Les branes avec Git


asiment tous les VCS ont une forme ou une autre de gestion de branche. Faire une branche
signie diverger de la ligne principale de dveloppement et continuer travailler sans se proccuper
de cee ligne principale. Dans de nombreux outils de gestion de version, cee fonctionnalit est
souvent chre en ressources et ncessite souvent de crer une nouvelle copie du rpertoire de travail,
ce qui peut prendre longtemps dans le cas de grands projets.
De nombreuses personnes font rfrence au modle de gestion de branche de Git comme LA
fonctionnalit et cest srement la spcicit de Git par rapport la communaut des gestionnaires
de version. Pourquoi est-elle si spciale ? La mthode de Git pour grer les branches est particulirement lgre, permeant de raliser des embranchements quasi instantanment et de basculer
de branche gnralement aussi rapidement. la dirence de nombreux autres gestionnaires de
version, Git encourage travailler avec des mthodes qui privilgient la cration et la fusion de
branches, jusqu plusieurs fois par jour. Bien comprendre et matriser cee fonctionnalit est un
atout pour faire de Git un outil unique qui peut liralement changer la manire de dvelopper.

3.1 Ce quest une brane


Pour rellement comprendre comment Git gre les branches, nous devons revenir en arrire
et examiner de plus prs comment Git stocke ses donnes. Comme vous pouvez vous en souvenir
du chapitre 1, Git ne stocke pas ses donnes comme une srie de changesets ou deltas, mais comme
une srie dinstantans.
Lorsquon valide dans Git, Git stocke un objet commit qui contient un pointeur vers linstantan
du contenu qui a t index, les mta-donnes dauteur et de message et zro ou plusieurs pointeurs
vers le ou les commits qui sont les parents directs de ce commit : zro parent pour la premire
validation, un parent pour un commit normal et des parents multiples pour des commits qui sont le
rsultat de la fusion dune ou plusieurs branches.
Pour visualiser ce concept, supposons un rpertoire contenant trois chiers, ces trois chiers
tant indexs puis valids. Indexer les chiers signie calculer la somme de contrle pour chacun
(la fonction de hachage SHA-1 mentionne au chapitre 1), stocker cee version du chier dans le
dpt Git (Git les nomme blobs) et ajouter la somme de contrle la zone dindex :

$ git add LISEZMOI test.rb LICENCE


$ git commit -m 'commit initial de mon projet'

47

Chapitre 3 Les branches avec Git

Sco Chacon Pro Git

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.

Figure 3.1: Donnes dun unique commit.

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.

Figure 3.2: Donnes et objets Git pour des validations multiples.

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 :

$ git branch testing

48

Sco Chacon Pro Git

Section 3.1 Ce quest une branche

Figure 3.3: Brane pointant dans lhistorique des donnes de commit.

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).

Figure 3.5: ier HEAD pointant sur la brane active

Pour basculer vers une branche existante, il sut de lancer la commande git checkout.
Basculons vers la nouvelle branche testing :

$ git checkout testing

49

Chapitre 3 Les branches avec Git

Sco Chacon Pro Git

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

est-ce que cela signie ? Et bien, faisons une autre validation :

$ vim test.rb
$ git commit -a -m 'petite modification'

La gure 3-7 illustre le rsultat.

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 :

$ git checkout master

La gure 3-8 montre le rsultat.


Cee commande a ralis deux actions. Elle a remis le pointeur HEAD sur la branche master et
elle a replac les chiers de la copie de travail dans ltat point par master. Cela signie aussi que les
modications que vous ralisez partir de maintenant divergeront de lancienne version du projet.
Cee commande retire les modications ralises dans la branche testing pour vous permere de
repartir dans une autre direction de dveloppement.
50

Sco Chacon Pro Git

Section 3.1 Ce quest une branche

Figure 3.8: HEAD se dplace sur une autre brane lors dun eout.

Ralisons quelques autres modications et validons nouveau :

$ 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.

Figure 3.9: Les historiques de brane ont diverg.

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

Chapitre 3 Les branches avec Git

Sco Chacon Pro Git

de manire trs facile. Ces fonctionnalits encouragent naturellement les dveloppeurs crer et
utiliser souvent des branches.
Voyons pourquoi vous devriez en faire autant.

3.2 Braner et fusionner : les bases


Suivons un exemple simple de branche et fusion dans une utilisation que vous feriez dans le
monde rel. Vous feriez les tapes suivantes :
1. Travailler sur un site web
2. Crer une branche pour une nouvelle Story sur laquelle vous souhaiteriez travailler
3. Raliser quelques tches sur cee branche
cee tape, vous recevez un appel pour vous dire quun problme critique a t dcouvert et quil
faut le rgler au plus tt. Vous feriez ce qui suit :
1. Revenir la branche de production
2. Crer une branche et y dvelopper le correctif
3. Aprs un test, fusionner la branche de correctif et pousser le rsultat la production
4. Rebasculer la branche initiale et continuer le travail

3.2.1 Le branement de base


Premirement, supposons que vous tes travailler sur votre projet et avez dj quelques commits (voir gure 3-10).

Figure 3.10: Un historique simple et court.

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 :

$ git checkout -b prob53


Switched to a new branch "prob53"

Cest un raccourci pour :

52

Sco Chacon Pro Git

Section 3.2 Brancher et fusionner : les bases

$ git branch prob53


$ git checkout prob53

La gure 3-11 illustre le rsultat.

Figure 3.11: Cration dun nouveau pointeur de brane.

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]'

Figure 3.12: La brane prob53 a avanc avec votre travail.

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

Chapitre 3 Les branches avec Git

Sco Chacon Pro Git

$ git checkout master


Switched to branch "master"

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) :

$ git checkout -b 'correctif'


Switched to a new branch "correctif"
$ vim index.html
$ git commit -a -m "correction d'une adresse mail incorrecte"
[correctif]: created 3a0874c: "correction d'une adresse mail incorrecte"
1 files changed, 0 insertions(+), 1 deletions(-)

Figure 3.13: Brane de correctif base partir de la brane master.

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 :

$ git checkout master


$ git merge correctif
Updating f42c576..3a0874c
Fast forward
LISEZMOI |

1 -

1 files changed, 0 insertions(+), 1 deletions(-)

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

Sco Chacon Pro Git

Section 3.2 Brancher et fusionner : les bases

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 :

$ git branch -d correctif


Deleted branch correctif (3a0874c).

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) :

$ git checkout prob53


Switched to branch "prob53"
$ vim index.html
$ git commit -a -m 'Nouveau pied de page termin [problme 53]'
[prob53]: created ad82d7a: "Nouveau pied de page termin [problme 53]"
1 files changed, 1 insertions(+), 0 deletions(-)

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.

3.2.2 Les bases de la fusion


Supposons que vous ayez dcid que le travail sur le problme #53 est termin et se trouve
donc prt tre fusionn dans la branche master. Pour ce faire, vous allez rapatrier votre branche
55

Chapitre 3 Les branches avec Git

Sco Chacon Pro Git

Figure 3.15: Votre brane prob53 peut avancer indpendamment de 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 :

$ git checkout master


$ git merge prob53
Merge made by recursive.
README |

1 +

1 files changed, 1 insertions(+), 0 deletions(-)

Le comportement semble lgrement dirent de celui observ pour la fusion prcdente de


correctif. Dans ce cas, lhistorique de dveloppement a diverg un certain point. Comme le
commit sur la branche sur laquelle vous vous trouvez nest plus un anctre direct de la branche
que vous cherchez fusionner, Git doit travailler. Dans ce cas, Git ralise une simple fusion trois
sources, en utilisant les deux instantans points par les sommets des branches et lanctre commun
des deux. La gure 3-16 illustre les trois instantans que Git utilise pour raliser la fusion dans ce
cas.

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

Sco Chacon Pro Git

Section 3.2 Brancher et fusionner : les bases

(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 :

$ git branch -d prob53

3.2.3 Conits de fusion


elques fois, le processus ci-dessus ne se passe pas sans accroc. Si vous avez modi diremment la mme partie du mme chier dans les deux branches que vous souhaitez fusionner, Git ne
sera pas capable de raliser proprement la fusion. Si votre rsolution du problme #53 a modi la
mme section de chier que le correctif, vous obtiendrez une conit de fusion qui ressemble
ceci :

$ git merge prob53


Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

Git na pas automatiquement cr le commit du fusion. Il a arrt le processus le temps que


vous rsolviez le conit. Lancez git status pour voir tout moment aprs lapparition du conit
de fusion quels chiers nont pas t fusionns :

[master*]$ git status


index.html: needs merge
# On branch master
# Changed but not updated:
#

(use "git add <file>..." to update what will be committed)

57

Chapitre 3 Les branches avec Git

Sco Chacon Pro Git

(use "git checkout -- <file>..." to discard changes in working directory)

#
# 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

Sco Chacon Pro Git

Section 3.3 Gestion de branches

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:
#

(use "git reset HEAD <file>..." to unstage)

#
# 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 :

Merge branch 'prob53'


Conflicts:
index.html
#
# It looks like you may be committing a MERGE.
# If this is not correct, please remove the file
# .git/MERGE_HEAD
# and try again.
#

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.

3.3 Gestion de branes


Aprs avoir cr, fusionn et eac des branches, regardons de plus prs les outils de gestion
de branche qui savreront utiles lors dune utilisation intensive des branches.
La commande git branch fait plus que crer et eacer des branches. Si vous la lancez sans
argument, vous obtenez la liste des branches courantes :

$ git branch
prob53
* master
testing

59

Chapitre 3 Les branches avec Git

Sco Chacon Pro Git

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

93b412c fix javascript issue

* master

7a98805 Merge branch 'prob53'

testing 782fd34 add scott to the author list in the readmes

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 :

$ git branch --merged


prob53
* master

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 :

$ git branch --no-merged


testing

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 :

$ git branch -d testing


error: The branch 'testing' is not an ancestor of your current HEAD.
If you are sure you want to delete it, run 'git branch -D testing'.

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

Sco Chacon Pro Git

Section 3.4 Travailler avec les branches

3.4 Travailler avec les branes


Aprs avoir acquis les bases pour brancher et fusionner, que pouvons-nous ou devons-nous
en faire ? Ce chapitre traite des dirents styles de dveloppement que cee gestion de branche
lgre permet de mere en place, pour vous aider dcider den incorporer une dans votre cycle de
dveloppement.

3.4.1 Branes au long cours


Comme Git utilise une fusion 3 branches, fusionner une branche dans une autre plusieurs fois
sur une longue priode est gnralement facile. Cela signie que vous pouvez travailler sur plusieurs
branches ouvertes en permanence pendant plusieurs tapes de votre cycle de dveloppement ; vous
pouvez fusionner rgulirement certaines dans dautres.
De nombreux dveloppeurs utilisent Git avec une mthode qui utilise cee approche, telle que
navoir que du code entirement stable et test dans la branche master, voire du code qui a t
ou sera publi. Ils ont une autre branche en parallle appele develop qui, lorsquelle devient stable,
peut tre fusionne dans master. Cee branche est utilise pour tirer des branches spciques
(branches avec une faible dure de vie, telles que notre branche prob53) quand elles sont prtes,
sassurer quelles passent tous les tests et nintroduisent pas de bugs.
En ralit, nous parlons de pointeurs qui se dplacent le long des lignes des commits raliss.
Les branches stables sont plus en profondeur dans la ligne de lhistorique des commits tandis que
les branches des derniers dveloppements sont plus en hauteur dans lhistorique (voir gure 3-18).

Figure 3.18: Les branes les plus stables sont gnralement plus bas dans lhistorique des commits.

Cest gnralement plus simple dy penser en terme de silos de tches, o un ensemble de


commits volue vers un silo plus stable quand il a t compltement test (voir gure 3-19).

Figure 3.19: Reprsentation des branes comme des silos.

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

Chapitre 3 Les branches avec Git

Sco Chacon Pro Git

ne sont pas ncessaires, mais savrent souvent utiles, spcialement dans le cadre de projets gros ou
complexes.

3.4.2 Les branes de sujet


Les branches de sujet sont tout de mme utiles quelle que soit la taille du projet. Une branche
de sujet est une branche de courte dure de vie cre et utilise pour une fonctionnalit ou une tche
particulire. Cest une manire doprer que vous navez vraisemblablement jamais utilise avec un
autre VCS parce quil est gnralement trop lourd de crer et fusionner des branches. Mais dans Git,
crer, dvelopper, fusionner et eacer des branches plusieurs fois par jour est monnaie courante.
Vous lavez remarqu dans la section prcdent avec les branches prob53 et correctif
que vous avez cres. Vous avez ralis quelques validations sur elles et vous les avez eaces juste
aprs les avoir fusionnes dans votre branche principale. Cee technique vous permet de basculer
de contexte compltement et immdiatement. Il est beaucoup plus simple de raliser des revues de
code parce que votre travail est isol dans des silos o toutes les modications sont lies au sujet .
Vous pouvez entreposer vos modications ici pendant des minutes, des jours ou des mois, puis les
fusionner quand elles sont prtes, indpendamment de lordre dans lequel elles ont t cres ou de
dveloppes.
Supposons un exemple o pendant un travail (sur master), vous branchiez pour un problme
(prob91), travaillez un peu dessus, vous branchiez une seconde branche pour essayer de trouver
une autre manire de le rsoudre (prob91v2), vous retourniez sur la branche master pour y
travailler pendant un moment pour nalement brancher sur un dernire branche (ideeidiote)
pour laquelle vous ntes pas sr que ce soit une bonne ide. Votre historique de commit pourrait
ressembler la gure 3-20.

Figure 3.20: Votre historique de commit avec de multiples branes de sujet.

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

Sco Chacon Pro Git

Section 3.5 Les branches distantes

Figure 3.21: Votre historique aprs la fusion de ideeidiote et prob91v2.

locales. Lorsque vous branchez et fusionnez, tout est ralis dans votre dpt Git. Aucune communication avec un serveur na lieu.

3.5 Les branes distantes


Les branches distantes sont des rfrences ltat des branches sur votre dpt distant. Ce
sont des branches locales quon ne peut pas modier ; elles sont modies automatiquement lors
de communications rseau. Les branches distantes agissent comme des marques-pages pour vous
aider vous souvenir de ltat de votre dpt distant lorsque vous vous y tes connects.
Elles prennent la forme de (distant)/(branche). Par exemple, si vous souhaitiez visualiser ltat de votre branche master sur le dpt distant origin lors de votre dernire communication, il vous sut de vrier la branche origin/master. Si vous tiez en train de travailler
avec un collgue et quil a mis jour la branche prob53, vous pourriez avoir votre propre branche
prob53 ; mais la branche sur le serveur pointerait sur le commit de origin/prob53.
Cela peut paratre dconcertant, alors claircissons les choses par un exemple. Supposons que
vous avez un serveur Git sur le rseau ladresse git.notresociete.com. Si vous clonez
partir de ce serveur, Git le nomme automatiquement origin et en tire tout lhistorique, cre un
pointeur sur ltat actuel de la branche master et lappelle localement origin/master ; vous ne
pouvez pas la modier. Git vous cre votre propre branche master qui dmarre au mme commit
que la branche master dorigine, pour que vous puissiez commencer travailler (voir gure 3-22).
Si vous travaillez sur votre branche locale master et que dans le mme temps, quelquun
pousse vers git.notresociete.com et met jour cee branche, alors vos deux historiques
divergent. Tant que vous restez sans contact avec votre serveur distant, votre pointeur origin/
master navance pas (voir gure 3-23).
Lancez la commande git fetch origin pour synchroniser votre travail. Cee commande
recherche le serveur hbergeant origin (dans notre cas, git.notresociete.com), en rcupre
toutes les nouvelles donnes et met jour votre base de donne locale en dplaant votre pointeur
63

Chapitre 3 Les branches avec Git

Sco Chacon Pro Git

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

Sco Chacon Pro Git

Section 3.5 Les branches distantes

Figure 3.24: La commande git fet met jour vos rfrences distantes.

Figure 3.25: Ajouter un autre serveur comme accs distant.

3.5.1 Pousser vers un serveur


Lorsque vous souhaitez partager une branche avec le reste du monde, vous devez la pousser sur
le serveur distant sur lequel vous avez accs en criture. Vos branches locales ne sont pas automatiquement synchronises sur les serveurs distants vous devez pousser explicitement les branches
que vous souhaitez partager. De cee manire, vous pouvez utiliser des branches prives pour le travail que vous ne souhaitez pas partager et ne pousser que les branches sur lesquelles vous souhaitez
collaborer.
Si vous possdez une branche nomme correctionserveur sur laquelle vous souhaitez
travailler avec des tiers, vous pouvez la pousser de la mme manire que vous avez pouss votre
premire branche. Lancez git push [serveur distant] [branche] :
65

Chapitre 3 Les branches avec Git

Sco Chacon Pro Git

Figure 3.26: Vous rcuprez une rfrence locale la bran master de equipeun.

$ git push origin correctionserveur


Counting objects: 20, done.
Compressing objects: 100% (14/14), done.
Writing objects: 100% (15/15), 1.74 KiB, done.
Total 15 (delta 5), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
* [new branch]

correctionserveur -> correctionserveur

Cest un raccourci. En fait, Git tend le nom de branche correctionserveur en refs/


heads/correctionserveur:refs/heads/correctionserveur, ce qui signie Prendre ma branche locale correctionserveur et la pousser pour mere jour la branche distante correctionserveur . Nous traiterons plus en dtail la partie refs/heads/ au chapitre 9, mais vous
pouvez gnralement loublier. Vous pouvez aussi lancer git push origin correctionserveur:correctionserveur, qui ralise la mme chose ce qui signie Prendre ma
branche correctionserveur et en faire la branche correctionserveur distante . Vous pouvez utiliser
ce format pour pousser une branche locale vers une branche distante nomme diremment. Si vous
ne souhaitez pas lappeler correctionserveur sur le serveur distant, vous pouvez lancer la
place git push origin correctionserveur:branchegeniale pour pousser votre
branche locale correctionserveur sur la branche branchegeniale sur le projet distant.
La prochaine fois quun de vos collaborateurs rcupre les donnes depuis le serveur, il rcuprera une rfrence ltat de la branche distante origin/correctionserveur :

$ git fetch origin


remote: Counting objects: 20, done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 15 (delta 5), reused 0 (delta 0)
Unpacking objects: 100% (15/15), done.
From git@github.com:schacon/simplegit
* [new branch]

66

correctionserveur

-> origin/correctionserveur

Sco Chacon Pro Git

Section 3.5 Les branches distantes

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 :

$ git checkout -b correctionserveur origin/correctionserveur


Branch

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.

3.5.2 Suivre les branes


Lextraction dune branche locale partir dune branche distante cre automatiquement ce
quon appelle une brane de suivi. Les branches de suivi sont des branches locales qui sont en relation directe avec une branche distante. Si vous vous trouvez sur une branche de suivi et que vous
tapez git push, Git slectionne automatiquement le serveur vers lequel pousser vos modications. De mme, git pull sur une de ces branches rcupre toutes les rfrences distantes et les
fusionne automatiquement dans la branche distante correspondante.
Lorsque vous clonez un dpt, il cre gnralement automatiquement une branche master
qui suit origin/master. Cest pourquoi les commandes git push et git pull fonctionnent
directement sans plus de paramtrage. Vous pouvez nanmoins crer dautres branches de suivi si
vous le souhaitez, qui ne suivront pas origin ni la branche master. Un cas dutilisation simple est lexemple prcdent, en lanant git checkout -b [branche] [nomdistant]/
[branche]. Si vous avez Git version 1.6.2 ou plus, vous pouvez aussi utiliser loption courte -track :

$ git checkout --track origin/correctionserveur


Branch

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 :

$ git checkout -b sf origin/correctionserveur


Branch sf set up to track remote branch refs/remotes/origin/correctionserveur.
Switched to a new branch "sf"

67

Chapitre 3 Les branches avec Git

Sco Chacon Pro Git

prsent, votre branche locale sf poussera vers et tirera automatiquement depuis origin/
correctionserveur.

3.5.3 Eacer des branes distantes


Supposons que vous en avez termin avec une branche distante. Vous et vos collaborateurs avez
termin une fonctionnalit et lavez fusionne dans la branche master du serveur distant (ou la
branche correspondant votre code stable). Vous pouvez eacer une branche distante en utilisant
la syntaxe plutt obtuse git push [nomdistant] :[branch]. Si vous souhaitez eacer
votre branche correctionserveur du serveur, vous pouvez lancer ceci :

$ git push origin :correctionserveur


To git@github.com:schacon/simplegit.git
- [deleted]

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.

3.6.1 Les bases


Si vous revenez un exemple prcdent du chapitre sur la fusion (voir la gure 3-27), vous
remarquerez que votre travail a diverg et que vous avez ajout de commits sur deux branches
direntes.

Figure 3.27: Votre historique divergent initial.

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

Sco Chacon Pro Git

Section 3.6 Rebaser

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 :

$ git checkout experience


$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command

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.

Figure 3.29: Rebaser les modications introduites par C3 sur C4.

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

Chapitre 3 Les branches avec Git

Sco Chacon Pro Git

Figure 3.30: Avance rapide sur la brane master.

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.

3.6.2 Rebasages plus intressants


Vous pouvez aussi faire rejouer votre rebasage sur autre chose quune branche. Prenez lhistorique
de la gure 3-31 par exemple. Vous avez cr une branche pour un sujet spcique (server) pour
ajouter des fonctionnalits ct serveur votre projet et avez ralis un commit. Ensuite, vous avez
cr une branche pour ajouter des modications ct client (client) et avez valid plusieurs fois.
Finalement, vous avez rebascul sur la branche server et avez ralis quelques commits supplmentaires.

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

Sco Chacon Pro Git

Section 3.6 Rebaser

en utilisant loption --onto de git rebase :

$ git rebase --onto master server client

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) :

$ git checkout master


$ git merge client

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) :

$ git rebase master server

71

Chapitre 3 Les branches avec Git

Sco Chacon Pro Git

Cee commande rejoue les modications de server sur le sommet de la branche master,
comme indiqu dans la gure 3-34.

Figure 3.34: Rebaser la brane server sur le sommet de la brane master.

Ensuite, vous pouvez faire une avance rapide sur la branche de base (master) :

$ git checkout master


$ git merge server

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 :

$ git branch -d client


$ git branch -d server

Figure 3.35: Lhistorique nal des commits.

3.6.3 Les dangers de rebaser


Ah mais les joies de rebaser ne viennent pas sans leurs contreparties, qui peuvent tre rsumes en une ligne :
Ne rebasez jamais des commits qui ont dj t pousss sur un dpt public.
Si vous suivez ce conseil, tout ira bien. Sinon, de nombreuses personnes vont vous har et vous
serez mpris par vos amis et votre famille.
and vous rebasez des donnes, vous abandonnez les commits existants et vous en crez
de nouveaux qui sont similaires mais dirents. Si vous poussez des commits quelque part et que
dautre les tirent et se basent dessus pour travailler et quaprs coup, vous rcrivez ces commits
laide de git rebase et les poussez nouveau, vos collaborateurs devront re-fusionner leur
travail et les choses peuvent rapidement devenir trs dsordonnes quand vous essaierez de tirer
leur travail dans votre dpt.
Examinons un exemple expliquant comment rebaser un travail dj publi sur un dpt public
peut gnrer des gros problmes. Supposons que vous clonez un dpt depuis un serveur central et
ralisez quelques travaux dessus. Votre historique de commits ressemble la gure 3-36.
72

Sco Chacon Pro Git

Section 3.6 Rebaser

Figure 3.36: Cloner un dpt et baser du travail dessus.

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.

Figure 3.37: Rcupration de commits et fusion dans votre copie.

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

Chapitre 3 Les branches avec Git

Sco Chacon Pro Git

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.

va encore plus drouter les autres dveloppeurs.


Si vous considrez le fait de rebaser comme un moyen de neoyer et rarranger des commits
avant de les pousser et si vous vous en tenez ne rebaser que des commits qui nont jamais t
publis, tout ira bien. Si vous tentez de rebaser des commits dj publis sur lesquels les gens ont
dj bas leur travail, vous allez au devant de gros problmes nervants.

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

Git sur le serveur


prsent, vous devriez tre capable de raliser la plupart des tches quotidiennes impliquant
Git. Nanmoins, pour pouvoir collaborer avec dautres personnes au moyen de Git, vous allez devoir
disposer dun dpt distant Git. Bien que vous puissiez techniquement tirer des modications et
pousser des modication avec des dpts individuels, cee pratique est dcourage parce quelle
introduit trs facilement une confusion avec votre travail actuel. De plus, vous souhaitez que vos
collaborateurs puissent accder votre dpt de sources, y compris si vous ntes pas connect
disposer dun dpt accessible en permanence peut savrer utile. De ce fait, la mthode canonique
pour collaborer consiste instancier un dpt intermdiaire auquel tous ont accs, que ce soit pour
pousser ou tirer. Nous nommerons ce dpt le serveur Git mais vous vous apercevrez quhberger
un serveur de dpt Git ne consomme que peu de ressources et quen consquence, on nutilise que
rarement une machine ddie cee tche.
Un serveur Git est simple lancer. Premirement, vous devez choisir quels protocoles seront
supports. La premire partie de ce chapitre traite des protocoles disponibles et de leurs avantages
et inconvnients. La partie suivante explique certaines congurations typiques avec ces protocoles
et comment les mere en uvre. Enn, nous traiterons de quelques types dhbergement, si vous
souhaitez hberger votre code sur un serveur tiers, sans avoir installer et maintenir un serveur
par vous-mme.
Si vous ne voyez pas dintrt grer votre propre serveur, vous pouvez sauter directement
la dernire partie de ce chapitre pour dtailler les options pour mere en place un compte hberg,
avant de continuer dans le chapitre suivant o les problmatiques de dveloppement distribu sont
abordes.
Un dpt distant est gnralement un dpt nu ( bare repository ), un dpt Git qui na pas de
copie de travail. Comme ce dpt nest utilis que comme centralisateur de collaboration, il ny a
aucune raison dextraire un instantan sur le disque ; seules les donnes Git sont ncessaires. Pour
simplier, un dpt nu est le contenu du rpertoire .git sans oriture.

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

Chapitre 4 Git sur le serveur

Sco Chacon Pro Git

4.1.1 Protocole local


Le protocole de base est le protocole local pour lequel le dpt distant est un autre rpertoire
dans le systme de chier. Il est souvent utilis si tous les membres de lquipe ont accs un
rpertoire partag via NFS par exemple ou dans le cas moins probable o tous les dveloppeurs
travaillent sur le mme ordinateur. Ce dernier cas nest pas optimum car tous les dpts seraient
hbergs de fait sur le mme ordinateur, rendant ainsi toute dfaillance catastrophique.
Si vous disposez dun systme de chiers partag, vous pouvez cloner, pousser et tirer avec
un dpt local. Pour cloner un dpt ou pour lutiliser comme dpt distant dun projet existant,
utilisez le chemin vers le dpt comme URL. Par exemple, pour cloner un dpt local, vous pouvez
lancer ceci :

$ git clone /opt/git/projet.git

Ou bien cela :

$ git clone file:///opt/git/projet.git

Git opre lgrement diremment si vous spciez explicitement le protocole file:// au


dbut de lURL. Si vous spciez simplement le chemin, Git tente dutiliser des liens durs ou une
copie des chiers ncessaires. Si vous spciez le protocole file://, Git lance un processus daccs
au travers du rseau, ce qui est gnralement moins ecace. La raison dutiliser spciquement le
prxe file:// est la volont dobtenir une copie propre du dpt, sans aucune rfrence ou aucun objet supplmentaire qui pourraient rsulter dun import depuis un autre systme de gestion de
version ou dun action similaire (voir chapitre 9 pour les tches de maintenance). Nous utiliserons
les chemins normaux par la suite car cest la mthode la plus ecace.
Pour ajouter un dpt local un projet Git existant, lancez ceci :

$ git remote add proj_local /opt/git/projet.git

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

Sco Chacon Pro Git

Section 4.1 Protocoles

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.

4.1.2 Protocole SSH


Le protocole SSH est probablement le protocole de transport de Git le plus utilis. Cela est d
au fait que laccs SSH est dj en place de nombreux endroits et que si ce nest pas le cas, cela
reste trs facile faire. Cela est aussi d au fait que SSH est le seul protocole permeant facilement
de lire et dcrire distance. Les deux autres protocoles rseau (HTTP et Git) sont gnralement en
lecture seule et sils peuvent tre utiles pour la publication, le protocole SSH est ncessaire pour les
mises jour de par ce quil permet lcriture. SSH est un protocole authenti susamment rpandu
et sa mise uvre est simplie.
Pour cloner une dpt Git travers SSH, spciez le prxe ssh:// dans lURL comme ceci :

$ git clone ssh://utilisateur@serveur:projet.git

ou ne spciez pas de protocole du tout Git choisit SSH par dfaut si vous ntes pas explicite :

$ git clone utilisateur@serveur:projet.git

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

Chapitre 4 Git sur le serveur

Sco Chacon Pro Git

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.

4.1.3 Protocole Git


Vient ensuite le protocole Git. Celui-ci est gr par un daemon spcial livr avec Git. Ce dmon
coute sur un port ddi (9418) et propose un service similaire au protocole SSH, mais sans aucune
scurisation. Pour quun dpt soit publi via le protocole Git, le chier git-export-daemonok doit exister mais mise part cee condition sans laquelle le daemon refuse de publier un projet,
il ny a aucune scurit. Soit le dpt Git est disponible sans restriction en lecture, soit il nest pas
publi. Cela signie quil ne permet de pousser des modications. Vous pouvez activer la capacit
pousser mais tant donn labsence dauthentication, nimporte qui sur internet peut pousser sur
le dpt. Autant dire que ce mode est rarement recherch.
Avantages
Le protocole Git est le protocole le plus rapide. Si vous devez servir un gros trac pour un projet
public ou un trs gros projet qui ne ncessite pas dauthentication en lecture, il est trs probable
que vous devriez installer un daemon Git. Il utilise le mme mcanisme de transfert de donnes que
SSH, la surcharge du chirement et de lauthentication en moins.
Inconvnients
Le dfaut du protocole Git est le manque dauthentication. Nutiliser que le protocole Git
pour accder un projet nest gnralement pas susant. Il faut le coupler avec un accs SSH pour
quelques dveloppeurs qui auront le droit de pousser (crire) et le garder pour un accs git://
en lecture seule. Cest aussi le protocole le plus dicile mere en place. Il doit tre gr par son
propre daemon qui est spcique. Nous traiterons de cee installation dans la section Gitosis
de ce chapitre elle ncessite la conguration dun daemon xinetd ou apparent, ce qui est loin
dtre simple. Il ncessite aussi un accs travers le pare-feu au port 9418 qui nest pas un port
ouvert en standard dans les pare-feux professionnels. Derrire les gros pare-feux professionnels, ce
port obscur est tout simplement bloqu.

4.1.4 Protocole HTTP/S


Enn, il reste le protocole HTTP. La beaut dHTTP ou HTTPS tient dans la simplicit le
mere en place. Tout ce quil y a faire, cest de simplement copier un dpt Git nu sous votre
racine de document HTTP et de paramtrer un crochet post-update et cest prt (voir chapitre
7 pour les dtails sur les crochets de Git). partir de ceci, toute personne possdant un accs au
serveur web sur lequel vous avez copi votre dpt peut le cloner. Pour autoriser un accs en lecture
votre dpt sur HTTP, fates ceci :
78

Sco Chacon Pro Git

Section 4.1 Protocoles

$ 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

$ git clone http://exemple.com/projetgit.git

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

Chapitre 4 Git sur le serveur

Sco Chacon Pro Git

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.

4.2 Installation de Git sur un serveur


Pour raliser linstallation initiale dun serveur Git, il faut exporter une dpt existant dans un
nouveau dpt nu un dpt qui ne contient pas de copie de rpertoire de travail. Cest gnralement simple faire. Pour cloner votre dpt en crant un nouveau dpt nu, lancez la commande
clone avec loption --bare. Par convention, les rpertoires de dpt nu nissent en .git, de cee
manire :

$ git clone --bare mon_project mon_project.git


Initialized empty Git repository in /opt/projets/mon_project.git/

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

$ cp -Rf mon_project/.git mon_project.git

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.

4.2.1 Copie du dpt nu sur un serveur


prsent que vous avez une copie nue de votre dpt, il ne reste plus qu la placer sur
un serveur et rgler les protocoles. Supposons que vous avez mis en place un serveur nomm
git.exemple.com auquel vous avez accs par SSH et que vous souhaitez stocker vos dpts Git
dans le rpertoire /opt/git. Vous pouvez mere en place votre dpt en copiant le dpt nu :

$ scp -r mon_projet.git utilisateur@git.exemple.com:/opt/git

80

Sco Chacon Pro Git

Section 4.2 Installation de Git sur un serveur

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

$ git clone utilisateur@git.exemple.com:/opt/git/mon_projet.git

Si un utilisateur se connecte par SSH au serveur et a accs en lecture au rpertoire /opt/git/


mon_projet.git, il aura automatiquement accs pour tirer. Git ajoutera automatiquement les
droits de groupe en criture un dpt si vous lancez la commande git init avec loption -shared.

$ 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.

4.2.2 Petites installations


Si vous travaillez dans un petit groupe ou si vous ntes quen phase dessai de Git au sein de
votre socit avec peu de dveloppeurs, les choses peuvent rester simples. Un des aspects les plus
compliqus de la mise en place dun serveur Git est la gestion des utilisateurs. Si vous souhaitez que
certains dpts ne soient accessibles certains utilisateurs quen lecture seule et en lecture/criture
pour dautres, la gestion des accs et des permissions peut devenir dicile rgler.
Accs SSH
Si vous disposez dj dun serveur auquel tous vos dveloppeurs ont un accs SSH, il est
gnralement plus facile dy mere en place votre premier dpt car vous naurez quasiment aucun
rglage supplmentaire faire (comme nous lavons expliqu dans le chapitre prcdent). Si vous
souhaitez des permissions daccs plus complexes, vous pouvez les mere en place par le jeu des
permissions standards sur le systme de chier du systme dexploitation de votre serveur.
Si vous souhaitez placer vos dpts sur un serveur qui ne dispose pas dj de comptes pour
chacun des membres de votre quipe qui aurait accs en criture, alors vous devrez mere en place
81

Chapitre 4 Git sur le serveur

Sco Chacon Pro Git

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.

4.3 Gnration des clefs publiques SSH


Cela dit, de nombreux serveurs Git utilisent une authentication par clefs publiques SSH. Pour
fournir une clef publique, chaque utilisateur de votre systme doit la gnrer sil nen a pas dj. Le
processus est similaire sur tous les systmes dexploitation. Premirement, lutilisateur doit vrier
quil nen a pas dj une. Par dfaut, les clefs SSH dun utilisateur sont stockes dans le rpertoire
~/.ssh du compte. Vous pouvez facilement vrier si vous avez dj une clef en listant le contenu
de ce rpertoire :

$ 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

Sco Chacon Pro Git

Section 4.4 Mise en place du serveur

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.

4.4 Mise en place du serveur


Parcourons les tapes de la mise en place dun accs SSH ct serveur. Dans cet exemple, vous
utiliserez la mthode des authorized_keys pour authentier vos utilisateurs. Nous supposerons
galement que vous utilisez une distribution Linux standard telle quUbuntu. Premirement, crez
un utilisateur git et un rpertoire .ssh pour cet utilisateur.

$ sudo adduser git


$ su git
$ cd
$ mkdir .ssh

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

Il sut de les ajouter au chier authorized_keys :


83

Chapitre 4 Git sur le serveur

Sco Chacon Pro Git

$ cat /tmp/id_rsa.john.pub >> ~/.ssh/authorized_keys


$ cat /tmp/id_rsa.josie.pub >> ~/.ssh/authorized_keys
$ cat /tmp/id_rsa.jessica.pub >> ~/.ssh/authorized_keys

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 :

# Sur l'ordinateur de John


$ cd monproject
$ git init
$ git add .
$ git commit -m 'premiere validation'
$ git remote add origin git@gitserveur:/opt/git/projet.git
$ git push origin master

prsent, les autres utilisateurs peuvent cloner le dpt et y pousser leurs modications aussi
simplement :

$ git clone git@gitserveur:/opt/git/projet.git


$ vim LISEZMOI
$ git commit -am 'correction fichier LISEZMOI'
$ git push origin master

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

Sco Chacon Pro Git

Section 4.5 Accs public

$ sudo vim /etc/passwd

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.

4.5 Accs public


Et si vous voulez permere des accs anonymes en lecture ? Peut-tre souhaitez-vous hberger
un projet open source au lieu dun projet interne priv. Ou peut-tre avez-vous quelques serveurs
de compilation ou dintgration continue qui changent souvent et vous ne souhaitez pas avoir
regnrer des clefs SSH tout le temps vous avez besoin dun accs en lecture seule simple.
Le moyen le plus simple pour des petites installations est probablement dinstaller un serveur
web statique dont la racine pointe sur vos dpts Git puis dactiver le crochet post-update
mentionn la premire partie de ce chapitre. Reprenons lexemple prcdent. Supposons que vos
dpts soient dans le rpertoire /opt/git et quun serveur Apache soit install sur la machine.
Vous pouvez bien sr utiliser nimporte quel serveur web mais nous utiliserons Apache pour montrer la conguration ncessaire.
Premirement, il faut activer le crochet :

$ 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

Chapitre 4 Git sur le serveur

Sco Chacon Pro Git

$ 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) :

$ chgrp -R www-data /opt/git

Aprs avoir redmarr Apache, vous devriez tre capable de cloner vos dpts en spciant
lURL de votre projet :

$ git clone http://git.gitserveur/projet.git

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

Sco Chacon Pro Git

Section 4.6 GitWeb

Figure 4.1: Linterface web de visualisation GitWeb

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.

$ git instaweb --httpd=webrick


[2009-02-21 10:02:21] INFO

WEBrick 1.3.1

[2009-02-21 10:02:21] INFO

ruby 1.8.6 (2008-03-03) [universal-darwin9.0]

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 :

$ git instaweb --httpd=webrick --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 :

$ git clone git://git.kernel.org/pub/scm/git/git.git


$ cd git/
$ make GITWEB_PROJECTROOT="/opt/git" \
prefix=/usr gitweb/gitweb.cgi
$ sudo cp -Rf gitweb /var/www/

87

Chapitre 4 Git sur le serveur

Sco Chacon Pro Git

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 :

$ apt-get install python-setuptools

Ensuite, il faut cloner et installer Gitosis partir du site principal du projet :

$ git clone git://eagain.net/gitosis.git


$ cd gitosis

88

Sco Chacon Pro Git

Section 4.7 Gitosis

$ sudo python setup.py install

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

pour la version dorigine :

git:x:1000:1000::/home/git:/bin/sh

Vous pouvez maintenant initialiser Gitosis en lanant la commande gitosis-init avec


votre clef publique. Si votre clef publique nest pas prsente sur le serveur, il faut ly tlcharger :

$ sudo -H -u git gitosis-init < /tmp/id_dsa.pub


Initialized empty Git repository in /opt/git/gitosis-admin.git/
Reinitialized existing Git repository in /opt/git/gitosis-admin.git/

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.

$ sudo chmod 755 /opt/git/gitosis-admin.git/hooks/post-update

89

Chapitre 4 Git sur le serveur

Sco Chacon Pro Git

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 :

# sur votre ordinateur local


$ git clone git@gitserveur:gitosis-admin.git

Vous avez prsent un rpertoire gitosis-admin qui contient deux entres :

$ 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

Sco Chacon Pro Git

Section 4.7 Gitosis

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 :

$ git commit -am 'ajout iphone_projet et groupe mobile'


[master]: created 8962da8: "changed name"
1 files changed, 4 insertions(+), 0 deletions(-)
$ git push
Counting objects: 5, done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 272 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
To git@gitserver:/opt/git/gitosis-admin.git
fb27aec..8962da8

master -> master

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 :

$ git remote add origin git@gitserveur:iphone_projet.git


$ git push origin master
Initialized empty Git repository in /opt/git/iphone_projet.git/
Counting objects: 3, done.
Writing objects: 100% (3/3), 230 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@gitserver:iphone_project.git
* [new branch]

master -> master

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

Chapitre 4 Git sur le serveur

Sco Chacon Pro Git

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

Sco Chacon Pro Git

Section 4.8 Le daemon Git

4.8 Le daemon Git


Pour garantir les accs publics non authentis en lecture vos projet, il est prfrable de
dpasser le protocole HTTP et de commencer utiliser le protocole Git. La raison principale en est
la vitesse. Le protocole Git est bien plus ecace et de ce fait plus rapide que le protocole HTTP et
fera gagner du temps vos utilisateurs.
Ce systme nest valable que pour les accs non authentis en lecture seule. Si vous meez
ceci en place sur un serveur lextrieur de votre pare-feu, il ne devrait tre utilis que pour des
projets qui sont destins tre visibles publiquement par le monde entier. Si le serveur est derrire
le pare-feu, il peut tre utilis pour des projets avec accs en lecture seule pour un grand nombre
dutilisateurs ou des ordinateurs (intgration continue ou serveur de compilation) pour lequels vous
ne souhaitez pas avoir grer des clefs SSH.
En tout cas, le protocole Git est relativement facile mere en place. Grossirement, il sut
de lancer la commande suivante en tant que daemon :

git daemon --reuseaddr --base-path=/opt/git/ /opt/git/

--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

Chapitre 4 Git sur le serveur

Sco Chacon Pro Git

initctl start local-git-daemon

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

Sco Chacon Pro Git

Section 4.9 Git hberg

4.9 Git hberg


Si vous ne vous ne voulez pas vous investir dans la mise en place de votre propre serveur Git,
il reste quelques options pour hberger vos projets Git chez un site externe ddi lhbergement.
Cee mthode ore de nombreux avantages : un site en hbergement est gnralement rapide
crer et facilite le dmarrage de projets, et nimplique pas de maintenance et de surveillance de
serveur. Mme si vous montez et faites fonctionner votre serveur en interne, vous souhaiterez surement utiliser un site dhbergement public pour votre code open source cela rend gnralement
plus facile laccs et laide par la communaut.
Aujourdhui, vous avez disposition un nombre impressionnant doptions dhbergement, chacune avec dirents avantages et dsavantages. Pour une liste jour, rfrez-vous la page GitHosting du wiki principal sur Git :
http://git.or.cz/gitwiki/GitHosting
Comme nous ne pourrons pas les passer toutes en revue, et comme de plus, il savre que je
travaille pour lune dentre elles, nous utiliserons ce chapitre pour dtailler la cration dun compte
et dun nouveau projet sur GitHub. Cela vous donnera une ide de ce qui est ncessaire.
GitHub est de loin le plus grand site dhbergement open source sur Git et cest aussi un des
rares orir la fois des options dhbergement public et priv, ce qui vous permet de conserver
vos codes open source et privs au mme endroit. En fait, nous avons utilis GitHub pour collaborer
en priv sur ce livre.

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.

4.9.2 Cration dun compte utilisateur


La premire chose faire, cest de crer un compte utilisateur gratuit. Visitez la page Prix et
inscription http://github.com/plans et cliquez sur le bouton Crer un compte gratuit
de la zone Gratuit pour lopen source (voir gure 4-2) qui vous amne la page denregistrement.

Figure 4.2: La page des dirents plans de GitHub.


95

Chapitre 4 Git sur le serveur

Sco Chacon Pro Git

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).

Figure 4.3: La page denregistrement de GitHub

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).

Figure 4.4: Le tableau de bord dutilisateur de GitHub

Vous pouvez ensuite procder la cration dun nouveau dpt.

4.9.3 Cration dun nouveau dpt


Commencez en cliquant sur Nouveau dpt juste ct de vos dpts sur le tableau de bord
utilisateur. Un formulaire Crer un nouveau dpt apparat pour vous guider dans la cration
dun nouveau dpt (voir gure 4-5).
Le strict ncessaire consiste fournir un nom au projet, mais vous pouvez aussi ajouter une
description. Ensuite, cliquez sur le bouton Crer un dpt . Voil un nouveau dpt sur GitHub
(voir gure 4-6).
Comme il ny a pas encore de code, GitHub ache les instructions permeant de crer un nouveau projet, de pousser un projet Git existant ou dimporter un projet depuis un dpt Subversion
public (voir gure 4-7).
Ces instructions sont similaires ce que nous avons dj dcrit. Pour initialiser un projet qui
nest pas dj dans Git, tapez
96

Sco Chacon Pro Git

Section 4.9 Git hberg

Figure 4.5: Cration dun nouveau dpt sur GitHub

Figure 4.6: Information principale dun projet GitHub

Figure 4.7: Instructions pour un nouveau dpt

$ 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 :

$ git remote add origin git@github.com:testinguser/iphone_projet.git


$ git push origin 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

Chapitre 4 Git sur le serveur

Sco Chacon Pro Git

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.

4.9.4 Import depuis Subversion


Si vous souhaitez importer un projet public sous Subversion dans Git, GitHub peut vous faciliter la tche. Il y a un lien Vous importez un dpt Subversion? Cliquez ici au bas de la page
dinstructions. En le cliquant, vous accdez un formulaire contenant des informations sur le processus dimport et une bote texte o vous pouvez coller lURL de votre dpt public Subversion
(voir gure 4-9).

Figure 4.9: Interface dimport depuis Subversion.

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.

4.9.5 Ajout des collaborateurs


Ajoutons le reste de lquipe. Si John, Josie et Jessica ouvrent tous un compte sur GitHub, et
que vous souhaitez leur donner un accs en criture votre dpt, vous pouvez les ajouter votre
projet comme collaborateurs. Cela leur permera de pousser leur travail sur le dpt avec leurs clefs
prives.
Cliquez le bouton Admin dans lentte du projet pour accder la page dadministration
de votre projet GitHub (voir gure 4-10).
98

Sco Chacon Pro Git

Section 4.9 Git hberg

Figure 4.10: Page dadministration GitHub.

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).

Figure 4.11: Ajout dun collaborateur votre projet.

Lorsque vous avez ni dajouter des collaborateurs, vous devriez les voir en liste dans la bote
Repository Collaborators (voir gure 4-12).

Figure 4.12: Une liste des collaborateurs sur votre projet.

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.

4.9.6 Votre projet


Une fois que vous avez pouss votre projet ou lavez import depuis Subversion, votre page
principale de projet ressemble la gure 4-13.
Lorsquon visite votre projet, on voit cee page. Elle contient des onglets vers direntes vues
des projets. Longlet Contributions ache une liste des validations dans lordre chronologique
99

Chapitre 4 Git sur le serveur

Sco Chacon Pro Git

Figure 4.13: Un page principale de projet GitHub.

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.

4.9.7 Duplication de projets


Si vous souhaitez contribuer un projet auquel vous navez pas accs en criture, GitHub
encourage dupliquer le projet. Si le projet vous semble intressant et que vous souhaitez le modier,
vous pouvez cliquer sur le bouton Fork (dupliquer) visible dans lentte du projet pour faire copier
ce projet par GitHub vers votre utilisateur pour que vous puissiez pousser dessus.
De cee manire, les administrateurs de projet nont pas se soucier dajouter des utilisateurs
comme collaborateurs pour leur donner un accs en criture. On peut dupliquer un projet et pousser
dessus, et le mainteneur principal du projet peut tirer ces modications en ajoutant les projets dupliqus comme dpts distants et en fusionnant les changements.
Pour dupliquer un projet, visitez la page du projet (par exemple mojombo/chronic), et cliquez
le bouton Fork (dupliquer) dans lentte (voir gure 4-14).

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

Sco Chacon Pro Git

Section 4.10 Rsum

Figure 4.15: Votre duplicata dun projet.

4.9.8 Rsum sur GitHub


Cest tout ce que nous dirons de GitHub, mais il faut souligner que tous ces processus sont trs
rapides. Vous pouvez crer un compte, ajouter un nouveau projet et commencer pousser dessus
en quelques minutes. Si votre projet est libre, vous pouvez aussi construire une importante communaut de dveloppeurs qui ont prsent la visibilit sur votre projet et peuvent tout moment
le dupliquer et commencer contribuer. Tout au moins, cela peut savrer une manire rapide de
dmarrer avec Git et de lessayer.

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.

5.1 Dveloppements distribus


la dirence des systmes de gestion de version centraliss (CVCS), la nature distribue de
Git permet une bien plus grande exibilit dans la manire dont les dveloppeurs collaborent sur
un projet. Dans les systmes centraliss, tout dveloppeur est un nud travaillant de manire plus
ou moins gale sur un concentrateur central. Dans Git par contre, tout dveloppeur est potentiellement un nud et un concentrateur, cest--dire que chaque dveloppeur peut la fois contribuer
du code vers les autres dpts et maintenir un dpt public sur lequel dautres vont baser leur travail et auquel ils vont contribuer. Cee capacit ouvre une perspective de modes de dveloppement
pour votre projet ou votre quipe dont certains archtypes tirant parti de cee exibilit seront
traits dans les sections qui suivent. Les avantages et inconvnients ventuels de chaque mode seront
traits. Vous pouvez choisir den utiliser un seul ou de mlanger les fonctions de chacun.

5.1.1 Gestion centralise


Dans les systmes centraliss, il ny a gnralement quun seul modle de collaboration, la
gestion centralise. Un concentrateur ou dpt central accepte le code et tout le monde doit synchroniser son travail avec. Les dveloppeurs sont des nuds, des consommateurs du concentrateur,
seul endroit o ils se synchronisent (voir gure 5-1).
Cela signie que si deux dveloppeurs clonent depuis le concentrateur et quils introduisent
tous les deux des modications, le premier pousser ses modications le fera sans encombre. Le second dveloppeur doit fusionner les modications du premier dans son dpt local avant de pousser
ses modications pour ne pas craser les modications du premier. Ce concept reste aussi vrai avec
Git quil lest avec Subversion (ou tout autre CVCS) et le modle fonctionne parfaitement dans Git.
Si votre quipe est petite et que vous tes dj habitus une gestion centralise dans votre
103

Chapitre 5 Git distribu

Sco Chacon Pro Git

Figure 5.1: La gestion centralise.

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.

5.1.2 Mode du gestionnaire dintgration


Comme Git permet une multiplicit de dpt distants, il est possible denvisager un mode de
fonctionnement o chaque dveloppeur a un accs en criture son propre dpt public et en lecture
tous ceux des autres. Ce scnario inclut souvent un dpt canonique qui reprsente le projet
ociel . Pour commencer contribuer au projet, vous crez votre propre clone public du projet
et poussez vos modications dessus. Aprs, il sut denvoyer une demande au mainteneur de projet
pour quil tire vos modications dans le dpt canonique. Il peut ajouter votre dpt comme dpt
distant, tester vos modications localement, les fusionner dans sa branche et les pousser vers le
dpt public. Le processus se passe comme ceci (voir gure 5-2) :
1. Le mainteneur du projet pousse vers son dpt public.
2. Un contributeur clone ce dpt et introduit des modications.
3. Le contributeur pousse son travail sur son dpt public.
4. Le contributeur envoie au mainteneur un e-mail de demande pour tirer depuis son dpt.
5. Le mainteneur ajoute le dpt du contributeur comme dpt distant et fusionne localement.
6. Le mainteneur pousse les modications fusionnes sur le dpt principal.
Cest une gestion trs commune sur des sites tels que GitHub o il est ais de dupliquer un
projet et de pousser ses modications pour les rendre publiques. Un avantage distinctif de cee
approche est quil devient possible de continuer travailler et que le mainteneur du dpt principal
peut tirer les modications tout moment. Les contributeurs nont pas aendre le bon-vouloir du
mainteneur pour incorporer leurs modications. Chaque acteur peut travailler son rythme.
104

Sco Chacon Pro Git

Section 5.1 Dveloppements distribus

Figure 5.2: Le mode du gestionnaire dintgration

5.1.3 Mode dictateur et ses lieutenants


Cest une variante de la gestion multi-dpt. En gnral, ce mode est utilis sur des projets
immenses comprenant des centaines de collaborateurs. Un exemple connu en est le noyau Linux.
Des gestionnaires dintgration grent certaines parties du projet. Ce sont les lieutenants. Tous les
lieutenants ont un unique gestionnaire dintgration, le dictateur bnvole. Le dpt du dictateur
sert de dpt de rfrence partir duquel tous les collaborateurs doivent tirer. Le processus se
droule comme suit (voir gure 5-3) :
1. Les dveloppeurs de base travaillent sur la branche thmatique et rebasent leur travail sur
master. La branche master est celle du dictateur.
2. Les lieutenants fusionnent les branches thmatiques des dveloppeurs dans leur propre branche
master.
3. Le dictateur fusionne les branches master de ses lieutenants dans sa propre branche master.
4. Le dictateur pousse sa branche master sur le dpt de rfrence pour que les dveloppeurs se
rebasent dessus.

Figure 5.3: Le processus du dictateur bnvole.

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

Chapitre 5 Git distribu

Sco Chacon Pro Git

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.

5.2 Contribution un projet


Vous savez ce que sont les dirents modes de gestion et vous devriez connatre susamment
lutilisation de Git. Dans cee section, vous apprendrez les moyens les plus utiliss pour contribuer
un projet.
La principale dicult dcrire ce processus rside dans lextraordinaire quantit de variations
dans sa ralisation. Comme Git est trs exible, les gens peuvent collaborer de direntes faons
et ils le font, et il devient problmatique de dcrire de manire unique comment devrait se raliser
la contribution un projet. Chaque projet est lgrement dirent. Les variables incluent la taille
du corps des contributeurs, le choix du ux de gestion, les accs en validation et la mthode de
contribution externe.
La premire variable est la taille du corps de contributeurs. Combien de personnes contribuent
activement du code sur ce projet et quelle vitesse ? Dans de nombreux cas, vous aurez deux
trois dveloppeurs avec quelques validations par jour, voire moins pour des projets endormis. Pour
des socits ou des projets particulirement grands, le nombre de dveloppeurs peut chirer des
milliers, avec des dizaines, voire des centaines de patchs ajouts chaque jour. Ce cas est important
car avec de plus en plus de dveloppeurs, les problmes de fusion et dapplication de patch deviennent de plus en plus courants. Les modications soumises par un dveloppeur peuvent tre rendu
obsoltes ou impossibles appliquer sur des changements qui ont eu lieu dans lintervalle de leur
dveloppement, de leur approbation ou de leur application. Comment dans ces conditions conserver
son code en permanence synchronis et ses patchs valides ?
La variable suivante est le mode de gestion utilis pour le projet. Est-il centralis avec chaque
dveloppeur ayant un accs gal en criture sur la ligne de dveloppement principale ? Le projet
prsente-t-il un mainteneur ou un gestionnaire dintgration qui vrie tous les patchs ? Tous les
patchs doivent-ils subir une revue de pair et une approbation ? Fates-vous partie du processus ? Un
systme lieutenant est-il en place et doit-on leur soumere les modications en premier ?
La variable suivante est la gestion des accs en criture. Le mode de gestion ncessaire la
contribution au projet est trs dirent selon que vous ayez ou non accs au dpt en criture. Si vous
navez pas accs en criture, quelle est la mthode prfre pour la soumission de modications ?
Y a-t-il seulement un politique en place ? elle est la quantit de modications fournie chaque
fois ? elle est la priodicit de contribution ?
Toutes ces questions aectent la manire de contribuer ecacement un projet et les modes
de gestion disponibles ou prfrables. Je vais traiter ces sujets dans une srie de cas dutilisation
allant des plus simples aux plus complexes. Vous devriez pouvoir construire vos propres modes de
gestion partir de ces exemples.

5.2.1 Guides pour une validation


Avant de passer en revue les cas dutilisation spciques, voici un point rapide sur les messages
de validation. La dnition et lutilisation dun bonne ligne de conduite sur les messages de valida106

Sco Chacon Pro Git

Section 5.2 Contribution un projet

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 diff --check


lib/simplegit.rb:5: trailing whitespace.
+

@git_dir = File.expand_path(git_dir)XX

lib/simplegit.rb:7: trailing whitespace.


+ XXXXXXXXXXX
lib/simplegit.rb:26: trailing whitespace.
+

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 :

Court rsum des modifications( 50 caractres ou moins)

107

Chapitre 5 Git distribu

Sco Chacon Pro Git

Explication plus dtaille si ncessaire. Retour la ligne vers 72


caractres. Dans certains contextes, la premire ligne est traite
comme le sujet d'un e-mail et le reste comme le corps. La ligne
vide qui spare le titre du corps est importante ( moins d'omettre
totalement le corps). Des outils tels que rebase peuvent tre gns
si vous les laissez colls.
Paragraphes supplmentaires aprs des lignes vides.
- les listes puce sont acceptes aussi
- Typiquement, un tiret ou un astrisk prcds d'un espace unique
unique, spars par des lignes vides mais les conventions peuvent
varier

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.

5.2.2 Cas dune petite quipe prive


Le cas le plus probable que vous rencontrerez est celui du projet priv avec un ou deux autres
dveloppeurs. Par priv, jentends source ferm non accessible au public en lecture. Vous et les autres
dveloppeurs aurez accs en pousse au dpt.
Dans cet environnement, vous pouvez suivre une mthode similaire ce que vous feriez en
utilisant Subversion ou tout autre systme centralis. Vous bnciez toujours davantages tels que
la validation hors-ligne et la gestion de branche et de fusion grandement simplie mais les tapes
restent similaires. La dirence principale reste que les fusions ont lieu du ct client plutt que
sur le serveur au moment de valider. Voyons quoi pourrait ressembler la collaboration de deux
dveloppeurs sur un dpt partag. Le premier dveloppeur, John, clone le dpt, fait une modication et valide localement. Dans les exemples qui suivent, les messages de protocole sont remplacs
par ... pour les raccourcir .

# 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

Sco Chacon Pro Git

Section 5.2 Contribution un projet

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(-)

prsent, Jessica pousse son travail sur le serveur :

# Ordinateur de Jessica
$ git push origin master
...
To jessica@githost:simplegit.git
1edee6b..fbff5bc

master -> master

John tente aussi de pousser ses modications :

# Ordinateur de John
$ git push origin master
To john@githost:simplegit.git
! [rejected]

master -> master (non-fast forward)

error: failed to push some refs to 'john@githost:simplegit.git'

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 :

$ git fetch origin


...
From john@githost:simplegit
+ 049d078...fbff5bc master

-> origin/master

prsent, le dpt local de John ressemble la gure 5-4.


John a une rfrence aux modications que Jessica a pousses, mais il doit les fusionner dans
sa propre branche avant de pouvoir pousser :
109

Chapitre 5 Git distribu

Sco Chacon Pro Git

Figure 5.4: tat initial du dpt de John.

$ git merge origin/master


Merge made by recursive.
TODO |

1 +

1 files changed, 1 insertions(+), 0 deletions(-)

Cee fusion se passe sans problme lhistorique de commits de John ressemble prsent
la gure 5-5.

Figure 5.5: Le dpt local de John aprs la fusion dorigin/master.

Maintenant, John peut tester son code pour sassurer quil fonctionne encore correctement et
peut pousser son travail nouvellement fusionn sur le serveur :

$ git push origin master


...
To john@githost:simplegit.git
fbff5bc..72bbc59

master -> master

la n, lhistorique des commits de John ressemble la gure 5-6.


110

Sco Chacon Pro Git

Section 5.2 Contribution un projet

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.

Figure 5.7: Lhistorique initial de commits de Jessica.

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

Chapitre 5 Git distribu

Sco Chacon Pro Git

$ git log --no-merges origin/master ^issue54


commit 738ee872852dfaa9d6634e0dea7a324040193016
Author: John Smith <jsmith@example.com>
Date:

Fri May 29 16:01:27 2009 -0700

Eliminer une valeur par defaut invalide

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 :

$ git checkout master


Switched to branch "master"
Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded.

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 :

$ git merge prob54


Updating fbff5bc..4af4298
Fast forward
LISEZMOI

lib/simplegit.rb |

1 +
6 +++++-

2 files changed, 6 insertions(+), 1 deletions(-)

Aucun problme napparat. Comme vous pouvez le voir, cest une simple avance rapide. Maintenant, Jessica fusionne le travail de John (origin/master) :

$ git merge origin/master


Auto-merging lib/simplegit.rb
Merge made by recursive.
lib/simplegit.rb |

2 +-

1 files changed, 1 insertions(+), 1 deletions(-)

Tout a fusionn proprement et lhistorique de Jessica ressemble la gure 5-9.


Maintenant origin/master est accessible depuis la branche master de Jessica, donc elle
devrait tre capable de pousser (en considrant que John na pas encore pouss dans lintervalle) :

$ git push origin master


...
To jessica@githost:simplegit.git
72bbc59..8059c15

112

master -> master

Sco Chacon Pro Git

Section 5.2 Contribution un projet

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

Chapitre 5 Git distribu

Sco Chacon Pro Git

5.2.3 quipe prive importante


Dans le scnario suivant, nous aborderons les rles de contributeur dans un groupe priv plus
grand. Vous apprendrez comment travailler dans un environnement o des petits groupes collaborent sur des fonctionnalits, puis les contributions de chaque quipe sont intgres par une autre
entit.
Supposons que John et Jessica travaillent ensemble sur une premire fonctionnalit, tandis que
Jessica et Josie travaillent sur une autre. Dans ce cas, lentreprise utilise un mode dopration de
type gestionnaire dintgration o le travail des groupes est intgr par certains ingnieurs,
et la branche master du dpt principal ne peut tre mise jour que par ces ingnieurs. Dans
ce scnario, tout le travail est valid dans des branches orientes quipe, et tir plus tard par les
intgrateurs.
Suivons le cheminement de Jessica tandis quelle travaille sur les deux nouvelles fonctionnalits,
collaborant en parallle avec deux dveloppeurs dirents dans cet environnement. En supposant
quelle a clon son dpt, elle dcide de travailler sur la fonctionA en premier. Elle cre une
nouvelle branche pour cee fonction et travaille un peu dessus :

# 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 :

$ git push origin fonctionA


...
To jessica@githost:simplegit.git
* [new branch]

fonctionA -> fonctionA

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"

prsent, Jessica ralise quelques validations sur la branche fonctionB :


114

Sco Chacon Pro Git

Section 5.2 Contribution un projet

$ 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(-)

Le dpt de Jessica ressemble la gure 5-12.

Figure 5.12: Lhistorique initial de Jessica.

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 :

$ git fetch origin


...
From jessica@githost:simplegit
* [new branch]

fonctionBee -> origin/fonctionBee

Jessica peut prsent fusionner ceci dans le travail quelle a ralis grce git merge :

$ git merge origin/fonctionBee


Auto-merging lib/simplegit.rb
Merge made by recursive.
lib/simplegit.rb |

4 ++++

1 files changed, 4 insertions(+), 0 deletions(-)

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

Chapitre 5 Git distribu

Sco Chacon Pro Git

$ git push origin fonctionB:fonctionBee


...
To jessica@githost:simplegit.git
fba9af8..cd685d1

fonctionB -> fonctionBee

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 :

$ git fetch origin


...
From jessica@githost:simplegit
3300904..aad881d

fonctionA

-> origin/fonctionA

Elle peut alors voir ce qui a t modi avec git log :

$ git log origin/fonctionA ^fonctionA


commit aad881d154acdaeb2b6b18ea0e827ed8a6d671e6
Author: John Smith <jsmith@example.com>
Date:

Fri May 29 19:57:33 2009 -0700

largeur du log passee de 25 a 30

Finalement, elle fusionne le travail de John dans sa propre branche fonctionA :

$ git checkout fonctionA


Switched to branch "fonctionA"
$ git merge origin/fonctionA
Updating 3300904..aad881d
Fast forward
lib/simplegit.rb |

10 +++++++++-

1 files changed, 9 insertions(+), 1 deletions(-)

Jessica veut rgler quelques dtails. Elle valide donc encore et pousse ses changements sur le
serveur :

$ git commit -am 'details regles'


[fonctionA ed774b3] details regles
1 files changed, 1 insertions(+), 1 deletions(-)
$ git push origin fonctionA
...
To jessica@githost:simplegit.git
3300904..ed774b3

116

fonctionA -> fonctionA

Sco Chacon Pro Git

Section 5.2 Contribution un projet

Lhistorique des commits de Jessica ressemble prsent la gure 5-13.

Figure 5.13: Lhistorique de Jessica aprs la validation dans le brane thmatique.

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.

5.2.4 Petit projet public


Contribuer un projet public est assez dirent. Il faut prsenter le travail au mainteneur
dune autre manire parce que vous navez pas possibilit de mere jour directement des branches
du projet. Ce premier exemple dcrit un mode de contribution via des serveurs Git qui proposent
facilement la duplication de dpt. Les site repo.or.cz ou GitHub proposent cee mthode, et de
nombreux mainteneurs saendent ce style de contribution. Le chapitre suivant traite des projets
qui prrent accepter les contributions sous forme de patch via e-mail.
117

Chapitre 5 Git distribu

Sco Chacon Pro Git

Figure 5.15: Une squence simple de gestion oriente quipe.

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 :

$ git clone (url)


$ cd projet
$ git checkout -b fonctionA
$ (travail)
$ git commit
$ (travail)
$ git commit

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 :

$ git remote add macopie (url)

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

Sco Chacon Pro Git

Section 5.2 Contribution un projet

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 :

$ git push macopie fonctionA

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 :

$ git request-pull origin/master macopie


The following changes since commit 1edee6b1d61823a2de3b09c160d7080b8d1b3a40:
John Smith (1):
ajout d'une nouvelle fonction
are available in the git repository at:
git://githost/simplegit.git fonctionA
Jessica Smith (2):
Ajout d'une limite la fonction de log
change la largeur du log de 25 a 30
lib/simplegit.rb |

10 +++++++++-

1 files changed, 9 insertions(+), 1 deletions(-)

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 :

$ git checkout -b fonctionB origin/master

119

Chapitre 5 Git distribu

Sco Chacon Pro Git

$ (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 :

$ git checkout fonctionA


$ git rebase origin/master
$ git push f macopie fonctionA

Cee action rcrit votre historique pour quil ressemble la gure 5-17.

Figure 5.17: Historique des validations aprs le travail sur fonctionA.

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

Sco Chacon Pro Git

Section 5.2 Contribution un projet

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 :

$ git checkout -b fonctionBv2 origin/master


$ git merge --no-commit --squash fonctionB
$ (changement d'implmentation)
$ git commit
$ git push macopie fonctionBv2

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).

Figure 5.18: Historique des validations aprs le travail sur fonctionBv2.

5.2.5 Grand projet public


De nombreux grands projets ont des procdures tablies pour accepter des patchs il faut
vrier les rgles spciques chaque projet qui peuvent varier. Nanmoins, ils sont nombreux
accepter les patchs via une liste de diusion de dveloppement, ce que nous allons clairer dun
exemple.
La mthode est similaire au cas prcdent vous crez une branche thmatique par srie de
patchs sur laquelle vous travaillez. La dirence rside dans la manire de les soumere au projet.
Au lieu de dupliquer le projet et de pousser vos soumissions sur votre dpt, il faut gnrer des
versions e-mail de chaque srie de commits et les envoyer la liste de diusion de dveloppement.

$ git checkout -b sujetA


$ (travail)
$ git commit

121

Chapitre 5 Git distribu

Sco Chacon Pro Git

$ (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.

$ git format-patch -M origin/master


0001-Ajout-d-une-limite-la-fonction-de-log.patch
0002-change-la-largeur-du-log-de-25-a-30.patch

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 files changed, 1 insertions(+), 1 deletions(-)


diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index 76f47bc..f9815f1 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -14,7 +14,7 @@ class SimpleGit
end
def log(treeish = 'master')
+

command("git log #{treeish}")


command("git log -n 20 #{treeish}")
end
def ls_tree(treeish = 'master')

-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

Sco Chacon Pro Git

Section 5.2 Contribution un projet

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 :

$ git send-email *.patch


0001-Ajout-d-une-limite-la-fonction-de-log.patch
0002-change-la-largeur-du-log-de-25-a-30.patch
Who should the emails appear to be from? [Jessica Smith <jessica@example.com>]
Emails will be sent from: Jessica Smith <jessica@example.com>
Who should the emails be sent to? jessica@example.com
Message-ID to be used as In-Reply-To for the first email? y

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 :

(mbox) Adding cc: Jessica Smith <jessica@example.com> from


\line 'From: Jessica Smith <jessica@example.com>'
OK. Log says:
Sendmail: /usr/sbin/sendmail -i jessica@example.com
From: Jessica Smith <jessica@example.com>

123

Chapitre 5 Git distribu

Sco Chacon Pro Git

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.

5.3 Maintenance dun projet


En plus de savoir comment contribuer ecacement un projet, vous aurez probablement besoin de savoir comment en maintenir un. Cela peut consister accepter et appliquer les patchs
gnrs via format-patch et envoys par e-mail, ou intgrer des modications dans des branches
distantes de dpts distants. e vous mainteniez le dpt de rfrence ou que vous souhaitiez aider
en vriant et approuvant les patchs, vous devez savoir comment accepter les contributions dune
manire limpide pour vos contributeurs et soutenable long terme pour vous.

5.3.1 Travail dans des branes thmatiques


and vous vous apprtez intgrer des contributions, un bonne ide consiste les essayer
dabord dans une branche thmatique, une branche temporaire spciquement cre pour essayer
cee nouveaut. De cee manire, il est plus facile de rectier un patch part et de le laisser sil ne
fonctionne pas jusqu ce que vous disposiez de temps pour y travailler. Si vous crez une simple
branche nomme daprs le thme de la modication que vous allez essayer, telle que ruby_client
ou quelque chose daussi descriptif, vous pouvez vous en souvenir simplement plus tard. Le mainteneur du projet Git a lhabitude dutiliser des espaces de nommage pour ses branches, tels que sc/
ruby_client, o sc reprsente les initiales de la personne qui a contribu les modications.
Comme vous devez vous en souvenir, on cre une branche part du master de la manire suivante :

$ git branch sc/ruby_client master

124

Sco Chacon Pro Git

Section 5.3 Maintenance dun projet

Ou bien, si vous voulez aussi basculer immdiatement dessus, vous pouvez utiliser loption
checkout -b :

$ git checkout -b sc/ruby_client master

Vous voil maintenant prt ajouter les modications sur cee branche thmatique et dterminer si cest prt tre fusionn dans les branches au long cours.

5.3.2 Application des pats partir de-mail


Si vous recevez par e-mail un patch que vous devez intgrer votre projet, vous avez besoin
dappliquer le patch dans une branche thmatique pour lvaluer. Il existe deux mthodes pour
appliquer un patch envoy par e-mail : git apply et git am.
Application dun pat avec apply
Si vous avez reu le patch de quelquun qui la gnr avec la commande git diff ou diff
Unix, vous pouvez lappliquer avec la commande git apply. Si le patch a t sauv comme chier
/tmp/patch-ruby-client.patch, vous pouvez lappliquer comme ceci :

$ git apply /tmp/patch-ruby-client.patch

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 :

$ git apply --check 0001-seeing-if-this-helps-the-gem.patch


error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply

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

Chapitre 5 Git distribu

Sco Chacon Pro Git

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 :

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

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:

Ajout d'une limite la fonction de log

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 :

$ git log --pretty=fuller -1


commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
Author:

Jessica Smith <jessica@example.com>

AuthorDate: Sun Apr 6 10:17:23 2008 -0700


Commit:

Scott Chacon <schacon@gmail.com>

CommitDate: Thu Apr 9 09:19:06 2009 -0700


Ajout d'une limite la fonction de log
Limite la fonctionnalit de log aux 20 premires lignes

Linformation Commit indique la personne qui a appliqu le patch et la date dapplication.


Linformation Author indique la personne qui a cr le patch et la date de cration.
126

Sco Chacon Pro Git

Section 5.3 Maintenance dun projet

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

Chapitre 5 Git distribu

Sco Chacon Pro Git

$ 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.

5.3.3 Vrication des branes distantes


Si votre contribution a t fournie par un utilisateur de Git qui a mis en place son propre
dpt public sur lequel il a pouss ses modications et vous a envoy lURL du dpt et le nom de la
branche distante, vous pouvez les ajouter en tant que dpt distant et raliser les fusions localement.
Par exemple, si Jessica vous envoie un e-mail indiquant quelle a une nouvelle fonctionnalit
gniale dans la branche ruby-client de son dpt, vous pouvez la tester en ajoutant le dpt
distant et en tirant la branche localement :

$ git remote add jessica git://github.com/jessica/monprojet.git


$ git fetch jessica
$ git checkout -b rubyclient jessica/ruby-client

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

Sco Chacon Pro Git

Section 5.3 Maintenance dun projet

$ git pull git://github.com/typeunique/projet.git


From git://github.com/typeunique/projet
* branch

HEAD

-> FETCH_HEAD

Merge made by recursive.

5.3.4 Dterminer les modications introduites


Vous avez maintenant une branche thmatique qui contient les contributions. De ce point, vous
pouvez dterminer ce que vous souhaitez en faire. Cee section revisite quelques commandes qui
vont vous permere de faire une revue de ce que vous allez exactement introduire si vous fusionnez
dans la branche principale.
Faire une revue de tous les commits dans cee branche savre souvent dune grande aide. Vous
pouvez exclure les commits de la branche master en ajoutant loption --not devant le nom de la
branche. Par exemple, si votre contributeur vous envoie deux patchs et que vous crez une branche
appele contrib et y appliquez ces patchs, vous pouvez lancer ceci :

$ git log contrib --not master


commit 5b6235bd297351589efc4d73316f0a68d484f118
Author: Scott Chacon <schacon@gmail.com>
Date:

Fri Oct 24 09:53:59 2008 -0700

seeing if this helps the gem


commit 7482e0d16d04bea79d0dba8988cc78df655f16a0
Author: Scott Chacon <schacon@gmail.com>
Date:

Mon Oct 22 19:38:36 2008 -0700

updated the gemspec to hopefully work better

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 :

$ git diff master

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

Chapitre 5 Git distribu

Sco Chacon Pro Git

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 :

$ git merge-base contrib master


36c7dba2c95e6bbb78dfa822519ecfec6e1ca649
$ git diff 36c7db

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 :

$ git diff master...contrib

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.

5.3.5 Intgration des contributions


Lorsque tout le travail de votre branche thmatique est prt tre intgr dans la branche
principale, il reste savoir comment le faire. De plus, il faut connatre le mode de gestion que vous
souhaitez pour votre projet. Vous avez de nombreux choix et je vais en traiter quelques uns.
Modes de fusion
Un mode simple fusionne votre travail dans la branche master. Dans ce scnario, vous avez
une branche master qui contient le code stable. and vous avez des modications prtes dans
une branche thmatique, vous la fusionnez dans votre branche master puis eacez la branche thmatique, et ainsi de suite. Si vous avez un dpt contenant deux branches nommes ruby_client
et php_client qui ressemble la gure 5-19 et que vous fusionnez ruby_client en premier,
suivi de php_client, alors votre historique ressemblera la n la gure 5-20.
Cest probablement le mode le plus simple mais cela peut savrer problmatique si vous avez
grer des dpts ou des projets plus gros.
Si vous avez plus de dveloppeurs ou un projet plus important, vous souhaiterez probablement
utiliser un cycle fusion au moins deux tapes. Dans ce scnario, vous avez deux branches au long
cours, master et develop, dans lequel vous dterminez que master est mis jour seulement
lors dune version vraiment stable et tout le nouveau code est intgr dans la branche develop.
Vous poussez rgulirement ces deux branches sur le dpt public. Chaque fois que vous avez une
nouvelle branche thmatique fusionner (gure 5-21), vous la fusionnez dans develop (gure 522). Puis, lorsque vous balisez une version majeure, vous meez master niveau avec ltat stable
de develop en avance rapide (gure 5-23).
130

Sco Chacon Pro Git

Section 5.3 Maintenance dun projet

Figure 5.19: Historique avec quelques branes thmatiques.

Figure 5.20: Aprs fusion dune brane thmatique.

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

Chapitre 5 Git distribu

Sco Chacon Pro Git

Figure 5.21: Avant la fusion dune brane thmatique.

Figure 5.22: Aprs la fusion dune brane thmatique.

Figure 5.23: Aprs une publication dune brane thmatique.

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

Sco Chacon Pro Git

Section 5.3 Maintenance dun projet

Figure 5.24: Srie complexe de branes thmatiques contribues en parallle.

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

Chapitre 5 Git distribu

Sco Chacon Pro Git

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.

Figure 5.26: Historique dexemple avant une slection.

Si vous souhaitez tirer le commit e43a6 dans votre branche master, vous pouvez lancer

$ git cherry-pick e43a6fd3e94888d76779ad79fb568ed180e5fcdf


Finished one cherry-pick.
[master]: created a0a41a9: "More friendly message when locking the index fails."
3 files changed, 17 insertions(+), 3 deletions(-)

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

Sco Chacon Pro Git

Section 5.3 Maintenance dun projet

5.3.6 Balisage de vos publications


and vous dcidez darrter une publication de votre projet, vous souhaiterez probablement
baliser le projet pour pouvoir recrer cee version dans le futur. Vous pouvez crer une nouvelle
balise telle que dcrite au chapitre 2. Si vous dcidez de signer la balise en tant que mainteneur, la
commande ressemblera ceci :

$ git tag -s v1.5 -m 'my signed 1.5 tag'


You need a passphrase to unlock the secret key for
user: "Scott Chacon <schacon@gmail.com>"
1024-bit DSA key, ID F721C45A, created 2009-02-09

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

1024D/F721C45A 2009-02-09 [expires: 2010-02-09]

uid

Scott Chacon <schacon@gmail.com>

sub

2048g/45D02282 2009-02-09 [expires: 2010-02-09]

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 :

$ gpg -a --export F721C45A | git hash-object -w --stdin


659ef797d181633c87ec71ac3f9ba29fe5775b92

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 :

$ git tag -a maintainer-pgp-pub 659ef797d181633c87ec71ac3f9ba29fe5775b92

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 :

$ git show maintainer-pgp-pub | gpg --import

135

Chapitre 5 Git distribu

Sco Chacon Pro Git

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>.

5.3.7 Gnration dun nom de rvision


Comme Git ne fournit pas par nature de nombres croissants tels que r123 chaque validation, la commande git describe permet de gnrer un nom humainement lisible pour chaque
commit. Git concatne la nom de la balise la plus proche, le nombre de validations depuis cee balise
et un code SHA-1 partiel du commit que lon cherche dnir :

$ git describe master


v1.6.2-rc1-20-g8c5b85c

De cee manire, vous pouvez exporter un instantan ou le construire et le nommer de manire


intelligible. En fait, si Git est construit partir du source clon depuis le dpt Git, git --version
vous donne exactement cee valeur. Si vous demandez la description dun instantan qui a t balis,
le nom de la balise est retourn.
La commande git describe repose sur les balises annotes (balises cres avec les options
-a ou -s). Les balises de publication doivent donc tre cres de cee manire si vous souhaitez
utiliser git describe pour garantir que les commits seront dcrits correctement. vous pouvez
aussi utiliser ces noms comme cible lors dune extraction ou dune commande show, bien quils
reposent sur le SHA-1 abrg et pourraient ne pas rester valide indniment. Par exemple, le noyau
Linux a saut dernirement de 8 10 caractres pour assurer lunicit des objets SHA-1 et les anciens
noms git describe sont par consquent devenus invalides.

5.3.8 Prparation dune publication


Maintenant, vous voulez publier une version. Une des tapes consiste crer une archive du
dernier instantan de votre code pour les pauvres hres qui nutilisent pas Git. La commande ddie
cee action est git archive :

$ git archive master --prefix='projet/' | gzip > `git describe master`.tar.gz


$ ls *.tar.gz
v1.6.2-rc1-20-g8c5b85c.tar.gz

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 :

$ git archive master --prefix='projet/' --format=zip > `git describe master`.zip

Voil deux belles archives tar.gz et zip de votre projet prtes tre tlcharges sur un site web
ou envoyes par e-mail.
136

Sco Chacon Pro Git

Section 5.4 Rsum

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 :

$ git shortlog --no-merges master --not v1.0.1


Chris Wanstrath (8):
Add support for annotated tags to Grit::Tag
Add packed-refs annotated tag support.
Add Grit::Commit#to_patch
Update version and History.txt
Remove stray `puts`
Make ls_tree ignore nils
Tom Preston-Werner (4):
fix dates in history
dynamic version method
Version bump to 1.0.2
Regenerated gemspec for version 1.0.2

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.

6.1 Slection des versions


Git vous permet dadresser certains commits ou un ensemble de commits de direntes faons.
Si elles ne sont pas toutes videntes il est bon de les connatre.

6.1.1 Rvisions ponctuelles


Naturellement, vous pouvez rfrencer un commit par la signature SHA-1, mais il existe des
mthodes plus confortables pour le genre humain. Cee section prsente les mthodes pour rfrencer
un commit simple.

6.1.2 Empreinte SHA courte


Git est capable de deviner de quel commit vous parlez si vous ne fournissez que quelques
caractres au dbut de la signature, tant que votre SHA-1 partiel comporte au moins 4 caractres et
ne gnre pas de collision. Dans ces conditions, un seul objet correspondra ce SHA-1.
Par exemple, pour acher un commit prcis, supposons que vous excutiez git log et que
vous identiez le commit o vous avez introduit une fonctionnalit prcise.

$ git log
commit 734713bc047d87bf7eac9674765ae793478c50d3
Author: Scott Chacon <schacon@gmail.com>
Date:

Fri Jan 2 18:32:33 2009 -0800

fixed refs handling, added gc auto, updated tests

139

Chapitre 6 Utilitaires Git

Sco Chacon Pro Git

commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Merge: 1c002dd... 35cfb2b...
Author: Scott Chacon <schacon@gmail.com>
Date:

Thu Dec 11 15:08:43 2008 -0800

Merge commit 'phedders/rdocs'


commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
Author: Scott Chacon <schacon@gmail.com>
Date:

Thu Dec 11 14:58:32 2008 -0800

added some blame and merge stuff

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 show 1c002dd4b536e7479fe34593e72e6c6c1819e53b


$ git show 1c002dd4b536e7479f
$ git show 1c002d

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 :

$ git log --abbrev-commit --pretty=oneline


ca82a6d changed the version number
085bb3b removed unnecessary test code
a11bef0 first commit

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.

6.1.3 QUELQUES MOTS SUR SHA-1


Beaucoup de gens se soucient qu un moment donn ils auront, par des circonstances hasardeuses,
deux objets dans leur rfrentiel de hachage de mme empreinte SHA-1. en est-il rellement ?
Sil vous arrivait de consigner (commit) un objet qui se hache de la mme empreinte SHA-1
dun objet existant dans votre rfrentiel, Git verrez lobjet existant dj dans votre base de donnes
et Git prsumera quil tait dj enregistr. Si vous essayez de rcuprer lobjet de nouveau un
moment donn, vous aurez toujours les donnes du premier objet.
oi quil en soit, vous devriez tre conscient quel point ce scnario est ridiculement improbable. Une empreinte SHA-1 porte sur 20 octets soit 160bits. Le nombre dobjet alatoires hasher
requis pour assurer une probabilit de collision de 50% vaut environ 280 (la formule pour calculer
140

Sco Chacon Pro Git

la probabilit de collision est p =

Section 6.1 Slection des versions


n(n1)
2

1
2160 ).

280 vaut 1.21024 soit 1 million de milliards de

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.

6.1.4 Rfrences de branes


La mthode la plus commune pour dsigner un commit est une branche y pointant. Ds lors,
vous pouvez utiliser le nom de la branche dans toute commande utilisant un objet de type commit ou
un SHA-1. Par exemple, si vous souhaitez acher le dernier commit dune branche, les commandes
suivantes sont quivalentes, en supposant que la branche sujet1 pointe sur ca82a6d :

$ git show ca82a6dff817ec66f44342007202690a93763949


$ git show sujet1

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 rev-parse sujet1


ca82a6dff817ec66f44342007202690a93763949

6.1.5 Raccourcis RefLog


Git maintient en arrire-plan un historique des rfrences o sont passes HEAD et vos branches
sur les dernieres mois - ceci sappelle le reog.
Vous pouvez le consulter avec la commande git reflog :

$ 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

Chapitre 6 Utilitaires Git

Sco Chacon Pro Git

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 :

$ git show HEAD@{5}

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 :

$ git show master@{yesterday}

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 :

$ git log -g master


commit 734713bc047d87bf7eac9674765ae793478c50d3
Reflog: master@{0} (Scott Chacon <schacon@gmail.com>)
Reflog message: commit: fixed refs handling, added gc auto, updated
Author: Scott Chacon <schacon@gmail.com>
Date:

Fri Jan 2 18:32:33 2009 -0800

fixed refs handling, added gc auto, updated tests


commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Reflog: master@{1} (Scott Chacon <schacon@gmail.com>)
Reflog message: merge phedders/rdocs: Merge made by recursive.
Author: Scott Chacon <schacon@gmail.com>
Date:

Thu Dec 11 15:08:43 2008 -0800

Merge commit 'phedders/rdocs'

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.

6.1.6 Rfrences passes


Une solution frquente de rfrencer un commit est dutiliser son anctre. Si vous suxez une
rfrence par , Git la rsoudra comme tant le parent de cee rfrence. Supposons que vous
consultiez votre historique :

142

Sco Chacon Pro Git

Section 6.1 Slection des versions

$ git log --pretty=format:'%h %s' --graph


* 734713b fix sur la gestion des refs, ajout gc auto, mise jour des tests
*

d921970 Merge commit 'phedders/rdocs'

|\
| * 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 :

$ git show HEAD^


commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Merge: 1c002dd... 35cfb2b...
Author: Scott Chacon <schacon@gmail.com>
Date:

Thu Dec 11 15:08:43 2008 -0800

Merge commit 'phedders/rdocs'

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 :

$ git show d921970^


commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
Author: Scott Chacon <schacon@gmail.com>
Date:

Thu Dec 11 14:58:32 2008 -0800

ajout blame and merge


$ git show d921970^2
commit 35cfb2b795a55793d7cc56a6cc2060b4bb732548
Author: Paul Hedderly <paul+git@mjr.org>
Date:

Wed Dec 10 22:22:03 2008 +0000

modifs minor rdoc

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

Chapitre 6 Utilitaires Git

Sco Chacon Pro Git

$ git show HEAD~3


commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
Author: Tom Preston-Werner <tom@mojombo.com>
Date:

Fri Nov 7 13:47:59 2008 -0500

ignore *.gem

Cela aura bien pu tre crit HEAD, qui l encore est le premier parent du premier parent
du premier parent :

$ git show HEAD^^^


commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
Author: Tom Preston-Werner <tom@mojombo.com>
Date:

Fri Nov 7 13:47:59 2008 -0500

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.

6.1.7 Plages de commits


A prsent que vous pouvez spcier des commits individuels, voyons comme spcier une
place de commits. Ceci est particulirement pratique pour la gestion des branches si vous avez
beaucoup de branches, vous pouvez utiliser les plages pour adresser des problmes tels que elle
activit sur cee branche nai-je pas encore fusionn sur ma branche principale ? .
Double point
La plus frquente spcication de plage de commit est la syntaxe double-point. En gros, cela
demande Git de rsoudre la plage des commits qui sont accessible depuis un commit mais ne le
sont pas depuis un autre. Par exemple, disons que votre historique ressemble celui de la Figure 6.1.

Figure 6.1: Exemple dhistorique pour la slection de plages de commits.

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

Sco Chacon Pro Git

Section 6.1 Slection des versions

$ git log master..experiment


D
C

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 :

$ git log experiment..master


F
E

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 :

$ git log origin/master..HEAD

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 :

$ git log refA..refB


$ git log ^refA refB
$ git log refB --not refA

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

Chapitre 6 Utilitaires Git

Sco Chacon Pro Git

$ git log refA refB ^refC


$ git log refA refB --not refC

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 :

$ git log master...experiment


F
E
D
C

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 :

$ git log --left-right master...experiment


< F
< E
> D
> C

Avec ces outils, vous pourrez utiliser Git pour savoir quels commits inspecter.

6.2 Mise en attente interactive


Git propose quelques scripts qui rendent les oprations en ligne de commande plus simple.
Nous allons prsent dcouvrir des commandes interactives vous permeant de choisir les chiers
ou une partie dun chier incorporer un commit. Ces outils sont particulirement pratiques si
vous modiez un large primtre de chiers et que vous souhaitez les commiter sparement plutt
que massivement. De la sorte, vous vous assurez que vos commits sont des ensembles cohrents et
quils peuvent tre facilement revus par vos collaborateurs. Si vous excutez git add avec loption
-i ou --interactive, Git rentre en mode interactif, achant quelque chose comme :

146

Sco Chacon Pro Git

Section 6.2 Mise en aente interactive

$ git add -i
staged

unstaged path

1:

unchanged

+0/-1 TODO

2:

unchanged

+1/-1 index.html

3:

unchanged

+5/-1 lib/simplegit.rb

*** Commands ***


1: status

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.

6.2.1 Mettre en attente des iers


Si vous tapez 2 ou u au prompt What now>, le script vous demande quels chiers vous voulez
mere 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

Chapitre 6 Utilitaires Git

Sco Chacon Pro Git

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) :

*** Commands ***


1: status

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 :

*** Commands ***


1: status

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

Sco Chacon Pro Git

Section 6.2 Mise en aente interactive

*** Commands ***


1: status

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.

6.2.2 Pates de Staging


Git est galement capable de mere en aente certaines parties dun chier. Par exemple, si
vous modiez en 2 endroits votre chier simplegit.rb et que vous souhaitez mere en aente lune
dentre elles seulement, cela peut se faire trs aisment avec Git. En mode interactif, tapez 5 ou p
(pour patch en anglais). Git vous demandera quels chiers vous voulez mere en aente partiellement, puis, pour chaque section des chiers slectionns, il achera les parties de chiers o il y a
des dirences et vous demandera si vous souhaitez les mere en aente, un par un :

diff --git a/lib/simplegit.rb b/lib/simplegit.rb


index dd5ecc4..57399e0 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -22,7 +22,7 @@ class SimpleGit
end
def log(treeish = 'master')
+

command("git log -n 25 #{treeish}")


command("git log -n 30 #{treeish}")
end
def blame(path)

Stage this hunk [y,n,a,d,/,j,J,g,e,?]?

A cee tape, vous disposez de bon nombre doptions. ? vous liste les actions possibles, voici
une traduction :
149

Chapitre 6 Utilitaires Git

Sco Chacon Pro Git

Mettre en attente cette partie [y,n,a,d,/,j,J,g,e,?]? ?


y - mettre en attente cette partie
n - ne pas mettre en attente cette partie
a - mettre en attente cette partie et toutes celles restantes dans ce fichier
d - ne pas mettre en attente cette partie ni aucune de celles restantes dans ce fichier
g - slectionner un partie voir
/ - chercher une partie correspondant la regexp donne
j - laisser cette partie non dcide, voir la prochaine partie non encore dcide
J - laisser cette partie non dcide, voir la prochaine partie
k - laisser cette partie non dcide, voir la partie non encore dcide prcendente
K - laisser cette partie non dcide, voir la partie prcdente
s - couper la partie courante en parties plus petites
e - modifier manuellement la partie courante
? - afficher l'aide

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

Sco Chacon Pro Git

Section 6.3 La remise

6.3.1 Remiser votre travail


Pour dmontrer cee possibilit, vous allez dans votre projet et commencez travailler sur
quelques chiers et mere en zone daente lun de ces changements. Si vous excutez git status, vous pouvez voir votre tat instable:

$ git status
# On branch master
# Changes to be committed:
#

(use "git reset HEAD <file>..." to unstage)

#
#

modified:

index.html

#
# Changed but not updated:
#

(use "git add <file>..." to update what will be committed)

#
#

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")

Votre rpertoire de travail est propre :

$ 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 :

$ git stash list


stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051... Revert "added file_size"
stash@{2}: WIP on master: 21d80a5... added number to log

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

Chapitre 6 Utilitaires Git

Sco Chacon Pro Git

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.

$ git stash apply


# On branch master
# Changed but not updated:
#

(use "git add <file>..." to update what will be committed)

#
#

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 :

$ git stash apply --index


# On branch master
# Changes to be committed:
#

(use "git reset HEAD <file>..." to unstage)

#
#

modified:

index.html

#
# Changed but not updated:
#

(use "git add <file>..." to update what will be committed)

#
#

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 :

$ git stash list

152

Sco Chacon Pro Git

Section 6.4 Rcrire lhistorique

stash@{0}: WIP on master: 049d078 added the index file


stash@{1}: WIP on master: c264051... Revert "added file_size"
stash@{2}: WIP on master: 21d80a5... added number to log
$ git stash drop stash@{0}
Dropped stash@{0} (364e91f3f268f0900bc3ee613f9f733e82aaed43)

Vous pouvez galement excutez git stash pop pour appliquer et supprimer immdiatement la remise de votre pile.

6.3.2 Crer une brane depuis une remise


Si vous remiser votre travail, loubliez pendant un temps en continuant sur la branche o vous
avez cr la remise, vous pouvez avoir un problme en rappliquant le travail. Si lapplication de la
remise essaye de modier un chier que vous avez modi depuis, vous allez obtenir des conits
de fusion et vous devrez essayer de les rsoudre. Si vous voulez un moyen plus facile de tester une
nouvelle fois les modications remises, vous pouvez excuter git stash branch, qui crera
une nouvelle branche votre place, rcuprant le commit o vous tiez lorsque vous avez cr la
remise, rappliquera votre travail dedans, et supprimera nalement votre remise si cela a russi :

$ git stash branch testchanges


Switched to a new branch "testchanges"
# On branch testchanges
# Changes to be committed:
#

(use "git reset HEAD <file>..." to unstage)

#
#

modified:

index.html

#
# Changed but not updated:
#

(use "git add <file>..." to update what will be committed)

#
#

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.

6.4 Rcrire lhistorique


Bien souvent, lorsque vous travaillez avec Git, vous souhaitez modier votre historique de
consignation pour une raison quelconque. Une des choses merveilleuses de Git est quil vous permet
de prendre des dcisions le plus tard possible. Vous pouvez dcider quels chiers vont dans quel
commit avant que vous ne consigniez la zone daente, vous pouvez dcider que vous ne voulez pas
encore montrer que vous travailler sur quelque chose avec les remises, et vous pouvez rcrire les
commits an dj sauvegard pour quils ressemblent quelque chose dautre. Cela peut signier
changer lordre des commits, modier les messages ou modier les chiers appartenant au commit,
153

Chapitre 6 Utilitaires Git

Sco Chacon Pro Git

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.

6.4.1 Modier la dernire consignation


Modier votre dernire consignation est probablement la plus habituelle rcriture de lhistorique
que vous allez faire. Vous voudrez souvent faire deux choses basiques votre dernier commit :
modier le message de consignation, ou changer le contenu que vous avez enregistr en ajoutant,
modiant ou supprimant des chiers.
Si vous voulez seulement modier votre dernier message de consignation, cest vraiment simple
:

$ git commit --amend

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 !

6.4.2 Modier plusieurs messages de consignation


Pour modier une consignation qui est plus loin dans votre historique, vous devez utilisez des
outils plus complexes. Git ne contient pas doutil de modication dhistorique, mais vous pouvez
utiliser loutil rebase pour rebaser une suite de commits depuis la branche HEAD plutt que de
les dplacer vers une autre branche. Avec loutil rebase interactif, vous pouvez vous arrter aprs
chaque commit que vous voulez modiez et changer le message, ajouter des chiers ou quoique
ce soit que vous voulez. Vous pouvez excuter rebase interactivement en ajoutant loption -i
git rebase. Vous devez indiquer jusqu quand remonter dans votre historique en donnant la
commande le commit sur lequel vous voulez vous rebaser.
Par exemple, si vous voulez modier les 3 derniers messages de consignation, ou nimporte
lequel des messages dans ce groupe, vous fournissez git rebase -i le parent du dernier
commit que vous voulez diter, qui est HEAD~2 or HEAD~3. Il peut tre plus facile de ce souvenir
de ~3, car vous essayer de modier les 3 derniers commits, mais gardez lesprit que vous dsignez
le 4e, le parent du dernier commit que vous voulez modier :
154

Sco Chacon Pro Git

Section 6.4 Rcrire lhistorique

$ git rebase -i HEAD~3

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 :

pick f7f3f6d changed my name a bit


pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file
# Rebase 710f0f8..a5f4a0d onto 710f0f8
#
# Commands:
#

p, pick = use commit

e, edit = use commit, but stop for amending

s, squash = use commit, but meld into previous commit

#
# 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 :

$ git log --pretty=format:"%h %s" HEAD~3..HEAD


a5f4a0d added cat-file
310154e updated README formatting and added blame
f7f3f6d changed my name a bit

Remarquez lordre inverse. Le rebasage interactif va crer un script excuter. Il commencera


au commit que vous spciez sur la ligne de commande (HEAD~3) et refait les modications introduites dans chacun des commits du dbut la n. Il ordonne donc le plus vieux au dbut, plutt que
le plus rcent, car cest celui quil refera en premier.
Vous devez diter le script an quil sarrte au commit que vous voulez modier. Pour cela,
remplacer le mot pick par le mot edit pour chaque commit aprs lequel vous voulez que le
script sarrte. Par exemple, pour modier uniquement le message du troisime commit, vous modiez le chier pour ressembler :

155

Chapitre 6 Utilitaires Git

Sco Chacon Pro Git

edit f7f3f6d changed my name a bit


pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file

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 :

$ git rebase -i HEAD~3


Stopped at 7482e0d... updated the gemspec to hopefully work better
You can amend the commit now, with
git commit --amend
Once youre satisfied with your changes, run
git rebase --continue

Ces instructions vous disent exactement quoi faire. Entrez :

$ git commit --amend

Modiez le message de commit et quiez lditeur. Puis excutez :

$ git rebase --continue

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.

6.4.3 Rordonner les commits


Vous pouvez galement utilisez les rebasages interactifs an de rordonner ou supprimer entirement des commits. Si vous voulez supprimer le commit added cat-le et modier lordre
dans lequel les deux autres commits se trouvent dans lhistorique, vous pouvez modier le script de
rebasage :

pick f7f3f6d changed my name a bit


pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file

an quil ressemble ceci :


156

Sco Chacon Pro Git

Section 6.4 Rcrire lhistorique

pick 310154e updated README formatting and added blame


pick f7f3f6d changed my name a bit

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 .

6.4.4 Rassembler des commits


Il est galement possible de prendre une srie de commits et de les rassembler en un seul avec
loutil de rebasage interactif. Le script ache des instructions utiles dans le message de rebasage :

#
# Commands:
#

p, pick = use commit

e, edit = use commit, but stop for amending

s, squash = use commit, but meld into previous commit

#
# 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 :

pick f7f3f6d changed my name a bit


squash 310154e updated README formatting and added blame
squash a5f4a0d added cat-file

Lorsque vous sauvegardez et quiez lditeur, Git applique ces trois modications et vous remontre lditeur contenant maintenant la fusion des 3 messages de consignation :

# This is a combination of 3 commits.


# The first commit's message is:
changed my name a bit
# This is the 2nd commit message:
updated README formatting and added blame
# This is the 3rd commit message:
added cat-file

157

Chapitre 6 Utilitaires Git

Sco Chacon Pro Git

Lorsque vous sauvegardez cela, vous obtenez un seul commit amenant les modications des
trois commits prcdents.

6.4.5 Diviser un commit


Pour diviser un commit, il doit tre dfait, puis partiellement mis en zone daente et consigner
autant de fois que vous voulez pour en nir avec lui. Par exemple, supposons que vous voulez diviser
le commit du milieu dans lexemple des trois commits prcdents. Plutt que updated README
formaing and added blame , vous voulez le diviser en deux commits : updated README formaing pour le premier, et added blame pour le deuxime. Vous pouvez le faire avec le script
rebase -i en remplaant linstruction sur le commit que vous voulez divisez en edit :

pick f7f3f6d changed my name a bit


edit 310154e updated README formatting and added blame
pick a5f4a0d added cat-file

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 reset HEAD^


$ git add README
$ git commit -m 'updated README formatting'
$ git add lib/simplegit.rb
$ git commit -m 'added blame'
$ git rebase --continue

Git applique le dernier commit (a5f4a0d) de votre script, et votre historique ressemblera
alors :

$ git log -4 --pretty=format:"%h %s"


1c002dd added cat-file
9b29157 added blame
35cfb2b updated README formatting
f3cc40e changed my name a bit

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

Sco Chacon Pro Git

Section 6.4 Rcrire lhistorique

6.4.6 Loption nuclaire : lter-bran


Il existe une autre option de la rcriture dhistorique que vous pouvez utiliser si vous avez
besoin de rcrire un grand nombre de commits dune manire scriptable; par exemple, modier
globalement votre adresse mail ou supprimer un chier de tous les commits. La commande est
filter-branch, et elle peut rcrire des pans entiers de votre historique, vous ne devriez donc
pas lutiliser moins que votre projet ne soit pas encore public ou que personne na encore travaill
sur les commits que vous allez rcrire. Cependant, cela peut tre trs utile. Vous allez maintenant
apprendre quelques usages communs pour vous donner une ide de ses capacits.
Supprimer un ier de aque commit
Cela arrive asser frquemment. elquun a accidentellement commit un norme chier binaire avec une commande git add . irrchie, and vous voulez le supprimer partout. Vous
avez peut-tre consign un chier contenant un mot de passe, et que vous voulez rendre votre projet open source. filter-branch est loutil que vous voulez probablement utiliser pour neoyer
votre historique entier. Pour supprimer un chier nomm passwords.txt de tout votre historique,
vous pouvez utiliser loption --tree-filter de filter-branch :

$ git filter-branch --tree-filter 'rm -f passwords.txt' HEAD


Rewrite 6b9b3cf04e7c5686a9cb838c3f36a8cb6a0fc2bd (21/21)
Ref 'refs/heads/master' was rewritten

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 :

$ git filter-branch --subdirectory-filter trunk HEAD


Rewrite 856f0bf61e41a27326cdae8f09fe708d679f596f (12/12)
Ref 'refs/heads/master' was rewritten

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

Chapitre 6 Utilitaires Git

Sco Chacon Pro Git

Modier globalement ladresse mail


Un autre cas habituel est que vous oubliez dexcuter git config pour congurer votre nom
et votre adresse mail avant de commencer travailler, ou vous voulez peut-tre rendre un projet
du boulot open source et donc changer votre adresse professionnelle pour celle personnelle. Dans
tous les cas, vous pouvez modier ladresse mail dans plusieurs commits avec un script filterbranch Vous devez faire aention de ne changer que votre adresse mail, utilisez donc --commitfilter :

$ git filter-branch --commit-filter '


if [ "$GIT_AUTHOR_EMAIL" = "schacon@localhost" ];
then
GIT_AUTHOR_NAME="Scott Chacon";
GIT_AUTHOR_EMAIL="schacon@example.com";
git commit-tree "$@";
else
git commit-tree "$@";
fi' HEAD

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.

6.5 Deboguer avec Git


Git fournit aussi quelques outils pour vous aider dboguer votre projet. Puisque Git est conu
pour fonctionner avec pratiquement tout type de projet, ces outils sont plutt gnriques, mais ils
peuvent souvent vous aider traquer un bogue ou au moins cerner o cela tourne mal.

6.5.1 Fiier annot


Si vous traquez un bogue dans votre code et que vous voulez savoir quand il est apparu et
pourquoi, annoter les chiers est souvent le meilleur moyen. Cela vous montre le dernier commit
qui a modi chaque ligne de votre chier. Donc, si vous voyez une mthode dans votre code qui
est bogue, vous pouvez annoter le chier avec git blame pour voir quand chaque ligne de la
mthode a t modie pour la dernire fois et par qui. Cet exemple utilise loption -L pour limiter
la sortie des lignes 12 22 :

$ git blame -L 12,22 simplegit.rb


^4832fe2 (Scott Chacon

2008-03-15 10:31:28 -0700 12)

^4832fe2 (Scott Chacon

2008-03-15 10:31:28 -0700 13)

^4832fe2 (Scott Chacon

2008-03-15 10:31:28 -0700 14)

^4832fe2 (Scott Chacon

2008-03-15 10:31:28 -0700 15)

9f6560e4 (Scott Chacon

2008-03-17 21:52:20 -0700 16)

79eaf55d (Scott Chacon

2008-04-06 10:15:08 -0700 17)

9f6560e4 (Scott Chacon

2008-03-17 21:52:20 -0700 18)

9f6560e4 (Scott Chacon

2008-03-17 21:52:20 -0700 19)

42cf2861 (Magnus Chacon 2008-04-13 10:45:01 -0700 20)

160

def show(tree = 'master')


command("git show #{tree}")
end
def log(tree = 'master')
command("git log #{tree}")
end
def blame(path)

Sco Chacon Pro Git

Section 6.5 Deboguer avec Git

42cf2861 (Magnus Chacon 2008-04-13 10:45:01 -0700 21)

command("git blame #{path}")

42cf2861 (Magnus Chacon 2008-04-13 10:45:01 -0700 22)

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 :

$ git blame -C -L 141,153 GITPackUpload.m


f344f58d GITServerHandler.m (Scott 2009-01-04 141)
f344f58d GITServerHandler.m (Scott 2009-01-04 142) - (void) gatherObjectShasFromC
f344f58d GITServerHandler.m (Scott 2009-01-04 143) {
70befddd GITServerHandler.m (Scott 2009-03-22 144)

//NSLog(@"GATHER COMMI

ad11ac80 GITPackUpload.m

(Scott 2009-03-24 145)

ad11ac80 GITPackUpload.m

(Scott 2009-03-24 146)

NSString *parentSha;

ad11ac80 GITPackUpload.m

(Scott 2009-03-24 147)

GITCommit *commit = [g

ad11ac80 GITPackUpload.m

(Scott 2009-03-24 148)

ad11ac80 GITPackUpload.m

(Scott 2009-03-24 149)

ad11ac80 GITPackUpload.m

(Scott 2009-03-24 150)

56ef2caf GITServerHandler.m (Scott 2009-01-05 151)


56ef2caf GITServerHandler.m (Scott 2009-01-05 152)

//NSLog(@"GATHER COMMI
if(commit) {
[refDict setOb

56ef2caf GITServerHandler.m (Scott 2009-01-05 153)

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.

6.5.2 La reere diotomique


Annoter un chier peut aider si vous savez dj o le problme se situe. Si vous ne savez pas ce
qui a cass le code, il peut y avoir des douzaines, voire des centaines de commits depuis le dernier
tat o votre code fonctionnait, et vous aimeriez certainement excuter git bisect pour laide
quil procure. La commande bisect eectue une recherche par dichotomie dans votre historique
pour vous aider identier aussi vite que possible quel commit a vu le bogue naitre.
161

Chapitre 6 Utilitaires Git

Sco Chacon Pro Git

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 bisect start


$ git bisect bad
$ git bisect good v1.0
Bisecting: 6 revisions left to test after this
[ecb6e1bc347ccecc5f9350d878ce677feb13d3b2] error handling on repo

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 :

$ git bisect good


Bisecting: 3 revisions left to test after this
[b047b02ea83310a70fd603dc8cd7a6cd13d15c04] secure this thing

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 :

$ git bisect bad


Bisecting: 1 revisions left to test after this
[f71ce38690acf49c1f3c9bea38e09d82a5ce6014] drop exceptions table

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 :

$ git bisect good


b047b02ea83310a70fd603dc8cd7a6cd13d15c04 is first bad commit
commit b047b02ea83310a70fd603dc8cd7a6cd13d15c04
Author: PJ Hyett <pjhyett@example.com>

162

Sco Chacon Pro Git

Date:

Section 6.6 Sous-modules

Tue Jan 27 14:48:32 2009 -0800

secure this thing


:040000 040000 40ee3e7821b895e52c1695092db9bdc4c61d1730
f24d3c6ebcfc639b1a3814550e62d60b8e68a8e4 M

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 :

$ git bisect reset

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 :

$ git bisect start HEAD v1.0


$ git bisect run test-error.sh

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

Chapitre 6 Utilitaires Git

Sco Chacon Pro Git

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.

6.6.1 Dmarrer un sous-module


Supposons que vous voulez ajouter la librairie Rack (un serveur dapplication web en Ruby)
votre projet, avec la possibilit de grer vos propres changements celle-ci mais en continuant
de fusionner avec la branche principale. La premire chose que vous devez faire est de cloner le
dpt externe dans votre sous-rpertoire. Ajouter des projets externes comme sous-modules de
votre projet se fait avec la commande git submodule add :

$ git submodule add git://github.com/chneukirchen/rack.git rack


Initialized empty Git repository in /opt/subtest/rack/.git/
remote: Counting objects: 3181, done.
remote: Compressing objects: 100% (1534/1534), done.
remote: Total 3181 (delta 1951), reused 2623 (delta 1603)
Receiving objects: 100% (3181/3181), 675.42 KiB | 422 KiB/s, done.
Resolving deltas: 100% (1951/1951), done.

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:
#

(use "git reset HEAD <file>..." to unstage)

#
#

new file:

.gitmodules

new file:

rack

Premirement, vous remarquerez le chier .gitmodules. Cest un chier de conguration


sauvegardant la liaison entre lURL du projet et le sous-rpertoire local o vous lavez mis :

$ 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

Sco Chacon Pro Git

Section 6.6 Sous-modules

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 :

$ git diff --cached rack


diff --git a/rack b/rack
new file mode 160000
index 0000000..08d709f
--- /dev/null
+++ b/rack
@@ -0,0 +1 @@
+Subproject commit 08d709f78b8c5b0fbeb7821e37fa53e69afcf433

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 :

$ git commit -m 'first commit with submodule rack'


[master 0550271] first commit with submodule rack
2 files changed, 4 insertions(+), 0 deletions(-)
create mode 100644 .gitmodules
create mode 160000 rack

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:

Thu Apr 9 09:03:56 2009 -0700

first commit with submodule rack


$ cd rack/

165

Chapitre 6 Utilitaires Git

Sco Chacon Pro Git

$ git log -1
commit 08d709f78b8c5b0fbeb7821e37fa53e69afcf433
Author: Christian Neukirchen <chneukirchen@gmail.com>
Date:

Wed Mar 25 14:49:04 2009 +0100

Document version change

6.6.2 Cloner un projet avec des sous-modules


Maintenant, vous allez apprendre cloner un projet contenant des sous-modules. and vous
rcuprez un tel projet, vous obtenez les dirents rpertoires qui contiennent les sous-modules,
mais encore aucun des chiers :

$ git clone git://github.com/schacon/myproject.git


Initialized empty Git repository in /opt/myproject/.git/
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (6/6), done.
$ cd myproject
$ ls -l
total 8
-rw-r-r--

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 :

$ git submodule init


Submodule 'rack' (git://github.com/chneukirchen/rack.git) registered for path 'rack'
$ git submodule update
Initialized empty Git repository in /opt/myproject/rack/.git/
remote: Counting objects: 3181, done.
remote: Compressing objects: 100% (1534/1534), done.
remote: Total 3181 (delta 1951), reused 2623 (delta 1603)
Receiving objects: 100% (3181/3181), 675.42 KiB | 173 KiB/s, done.
Resolving deltas: 100% (1951/1951), done.
Submodule path 'rack': checked out '08d709f78b8c5b0fbeb7821e37fa53e69afcf433'

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

Sco Chacon Pro Git

Section 6.6 Sous-modules

$ git merge origin/master


Updating 0550271..85a3eee
Fast forward
rack |

2 +-

1 files changed, 1 insertions(+), 1 deletions(-)


[master*]$ git status
# On branch master
# Changed but not updated:
#

(use "git add <file>..." to update what will be committed)

(use "git checkout -- <file>..." to discard changes in working directory)

#
#

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 :

$ git submodule update


remote: Counting objects: 5, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 1), reused 2 (delta 0)
Unpacking objects: 100% (3/3), done.
From git@github.com:schacon/rack
08d709f..6c5e70b

master

-> origin/master

Submodule path 'rack': checked out '6c5e70b984a60b3cecd395edd5b48a7575bf58e0'

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

Chapitre 6 Utilitaires Git

Sco Chacon Pro Git

$ git submodule update


fatal: reference isnt a tree: 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
Unable to checkout '6c5e70b984a60b3cecd395edd5ba7575bf58e0' in submodule path 'rack'

Vous devez regarder qui a modi le sous-module en dernier :

$ git log -1 rack


commit 85a3eee996800fcfa91e2119372dd4172bf76678
Author: Scott Chacon <schacon@gmail.com>
Date:

Thu Apr 9 09:19:14 2009 -0700

added a submodule reference I will never make public. hahahahaha!

Envoyez-lui un mail pour lui gueuler dessus.

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.

6.6.4 Les problmes avec les sous-modules


Cependant, utiliser des sous-modules ne se droule pas sans accroc. Premirement, vous devez
tre relativement prudent lorsque vous travaillez dans le rpertoire du sous-module. Lorsque vous
excutez git submodule update, cela rcupre une version spcique dun projet, mais pas
lintrieur dune branche. Cela sappelle avoir la tte en lair (detached head), cest--dire que votre
HEAD rfrence directement un commit, pas une rfrence symbolique. Le problme est que vous ne
voulez gnralement pas travailler dans un environnement tte en lair, car il est facile de perdre des
modications dans ces conditions. Si vous faites un premier git submodule update, consignez
des modications dans ce sous-module sans crer vous-mme de branche pour y travailler, et que
vous excutez un nouveau git submodule update depuis le projet parent sans y avoir consign
pendant ce temps, Git crasera vos modications sans vous le dire. Techniquement, vous ne perdrez
pas votre travail, mais vous naurez aucune branche sy rfrant, il sera donc assez dicile de le
rcuprer.
Pour viter ce problme, crez toujours une branche lorsque vous travaillez dans un rpertoire
de sous-module avec git checkout -b work ou une autre commande quivalente. Lorsque
vous merez jour le sous-module une deuxime fois, Git rinitialisera toujours votre travail, mais
vous aurez au moins une rfrence pour y retourner.
168

Sco Chacon Pro Git

Section 6.6 Sous-modules

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
:

$ git checkout -b rack


Switched to a new branch "rack"
$ git submodule add git@github.com:schacon/rack.git rack
Initialized empty Git repository in /opt/myproj/rack/.git/
...
Receiving objects: 100% (3184/3184), 677.42 KiB | 34 KiB/s, done.
Resolving deltas: 100% (1952/1952), done.
$ git commit -am 'added rack submodule'
[rack cc49a69] added rack submodule
2 files changed, 4 insertions(+), 0 deletions(-)
create mode 100644 .gitmodules
create mode 160000 rack
$ git checkout master
Switched to branch "master"
$ git status
# On branch master
# Untracked files:
#

(use "git add <file>..." to include in what will be committed)

#
#

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

Chapitre 6 Utilitaires Git

Sco Chacon Pro Git

remote: Compressing objects: 100% (1465/1465), done.


remote: Total 3184 (delta 1952), reused 2770 (delta 1675)
Receiving objects: 100% (3184/3184), 677.42 KiB | 88 KiB/s, done.
Resolving deltas: 100% (1952/1952), done.

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 :

$ git checkout master


error: Untracked working tree file 'rack/AUTHORS' would be overwritten by merge.

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.

6.7 Fusion de sous-arborescence


Maintenant que vous avez vu les dicults quil peut y avoir avec le systme de sous-module,
voyons une alternative pour rsoudre la mme problmatique. Lorsque Git fusionne, il regarde ce
quil doit fusionner et choisit alors une stratgie de fusion approprie. Si vous fusionnez deux
branches, Git utilise une stratgie rcursive (recursive strategy). Si vous fusionnez plus de deux
branches, Git choisit la stratgie de la pieuvre (octopus strategy). Ces stratgies sont choisies automatiquement car la stratgie rcursive peut grer des problmes comples de fusions trois entres, par exemple, plus dun anctre commun, mais il ne peut grer que deux branches. La fusion de
la pieuvre peut grer plusieurs branches mais il est plus prudent an dviter les conits diciles,
il est donc choisi comme stratgie par dfaut si vous essayez de fusionner plus de deux branches.
Cependant, il existe dautres stratgies que vous pouvez tout aussi bien choisir. Lune delles est
la fusion de sous-arborescence, et vous pouvez lutiliser pour grer la problmatique de sous-projet.
Nous allons donc voir comme grer linclusion de rack comme dans la section prcdente, mais en
utilisant cee fois-ci les fusion de sous-arborescence.
La fusion de sous-arborescence suppose que vous avez deux projets et que lun sidentie
un sous-rpertoire de lautre. Lorsque vous spciez une fusion de sous-arborescence, Git est assez
intellignet pour deviner lequel est un sous-rpertoire de lautre et fusionne en consquence, When
170

Sco Chacon Pro Git

Section 6.7 Fusion de sous-arborescence

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 :

$ git remote add rack_remote git@github.com:schacon/rack.git


$ git fetch rack_remote
warning: no common commits
remote: Counting objects: 3184, done.
remote: Compressing objects: 100% (1465/1465), done.
remote: Total 3184 (delta 1952), reused 2770 (delta 1675)
Receiving objects: 100% (3184/3184), 677.42 KiB | 4 KiB/s, done.
Resolving deltas: 100% (1952/1952), done.
From git@github.com:schacon/rack
* [new branch]

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

$ git checkout -b rack_branch rack_remote/master


Branch rack_branch set up to track remote branch refs/remotes/rack_remote/master.
Switched to a new branch "rack_branch"

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

$ git checkout master


Switched to branch "master"
$ ls
README

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 :

$ git read-tree --prefix=rack/ -u rack_branch

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

Chapitre 6 Utilitaires Git

Sco Chacon Pro Git

le projet Rack, vous pouvez les tirez depuis le dpt principal en commutant dans cee branche et
tirant les modications :

$ git checkout rack_branch


$ git pull

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 :

$ git checkout master


$ git merge --squash -s subtree --no-commit rack_branch
Squash commit -- not updating HEAD
Automatic merge went well; stopped before committing as requested

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 :

$ git diff-tree -p rack_branch

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 :

$ git diff-tree -p rack_remote/master

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.

7.1 Conguration de Git


Comme vous avez pu lentrevoir au chapitre 1, vous pouvez spcier les paramtres de conguration de Git avec la commande git config. Une des premires choses que vous avez faites a
t de paramtrer votre nom et votre adresse e-mail :

$ git config --global user.name "John Doe"


$ git config --global user.email johndoe@example.com

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

Chapitre 7 Personnalisation de Git

Sco Chacon Pro Git

7.1.1 Conguration de base dun client


Les options de conguration reconnues par Git tombent dans deux catgories : ct client et
ct serveur. La grande majorit se situe ct client pour coller vos prfrences personnelles de
travail. Parmi les tonnes doptions disponibles, seules les plus communes ou aectant signicativement la manire de travailler seront traites. De nombreuses options ne savrent utiles que sur des
cas rares et ne seront pas traites. Pour voir la liste des toutes les options que votre version de Git
reconnat, vous pouvez lancer :

$ git config --help

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 :

$ git config --global core.editor emacs

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 :

$ git config --global commit.template $HOME/.gitmessage.txt


$ git commit

174

Sco Chacon Pro Git

Section 7.1 Conguration de Git

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:
#

(use "git reset HEAD <file>..." to unstage)

#
# 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 :

$ git config --global core.pager ''

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 :

$ git config --global user.signingkey <gpg-key-id>

Maintenant, vous pouvez signer vos balises sans devoir spcier votre cl chaque fois la
commande git tag :
175

Chapitre 7 Personnalisation de Git

Sco Chacon Pro Git

$ git tag -s <nom-balise>

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

Si vous positionnez le paramtre help.autocorrect 1, Git lancera automatiquement de


lui-mme la commande si une seule commande ressemblante a t trouve.

7.1.2 Couleurs dans Git


Git peut coloriser ses achages dans votre terminal, ce qui peut faciliter le parcours visuel des
rsultats. Un certain nombre doptions peuvent vous aider rgler la colorisation votre got.
color.ui
Git colorise automatiquement la plupart de ses achages si vous le lui demandez. Vous pouvez
nanmoins vouloir tre plus prcis sur ce que vous souhaitez voir coloris et comment vous le
souhaitez. Pour activer toute la colorisation par dfaut, xez color.ui true :

$ git config --global color.ui true

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

Sco Chacon Pro Git

Section 7.1 Conguration de Git

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 :

$ git config --global color.diff.meta blue black bold

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.

7.1.3 Outils externes de fusion et de dirence


Bien que Git ait une implmentation interne de di que vous avez dj utilise, vous pouvez
slectionner la place un outil externe. Vous pouvez aussi slectionner un outil graphique pour la
fusion et la rsolution de conit au lieu de devoir rsoudre les conits manuellement. Je dmontrerai
le paramtrage avec Perforce Merge Tool (P4Merge) pour visualiser vos dirences et rsoudre vos
fusions parce que cest un outil graphique agrable et gratuit.
Si vous voulez lessayer, P4Merge fonctionne sur tous les systmes dexploitation principaux.
Dans cet exemple, je vais utiliser la forme des chemins usite sur Mac et Linux. Pour Windows, vous
devrez changer /usr/local/bin pour le chemin dexcution dans votre environnement.
Vous pouvez tlcharger P4Merge ici :
http://www.perforce.com/perforce/downloads/component.html
Pour commencer, crez un script dappel externe pour lancer vos commandes. Je vais utiliser
le chemin Mac pour lexcutable ; dans dautres systmes, il rsidera o votre binaire p4merge a
t install. Crez un script enveloppe nomm extMerge qui appelle votre binaire avec tous les
arguments fournis :

177

Chapitre 7 Personnalisation de Git

Sco Chacon Pro Git

$ 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 :

chemin ancien-fichier ancien-hex ancien-mode nouveau-fichier nouveau-hex nouveaumode

Comme seuls les arguments ancien-fichier et nouveau-fichier sont ncessaires,


vous utilisez le script denveloppe pour passer ceux dont vous avez besoin.

$ 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 :

$ sudo chmod +x /usr/local/bin/extMerge


$ sudo chmod +x /usr/local/bin/extDiff

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

$ git config --global merge.tool extMerge


$ git config --global mergetool.extMerge.cmd \
'extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"'
$ git config --global mergetool.trustExitCode false
$ git config --global diff.external extDiff

ou vous pouvez diter votre chier ~/.gitconfig pour y ajouter ces lignes :

[merge]
tool = extMerge
[mergetool "extMerge"]

178

Sco Chacon Pro Git

Section 7.1 Conguration de Git

cmd = extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"


trustExitCode = false
[diff]
external = extDiff

Aprs avoir rgl tout ceci, si vous lancez des commandes de di telles que celle-ci :

$ git diff 32d1776b1^ 32d1776b1

Au lieu dobtenir la sortie du di dans le terminal, Git lance P4Merge, ce qui ressemble la
Figure 7.1.

Figure 7.1: P4Merge.

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

Chapitre 7 Personnalisation de Git

Sco Chacon Pro Git

$ git config --global merge.tool kdiff3

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.

7.1.4 Formatage and espaces blancs


Les problmes de formatage et de blancs font partie des plus subtiles et frustrants que les
dveloppeurs rencontrent lorsquils collaborent, spciquement sur plusieurs plates-formes. Il est
trs facile dintroduire des modications subtiles de blancs lors de soumission de patchs ou dautres
modes de collaboration car les diteurs de textes les insrent silencieusement ou les programmeurs
Windows ajoutent de retour chariot la n des lignes quil modient. Git dispose de quelques options de conguration pour traiter ces problmes.
core.autocrlf
Si vous programmez vous-mme sous Windows ou si vous utilisez un autre systme dexploitation
mais devez travailler avec des personnes travaillant sous Windows, vous rencontrerez un moment
ou un autre des problmes de caractres de n de ligne. Ceci est d au fait que Windows utilise
pour marquer les ns de ligne dans ses chiers un caractre retour chariot (carriage return, CR)
suivi dun caractre saut de ligne (line feed, LF), tandis que Mac et Linux utilisent seulement le
caractre saut de ligne . Cest un cas subtile mais incroyablement ennuyeux de problme gnr
par la collaboration inter plate-forme.
Git peut grer ce cas en convertissant automatiquement les ns de ligne CRLF en LF lorsque
vous validez, et inversement lorsquil extrait des chiers sur votre systme. Vous pouvez activer
cee fonctionnalit au moyen du paramtre core.autcrlf. Si vous avez une machine Windows,
positionnez-le true. Git convertira les ns de ligne de LF en CRLF lorsque vous extrayerez votre
code :

$ git config --global core.autocrlf true

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 :

$ git config --global 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

Sco Chacon Pro Git

Section 7.1 Conguration de Git

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 :

$ git config --global core.autocrlf 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 config --global core.whitespace \


trailing-space,space-before-tab,indent-with-non-tab

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 :

$ git apply --whitespace=warn <patch>

Ou vous pouvez indiquer Git dessayer de corriger automatiquement le problme avant


dappliquer le patch :

$ git apply --whitespace=fix <patch>

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

Chapitre 7 Personnalisation de Git

Sco Chacon Pro Git

7.1.5 Conguration du serveur


Il ny a pas autant doptions de conguration de Git ct serveur, mais en voici quelques unes
intressantes dont il est utile de prendre note.
receive.fsObjects
Par dfaut, Git ne vrie pas la cohrence entre les objets quon lui pousse. Bien que Git puisse
vrier que chaque objet correspond bien sa somme de contrle et pointe vers des objets valides,
il ne le fait pas par dfaut sur chaque pousse. Cest une opration relativement lourde qui peut
normment allonger les pousses selon la taille du dpt ou de la pousse. Si vous voulez que
Git vrie la cohrence des objets chaque pousse, vous pouvez le forcer en xant le paramtre
receive.fsckObjects true :

$ git config --system receive.fsckObjects true

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 :

$ git config --system receive.denyNonFastForwards true

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 :

$ git config --system 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

Sco Chacon Pro Git

Section 7.2 Aributs Git

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.

7.2 Attributs Git


Certains de ces rglages peuvent aussi sappliquer sur un chemin, de telle sorte que Git ne
les applique que sur un sous-rpertoire ou un sous-ensemble de chiers. Ces rglages par chemin
sont appels aributs Git et sont dnis soit dans une chier .gitattributes dans un rpertoire (normalement la racine du projet), soit dans un chier .git/info/attributes si vous
ne souhaitez pas que la chier de description des aributs fasse partie du projet.
Les aributs permeent de spcier des stratgies de fusion direntes pour certains chiers
ou rpertoires dans votre projet, dindiquer Git la manire de calculer les dirences pour certains
chiers non-texte, ou de faire ltrer Git le contenu avant quil ne soit valid ou extrait. Dans ce
chapitre, nous traiterons certains aributs applicables aux chemins et dtaillerons quelques exemples de leur utilisation en pratique.

7.2.1 Fiiers binaires


Un des trucs malins auxquels les aributs Git sont utiliss est dindiquer Git quels chiers
sont binaires (dans les cas o il ne pourrait pas le deviner par lui-mme) et de lui donner les instructions spciques pour les traiter. Par exemple, certains chiers peuvent tre gnrs par machine et
impossible traiter par di, tandis que pour certains autres chiers binaires, les dirences peuvent
tre calcules. Nous dtaillerons comment indiquer Git lun et lautre.
Identication des iers binaires
Certains chiers ressemblent des chiers texte mais doivent en tout tat de cause tre traits
comme des chiers binaires. Par exemple, les projets Xcode sous Mac contiennent un chier nissant
en .pbxproj, qui est en fait un jeu de donnes JSON (format de donnes en texte javascript)
enregistr par lapplication EDI pour y sauver les rglages entre autres de compilation. Bien que ce
soit techniquement un chier texte en ASCII, il ny a aucun intrt le grer comme tel parce que
cest en fait une mini base de donnes. Il est impossible de fusionner les contenus si deux utilisateurs
le modient et les calculs de dirence par dfaut sont inutiles. Ce chier nest destin qu tre
manipul par un programme En rsum, ce chier doit tre considr comme un chier binaire.
Pour indiquer Git de traiter tous les chiers pbxproj comme binaires, ajoutez la ligne suivante votre chier .gitattributes :

*.pbxproj -crlf -diff

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

Chapitre 7 Personnalisation de Git

Sco Chacon Pro Git

Comparaison de iers binaires


Dans la branche 1.6 de Git, vous pouvez utiliser la fonctionnalit des aributs Git pour eectivement comparer les chiers binaires. Pour ce faire, indiquez Git comment convertir vos donnes
binaires en format texte qui peut tre compar via un di normal.
Comme cest une fonctionnalit plutt cool et peu connue, nous allons en voir quelques exemples. Premirement, nous utiliserons cee technique pour rsoudre un des problmes les plus
ennuyeux de lhumanit : grer en contrle de version les document Word. Tout le monde convient
que Word est lditeur de texte le plus horrible qui existe, mais bizarrement, tout le monde persiste
lutiliser. Si vous voulez grer en version des documents Word, vous pouvez les coller dans un
dpt Git et les valider de temps autre. Mais quest-ce que a vous apporte ? Si vous lancez git
diff normalement, vous verrez quelque chose comme :

$ 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 :

$ git config diff.word.textconv strings

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

Sco Chacon Pro Git

Section 7.2 Aributs Git

@@ -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 :

$ echo '*.png diff=exif' >> .gitattributes


$ git config diff.exif.textconv exiftool

Si vous remplacez une image dans votre projet et lancez git diff, vous verrez ceci :

diff --git a/image.png b/image.png


index 88839c4..4afcb7c 100644
--- a/image.png
+++ b/image.png
@@ -1,12 +1,12 @@
ExifTool Version Number

: 7.74

-File Size

: 70 kB

-File Modification Date/Time

: 2009:04:21 07:02:45-07:00

+File Size

: 94 kB

+File Modification Date/Time

: 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

: RGB with Alpha

Vous pouvez raliser rapidement que la taille du chier et les dimensions des images ont toutes
deux chang.
185

Chapitre 7 Personnalisation de Git

Sco Chacon Pro Git

7.2.2 Expansion des mots-cls


Lexpansion de mots-cls dans le style de CVS ou de SVN est souvent une fonctionnalit demande par les dveloppeurs qui y sont habitus. Le problme principal de ce systme avec Git et
que vous ne pouvez pas modier un chier avec linformation concernant le commit aprs la validation parce que Git calcule justement la somme de contrle sur son contenu. Cependant, vous pouvez
injecter des informations textuelles dans un chier au moment o il est extrait et les retirer avant
quil ne soit ajout une validation. Les aributs Git vous fournissent deux manires de le faire.
Premirement, vous pouvez injecter automatiquement la somme de contrle SHA-1 dun blob
dans un champ $Id$ dun chier. Si vous positionnez cet aribut pour un chier ou un ensemble
de chiers, la prochaine fois que vous extrairez cee branche, Git remplacera chaque champ avec
le SHA-1 du blob. Il est noter que ce nest pas le SHA du commit mais celui du blob lui-mme :

$ echo '*.txt ident' >> .gitattributes


$ echo '$Id$' > test.txt

la prochaine extraction de ce chier, Git injecte le SHA du blob :

$ 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.

Figure 7.2: Le ltre smudge est lanc lors dune extraction.

186

Sco Chacon Pro Git

Section 7.2 Aributs Git

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 :

$ git config --global filter.indent.clean indent


$ git config --global filter.indent.smudge cat

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

Chapitre 7 Personnalisation de Git

Sco Chacon Pro Git

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 :

$ git config filter.dater.smudge expand_date


$ git config filter.dater.clean 'perl -pe "s/\\\$Date[^\\\$]*\\\$/\\\$Date\\\$/"'

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 :

$ echo '# $Date$' > date_test.txt


$ echo 'date*.txt filter=dater' >> .gitattributes

Si vous validez ces modications et extrayez le chier nouveau, vous remarquez le mot-cl
correctement substitu :

$ git add date_test.txt .gitattributes


$ git commit -m "Testing date expansion in Git"
$ rm date_test.txt
$ git checkout date_test.txt
$ cat date_test.txt
# $Date: Tue Apr 21 07:26:52 2009 -0700$

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.

7.2.3 Export dun dpt


Les donnes daribut Git permeent aussi de faire des choses intressantes quand vous exportez une archive du projet.
export-ignore
Vous pouvez dire Git de ne pas exporter certains chiers ou rpertoires lors de la gnration
darchive. Sil y a un sous-rpertoire ou un chier que vous ne souhaitez pas inclure dans le chier
archive mais que vous souhaitez extraire dans votre projet, vous pouvez indiquer ce chier via
laribut export-ignore.
Par exemple, disons que vous avez des chiers de test dans le sous-rpertoire test/ et que ce
nest pas raisonnable de les inclure dans larchive dexport de votre projet. Vous pouvez ajouter la
ligne suivante dans votre chier daribut Git :

188

Sco Chacon Pro Git

Section 7.2 Aributs Git

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 :

$ echo 'Last commit date: $Format:%cd$' > LAST_COMMIT


$ echo "LAST_COMMIT export-subst" >> .gitattributes
$ git add LAST_COMMIT .gitattributes
$ git commit -am 'adding LAST_COMMIT file for archives'

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$

7.2.4 Stratgies de fusion


Vous pouvez aussi utiliser les aributs Git pour indiquer Git dutiliser des stratgies de fusion
direncies pour des chiers spciques dans votre projet. Une option trs utile est dindiquer
Git de ne pas essayer de fusionner des chiers spciques quand ils rencontrent des conits mais
plutt dutiliser prioritairement votre version du chier.
Cest trs utile si une branche de votre projet a diverg ou sest spcialise, mais que vous
souhaitez pouvoir fusionner les modications quelle porte et vous voulez ignorer certains chiers.
Supposons que vous avez un chier de paramtres de base de donnes appel database.xml dirent
sur deux branches et vous voulez les fusionner sans corrompre le chier de base de donnes. Vous
pouvez dclarer un aribut comme ceci :

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

Chapitre 7 Personnalisation de Git

Sco Chacon Pro Git

$ git merge topic


Auto-merging database.xml
Merge made by recursive.

Dans ce cas, database.xml reste dans ltat dorigine, quel quil soit.

7.3 Croets Git


Comme de nombreux autres systmes de gestion de version, Git dispose dun moyen de lancer
des scripts personnaliss quand certaines actions importantes ont lieu. Il y a deux groupes de crochets : ceux ct client et ceux ct serveur. Les crochets ct client concernent les oprations de
client telles que la validation et la fusion. Les crochets ct serveur concernent les oprations de
serveur Git telles que la rception de commits. Vous pouvez utiliser ces crochets pour toutes sortes
de raisons dont nous allons dtailler quelques unes.

7.3.1 Installation dun croet


Les crochets sont tous stocks dans le sous-rpertoire hooks du rpertoire Git. Dans la plupart des projets, cest .git/hooks. Par dfaut, Git popule ce rpertoire avec quelques scripts
dexemple dj utiles par eux-mmes ; mais ils servent aussi de documentation sur les paramtres
de chaque script. Tous les exemples sont des scripts shell avec un peu de Perl mais nimporte quel
script excutable nomm correctement fonctionnera. Vous pouvez les crire en Ruby ou Python ou
ce que vous voudrez. Pour les versions de Git postrieures 1.6, ces chiers crochet dexemple se
terminent en .sample et il faudra les renommer. Pour les versions de Git antrieures 1.6, les
chiers dexemple sont nomms correctement mais ne sont pas excutables.
Pour activer un script de crochet, placez un chier dans le sous-rpertoire hook de votre rpertoire Git, nomm correctement et excutable. partir de ce moment, il devrait tre appel. Abordons
donc les noms de chiers hooks les plus importants.

7.3.2 Croets ct client


Il y a de nombreux crochets ct client. Ce chapitre les classe entre crochets de traitement de
validation, scripts de traitement par e-mail et le reste des scripts ct client.
Croets de traitement de validation
Les quatre premiers crochets ont trait au processus de validation. Le crochet pre-commit
est lanc en premier, avant mme que vous ne saisissiez le message de validation. Il est utilis pour
inspecter linstantan qui est sur le point dtre valid, pour vrier si vous avez oubli quelque
chose, pour sassurer que les tests passent ou pour examiner ce que vous souhaitez inspecter dans
le code. Un code de sortie non nul de ce crochet annule la validation, bien que vous puissiez le
contourner avec git commit --no-verify. Vous pouvez raliser des actions telles quune
vrication de style (en utilisant lint ou un quivalent), dabsence de blancs en n de ligne (le crochet
par dfaut fait exactement cela) ou de documentation des nouvelles mthodes.
Le crochet prepare-commit-msg est appel avant que lditeur de message de validation
ne soit lanc aprs que le message par dfaut a t cr. Il vous permet dditer le message par
190

Sco Chacon Pro Git

Section 7.3 Crochets Git

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

Chapitre 7 Personnalisation de Git

Sco Chacon Pro Git

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.

7.3.3 Croets ct serveur


En complment des crochets ct client, vous pouvez utiliser comme administrateur systme
quelques crochets ct serveur pour appliquer quasiment toutes les rgles de votre projet. Ces scripts
sexcutent avant et aprs chaque pousses sur le serveur. Les crochets pre peuvent rendre un code
derreur non nul tout moment pour rejeter la pousse et acher un message derreur au client.
Vous pouvez mere en place des rgles aussi complexes que ncessaire.
pre-receive et post-receive
Le premier script lanc lors de la gestion dune pousse depuis un client est pre-receive.
Il accepte une liste de rfrences lues sur stdin. Sil sort avec un code derreur non nul, aucune nest
accepte. Vous pouvez utiliser ce crochet pour raliser des tests tels que sassurer que toutes les
rfrences mises jour le sont en avance rapide ou pour sassurer que lutilisateur dispose bien des
droits de cration, pousse, destruction ou de lecture des mises jour pour tous les chiers quil
cherche mere jour dans cee pousse.
Le crochet post-receive est lanc aprs lexcution complte du processus et peut tre
utilis pour mere jour dautres services ou pour notier des utilisateurs. Il accepte les mme
donnes sur stdin que pre-receive. Il peut par exemple envoyer un e-mail une liste de diusion, notier un serveur dintgration continue ou mere jour un systme de suivi de tickets. Il
peut aussi analyser les messages de validation la recherche dordres de mise jour de ltat des
tickets. Ce script ne peut pas arrter le processus de pousse mais le client nest pas dconnect tant
quil na pas termin. Il faut donc tre prudent ne pas essayer de lui faire raliser des actions qui
peuvent durer longtemps.
update
Le script update est trs similaire au script pre-receive, la dirence quil est lanc
une fois par branche qui doit tre modie lors de la pousse. Si la pousse sapplique plusieurs
branches, pre-receive nest lanc quune fois, tandis quupdate est lanc une fois par branche
impacte. Au lieu de lire partir de stdin, ce script accepte trois arguments : le nom de la rfrence
(branche), le SHA-1 du commit point par la rfrence avant la pousse et le SHA-1 que lutilisateur
est en train de pousser. Si le script update se termine avec un code derreur non nul, seule la
rfrence est rejete. Les autres rfrences pourront tre mises jour.
192

Sco Chacon Pro Git

Section 7.4 Exemple de politique gre par Git

7.4 Exemple de politique gre par Git


Dans ce chapitre, nous allons utiliser ce que nous venons dapprendre pour installer une gestion Git qui vrie la prsence dun format personnalis de message de validation, nautorise que
les pousses en avance rapide et autorise seulement certains utilisateurs modier certains sousrpertoires dans un projet. Nous construirons des scripts client pour informer les dveloppeurs que
leurs pousses vont tre rejetes et des scripts sur le serveur pour mere eectivement en place ces
rgles.
Jai utilis Ruby pour les crire, dabord parce que cest mon langage de script favori, ensuite
parce que je pense que cest le langage de script qui sapparente le plus du pseudo-code. Ainsi, il
devrait tre simple de suivre grossirement le code mme sans connatre le langage Ruby. Cependant, tout langage peut tre utilis. Tous les scripts dexemple distribus avec Git sont soit en Perl
soit en Bash, ce qui donne de nombreux autres exemples de crochets dans ces langages.

7.4.1 Croets ct serveur


Toutes les actions ct serveur seront contenues dans le chier update dans le rpertoire
hooks. Le chier update sexcute une fois par branche pousse et accepte comme paramtre
la rfrence sur laquelle on pousse, lancienne rvision de la branche et la nouvelle rvision de la
branche. Vous pouvez aussi avoir accs lutilisateur qui pousse si la pousse est ralise par SSH.
Si vous avez permis tout le monde de se connecter avec un utilisateur unique (comme git )
avec une authentication clef publique, il vous faudra fournir cet utilisateur une enveloppe
de shell qui dterminera lidentit de lutilisateur partir de sa clef publique et positionnera une
variable denvironnement spciant cee identit. Ici, je considre que la variable denvironnement
$USER indique lutilisateur connect, donc le script update commence par rassembler toutes les
informations ncessaires :

#!/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

Chapitre 7 Personnalisation de Git

Sco Chacon Pro Git

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 :

$ git rev-list 538c33..d14fc7


d14fc7c847ab946ec39590d87783c69b031bdfb7
9f585da4401b0a3999e84113824d15245c13f0be
234071a1be950e2a8d078e6141f5cd20c1e61ad3
dfa04c9ef3d5197182f13fb5b9b1fb7717d2222a
17716ec0f1ff5c77eff40b7fe912f9f6cfd0e475

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:

$ git cat-file commit ca82a6


tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf
parent 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
author Scott Chacon <schacon@gmail.com> 1205815931 -0700
committer Scott Chacon <schacon@gmail.com> 1240030591 -0700
changed the version number

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 :

$ git cat-file commit ca82a6 | sed '1,/^$/d'


changed the version number

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 :

$regex = /\[ref: (\d+)\]/


# vrification du format des messages de validation
def verif_format_message
revs_manquees = `git rev-list #{$anciennerev}..#{$nouvellerev}`.split("\n")
revs_manquees.each do |rev|
message = `git cat-file commit #{rev} | sed '1,/^$/d'`
if !$regex.match(message)

194

Sco Chacon Pro Git

Section 7.4 Exemple de politique gre par Git

puts "[REGLE] Le message de validation ne suit pas le format"


exit 1
end
end
end
verif_format_message

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

Chapitre 7 Personnalisation de Git

Sco Chacon Pro Git

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.

$ git log -1 --name-only --pretty=format:'' 9f585d


README
lib/test.rb

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 :

# permission certains utilisateurs de modifier certains sous-rpertoires du projet


def verif_perms_repertoire
acces = get_acl_access_data('acl')
# verifier si quelqu'un chercher pousser o il n'a pas le droit
nouveaux_commits = `git rev-list #{$anciennerev}..#{$nouvellerev}`.split("\n")
nouveaux_commits.each do |rev|
fichiers_modifies = `git log -1 --name-only --pretty=format:'' #{rev}`.split("\n")
fichiers_modifies.each do |chemin|
next if chemin.size == 0
acces_permis = false
acces[$utilisateur].each do |chemin_acces|
if !chemin_acces

# l'utilisateur a un accs complet

|| (chemin.index(chemin_acces) == 0) # acces ce chemin

196

Sco Chacon Pro Git

Section 7.4 Exemple de politique gre par Git

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 :

# Forcer les pousses qu'en avance rapide


def verif_avance_rapide
refs_manquees = `git rev-list #{$nouvellerev}..#{$anciennerev}`
nb_refs_manquees = refs_manquees.split("\n").size
if nb_refs_manquees > 0
puts "[REGLE] Pousse en avance rapide uniquement"
exit 1
end
end
verif_avance_rapide

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

Chapitre 7 Personnalisation de Git

Sco Chacon Pro Git

$ git push -f origin master


Counting objects: 5, done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 323 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
Vrification des rgles...
(refs/heads/master) (8338c5) (c5b616)
[REGLE] Pousse en avance rapide uniquement
error: hooks/update exited with error code 1
error: hook declined to update refs/heads/master
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 plusieurs point relever ici. Premirement, une ligne indique lendroit o le crochet est
appel.

Vrification des rgles...


(refs/heads/master) (fb8c72) (c56860)

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.

[REGLE] Pousse en avance rapide uniquement


error: hooks/update exited with error code 1
error: hook declined to update refs/heads/master

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 :

[REGLE] Le message de validation ne suit pas le format

198

Sco Chacon Pro Git

Section 7.4 Exemple de politique gre par Git

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

[ACL] Vous n'avez pas le droit de pousser sur lib/test.rb

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.

7.4.2 Croets ct client


Le problme de cee approche, ce sont les plaintes des utilisateurs qui rsulteront invitablement des checs de leurs pousses. Leur frustration et leur confusion devant le rejet la dernire
minute dun travail minutieux est tout fait comprhensible. De plus, la correction ncessitera une
modication de leur historique, ce qui nest pas une partie de plaisir.
Pour viter ce scnario, il faut pouvoir fournir aux utilisateurs des crochets ct client qui leur
permeront de vrier que leurs validations seront eectivement acceptes par le serveur. Ainsi,
ils pourront corriger les problmes avant de valider et avant que ces dicults ne deviennent des
casse-ttes. Ces scripts ntant pas diuss lors du clonage du projet, il vous faudra les distribuer
dune autre manire, puis indiquer aux utilisateurs de les copier dans leur rpertoire .git/hooks
et de les rendre excutables. Vous pouvez distribuer ces crochets au sein du projet ou dans un projet
annexe mais il ny a aucun moyen de les mere en place automatiquement.
Premirement, pour viter le rejet du serveur au motif dun mauvais format du message de
validation, il faut vrier celui-ci avant que chaque commit ne soit enregistr. Pour ce faire, utilisons
le crochet commit-msg. En lisant le message partir du chier pass en premier argument et en
le comparant au format aendu, on peut forcer Git abandonner la validation en cas dabsence de
correspondance :

#!/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

Avec ce chier excutable et sa place dans .git/hooks/commit-msg, si une validation


avec un message incorrect est tente, voici le rsultat :

$ git commit -am 'test'


[REGLE] Le message de validation ne suit pas le format

199

Chapitre 7 Personnalisation de Git

Sco Chacon Pro Git

La validation na pas abouti. Nanmoins, si le message contient la bonne forme, Git accepte la
validation :

$ git commit -am 'test [ref: 132]'


[master e05c914] test [ref: 132]
1 files changed, 1 insertions(+), 0 deletions(-)

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']

# [ insrer la fonction acl_access_data method ci-dessus ]


# Ne permet qu' certains utilisateurs de modifier certains sous-rpertoires
def verif_perms_repertoire
acces = get_acl_access_data('.git/acl')
fichiers_modifies = `git diff-index --cached --name-only HEAD`.split("\n")
fichiers_modifies.each do |chemin|
next if chemin.size == 0
acces_permis = false
acces[$utilisateur].each do |chemin_acces|
if !chemin_acces || (chemin.index(chemin_acces) == 0)
acces_permis = true
end
if !acces_permis
puts "[ACL] Vous n'avez pas le droit de pousser sur #{path}"
exit 1
end
end
end
verif_perms_repertoire

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

Sco Chacon Pro Git

Section 7.4 Exemple de politique gre par Git

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

fichiers_modifies = `git log -1 --name-only --pretty=format:'' #{ref}`

on utilise

fichiers_modifies = `git diff-index --cached --name-only HEAD`

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

Chapitre 7 Personnalisation de Git

Sco Chacon Pro Git

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 :

git rev-list ^#{sha}^@ refs/remotes/#{ref_distante}

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

Git et les autres systmes


Le monde nest pas parfait. Habituellement, vous ne pouvez pas basculer immdiatement sous
Git tous les projets que vous pourriez rencontrer. elques fois, vous tes bloqu sur un projet
utilisant un autre VCS et trs souvent ce systme savre tre Subversion. Dans la premire partie
de ce chapitre, nous traiterons de git svn, la passerelle bidirectionnelle de Git pour Subversion.
un moment, vous voudrez convertir votre projet Git. La seconde partie de ce chapitre traite
la migration de votre projet dans Git : depuis Subversion, puis depuis Perforce et enn par un script
dimport personnalis pour les cas non-standards.

8.1 Git et Subversion


Aujourdhui, la majorit des projets de dveloppement libre et un grand nombre de projets dans
les socits utilisent Subversion pour grer leur code source. Cest le VCS libre le plus populaire
depuis une bonne dcennie. Il est aussi trs similaire CVS qui a t le grand chef des gestionnaires
de source avant lui.
Une des grandes fonctionnalits de Git est sa passerelle vers subversion, git svn. Cet outil
vous permet dutiliser Git comme un client valide dun serveur Subversion pour que vous puissiez
utiliser les capacits de Git en local puis poussez sur le serveur Subversion comme si vous utilisiez
Subversion localement. Cela signie que vous pouvez raliser localement les embranchements et les
fusions, utiliser lindex, utiliser le rebasage et la slection de commits, etc, tandis que vos collaborateurs continuent de travailler avec leurs mthodes ancestrales et obscures. Cest une bonne manire
dintroduire Git dans un environnement professionnel et daider vos collgues dveloppeurs devenir plus ecaces tandis que vous ferez pression pour une modication de linfrastructure vers
lutilisation massive de Git. La passerelle Subversion nest que la premire dose vers la drogue du
monde des DVCS.

8.1.1 git svn


La commande de base dans Git pour toutes les commandes de passerelle est git svn. Vous
prposerez tout avec cee paire de mots. Les possibilits tant nombreuses, nous traiterons des plus
communes pendant que nous dtaillerons quelques petits modes de gestion.
Il est important de noter que lorsque vous utilisez git svn, vous interagissez avec Subversion
qui est un systme bien moins sophistiqu que Git. Bien que vous puissiez simplement raliser des
branches locales et les fusionner, il est gnralement conseill de conserver votre historique le plus
203

Chapitre 8 Git et les autres systmes

Sco Chacon Pro Git

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.

$ svnsync init file:///tmp/test-svn http://progit-example.googlecode.com/svn/

Cela initialise les proprits ncessaires la synchronisation. Vous pouvez ensuite cloner le
code en lanant

$ svnsync sync file:///tmp/test-svn


Committed revision 1.
Copied properties for revision 1.
Committed revision 2.
Copied properties for revision 2.
Committed revision 3.
...

204

Sco Chacon Pro Git

Section 8.1 Git et Subversion

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 :

$ git svn clone file:///tmp/test-svn -T trunk -b branches -t tags


Initialized empty Git repository in /Users/schacon/projects/testsvnsync/svn/.git/
r1 = b4e387bc68740b5af56c2a5faf4003ae42bd135c (trunk)
A

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 :

$ git svn clone file:///tmp/test-svn -s

prsent, vous disposez dun dpt Git valide qui a import vos branches et vos balises :

$ git branch -a
* master

205

Chapitre 8 Git et les autres systmes

Sco Chacon Pro Git

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

Pour un dpt Git normal, cela ressemble plus ceci :

$ 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.

8.1.4 Valider en retour sur le serveur Subversion


Comme vous disposez dun dpt en tat de marche, vous pouvez commencer travailler sur
le projet et pousser vos commits en utilisant ecacement Git comme client SVN. Si vous ditez un
des chiers et le validez, vous crez un commit qui existe localement dans Git mais qui nexiste pas
sur le serveur Subversion :

206

Sco Chacon Pro Git

Section 8.1 Git et Subversion

$ git commit -am 'Ajout d'instructions pour git-svn dans LISEZMOI'


[master 97031e5] Ajout d'instructions pour git-svn dans LISEZMOI
1 files changed, 1 insertions(+), 1 deletions(-)

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 :

$ git svn dcommit


Committing to file:///tmp/test-svn/trunk ...
M

README.txt

Committed r79
M

README.txt

r79 = 938b1a547c2cc92033b74d32030e86468294a5c8 (trunk)


No changes between current HEAD and refs/remotes/trunk
Resetting to the latest refs/remotes/trunk

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:

Sat May 2 22:06:44 2009 +0000

Ajout d'instructions pour git-svn dans LISEZMOI


git-svn-id: file:///tmp/test-svn/trunk@79 4c93b258-373f-11de-be05-5f7a86268029

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.

8.1.5 Tirer des modications


and vous travaillez avec dautres dveloppeurs, il arrive certains moments que ce quun
dveloppeur a pouss provoque un conit lorsquun autre voudra pousser son tour. Cee modication sera rejete jusqu ce quelle soit fusionne. Dans git svn, cela ressemble ceci :
207

Chapitre 8 Git et les autres systmes

Sco Chacon Pro Git

$ git svn dcommit


Committing to file:///tmp/test-svn/trunk ...
Merge conflict during commit: Your file or directory 'README.txt' is probably \
out-of-date: resource out of date; try updating at /Users/schacon/libexec/git-\
core/git-svn line 482

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 :

$ git svn rebase


M

README.txt

r80 = ff829ab914e8775c7c025d741beb3d523ee30bc4 (trunk)


First, rewinding head to replay your work on top of it...
Applying: first user change

prsent, tout votre travail se trouve au del de lhistorique du serveur et vous pouvez eectivement raliser un dcommit :

$ git svn dcommit


Committing to file:///tmp/test-svn/trunk ...
M

README.txt

Committed r81
M

README.txt

r81 = 456cbe6337abe49154db70106d1836bc1332deed (trunk)


No changes between current HEAD and refs/remotes/trunk
Resetting to the latest refs/remotes/trunk

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 :

$ git svn dcommit


Committing to file:///tmp/test-svn/trunk ...
M

configure.ac

Committed r84
M

autogen.sh

r83 = 8aa54a74d452f82eee10076ab2584c1fc424853b (trunk)


M

configure.ac

r84 = cdbac939211ccb18aa744e581e46563af5d962d0 (trunk)


W: d2f23b80f67aaaa1f6f5aaef48fce3263ac71a92 and refs/remotes/trunk differ, \
using rebase:
:100755 100755 efa5a59965fbbb5b2b0a12890f1b351bb5493c18 \
015e4c98c482f0fa71e4d5434338014530b37fa6 M

208

autogen.sh

Sco Chacon Pro Git

Section 8.1 Git et Subversion

First, rewinding head to replay your work on top of it...


Nothing to do.

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.

$ git svn rebase


M

generate_descriptor_proto.sh

r82 = bd16df9173e424c6f52c337ab6efa7f7643282f1 (trunk)


First, rewinding head to replay your work on top of it...
Fast-forwarded master to refs/remotes/trunk.

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.

8.1.6 Le problme avec les branes Git


Aprs vous tre habitu la manire de faire avec Git, vous souhaiterez srement crer des
branches thmatiques, travailler dessus, puis les fusionner. Si vous poussez sur un serveur Subversion via git svn, vous souhaiterez chaque fois rebaser votre travail sur une branche unique au lieu
de fusionner les branches ensemble. La raison principale en est que Subversion gre un historique
linaire et ne gre pas les fusions comme Git y excelle. De ce fait, git svn suit seulement le premier
parent lorsquil convertit les instantans en commits Subversion.
Supposons que votre historique ressemble ce qui suit. Vous avez cr une branche experience, avez ralis deux validations puis les avez fusionnes dans master. Lors du dcommit, vous
voyez le rsultat suivant :

$ git svn dcommit


Committing to file:///tmp/test-svn/trunk ...
M

CHANGES.txt

Committed r85
M

CHANGES.txt

r85 = 4bfebeec434d156c36f2bcd18f4e3d97dc3269a2 (trunk)


No changes between current HEAD and refs/remotes/trunk

209

Chapitre 8 Git et les autres systmes

Sco Chacon Pro Git

Resetting to the latest refs/remotes/trunk


COPYING.txt: locally modified
INSTALL.txt: locally modified
M

COPYING.txt

INSTALL.txt

Committed r86
M

INSTALL.txt

COPYING.txt

r86 = 2647f6b86ccfcaad4ec58c520e369ec81f7c283c (trunk)


No changes between current HEAD and refs/remotes/trunk
Resetting to the latest refs/remotes/trunk

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.

8.1.7 Les embranements dans Subversion


La gestion de branches dans Subversion na rien voir avec celle de Git. vitez de lutiliser
tant que possible. Cependant vous pouvez crer des branches et valider dessus dans Subversion en
utilisant git svn.
Crer une nouvelle brane SVN
Pour crer une nouvelle branche dans Subversion, vous pouvez utiliser la commande git svn
branch [nom de la branche] :

Copying file:///tmp/test-svn/trunk at r87 to file:///tmp/test-svn/branches/opera...


Found possible branch point: file:///tmp/test-svn/trunk => \
file:///tmp/test-svn/branches/opera, 87
Found branch parent: (opera) 1f6bfe471083cbca06ac8d4176f7ad4de0d62e5f
Following parent with do_switch
Successfully followed parent
r89 = 9b6fe0b90c5c9adf9165f700897518dbc54a7cbf (opera)

Cela est quivalent la commande Subversion svn copy trunk branches/opera et


ralise lopration sur le serveur Subversion. Remarquez que cee commande ne vous bascule pas
sur cee branche ; si vous validez, le commit sappliquera trunk et non la branche opera.

8.1.8 Basculer de brane active


Git devine la branche cible des dcommits en se rfrant au sommet des branches Subversion
dans votre historique vous ne devriez en avoir quun et celui-ci devrait tre le dernier possdant
un git-svn-id dans lhistorique actuel de votre branche.
210

Sco Chacon Pro Git

Section 8.1 Git et Subversion

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

$ git branch opera remotes/opera

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.

8.1.9 Les commandes Subversion


La bote outil git svn fournit des commandes de nature faciliter la transition vers Git
en mimant certaines commandes disponibles avec Subversion. Voici quelques commandes qui vous
fournissent les mmes services que Subversion.
Lhistorique dans le style Subversion
Si vous tes habitu Subversion, vous pouvez lancer git svn log pour visualiser votre
historique dans un format SVN :

$ git svn log


-----------------------------------------------------------------------r87 | schacon | 2009-05-02 16:07:37 -0700 (Sat, 02 May 2009) | 2 lines
autogen change
-----------------------------------------------------------------------r86 | schacon | 2009-05-02 16:00:21 -0700 (Sat, 02 May 2009) | 2 lines
Merge branch 'experiment'

211

Chapitre 8 Git et les autres systmes

Sco Chacon Pro Git

-----------------------------------------------------------------------r85 | schacon | 2009-05-02 16:00:09 -0700 (Sat, 02 May 2009) | 2 lines


updated the changelog

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 :

$ git svn blame README.txt


2

temporal Protocol Buffers - Google's data interchange format

temporal Copyright 2008 Google Inc.

temporal http://code.google.com/apis/protocolbuffers/

temporal

22
22
2
79
78

temporal C++ Installation - Unix


temporal =======================
temporal
schacon Committing in git-svn.
schacon

temporal To build and install the C++ Protocol Buffer runtime and the Protocol

temporal Buffer compiler (protoc) execute the following:

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 :

$ git svn info


Path: .
URL: https://schacon-test.googlecode.com/svn/trunk
Repository Root: https://schacon-test.googlecode.com/svn
Repository UUID: 4c93b258-373f-11de-be05-5f7a86268029
Revision: 87
Node Kind: directory
Schedule: normal

212

Sco Chacon Pro Git

Section 8.1 Git et Subversion

Last Changed Author: schacon


Last Changed Rev: 87
Last Changed Date: 2009-05-02 16:07:37 -0700 (Sat, 02 May 2009)

Comme blame et log, cee commande travaille hors connexion et nest jour qu la dernire
date laquelle vous avez communiqu avec le serveur Subversion.

Ignorer ce que Subversion ignore


Si vous clonez un dpt Subversion contenant des proprits svn:ignore, vous souhaiterez
srement paramtrer les chiers .gitignore en correspondance pour vous viter de valider accidentellement des chiers interdits. git svn dispose de deux commandes pour le faire.
La premire est git svn create-ignore qui cre automatiquement pour vous les chiers
.gitignore prts pour linclusion dans votre prochaine validation.
La seconde commande est git svn show-ignore qui ache sur stdout les lignes ncessaires un chier .gitignore quil sura de rediriger dans votre chier dexclusion de projet :

$ git svn show-ignore > .git/info/exclude

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.1.10 Rsum sur Git-Svn


Les outils git svn sont utiles si vous tes bloqu avec un serveur Subversion pour le moment ou si vous devez travailler dans un environnement de dveloppement qui ncessite un serveur
Subversion. Il faut cependant les considrer comme une version tronque de Git ou vous pourriez
rencontrer des problmes de conversion synonymes de troubles pour vous et vos collaborateurs.
Pour viter tout problme, essayez de suivre les principes suivants :
Garder un historique Git linaire qui ne contient pas de commits de fusion issus de git
merge. Rebasez tout travail ralis en dehors de la branche principale sur celle-ci ; ne la
fusionnez pas.
Ne meez pas en place et ne travaillez pas en parallle sur un serveur Git. Si ncessaire,
montez-en un pour acclrer les clones pour de nouveaux dveloppeurs mais ny poussez
rien qui nait dj une entre git-svn-id. Vous devriez mme y ajouter un crochet prereceive qui vrie la prsence de git-svn-id dans chaque message de validation et
rejee les remontes dont un des commits nen contiendrait pas.
Si vous suivez ces principes, le travail avec un serveur Subversion peut tre supportable. Cependant,
si le basculement sur un vrai serveur Git est possible, votre quipe y gagnera beaucoup.
213

Chapitre 8 Git et les autres systmes

Sco Chacon Pro Git

8.2 Migrer sur Git


Si vous avez une base de code dans un autre VCS et que vous avez dcid dutiliser Git, vous
devez migrer votre projet dune manire ou dune autre. Ce chapitre traite doutils dimport inclus
dans Git avec des systmes communs et dmontre comment dvelopper votre propre outil.

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 :

schacon = Scott Chacon <schacon@geemail.com>


selse = Someo Nelse <selse@geemail.com>

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

Sco Chacon Pro Git

Section 8.2 Migrer sur Git

$ git-svn clone http://mon-projet.googlecode.com/svn/ \


--authors-file=users.txt --no-metadata -s my_project

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:

Sun May 3 00:12:22 2009 +0000

fixed install - go to trunk


git-svn-id: https://my-project.googlecode.com/svn/trunk@94 4c93b258-373f-11debe05-5f7a86268029

les commits ressemblent ceci :

commit 03a8785f44c8ea5cdb0e8834b7c8e6c469be2ff2
Author: Scott Chacon <schacon@geemail.com>
Date:

Sun May 3 00:12:22 2009 +0000

fixed install - go to trunk

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

$ cp -Rf .git/refs/remotes/tags/* .git/refs/tags/


$ rm -Rf .git/refs/remotes/tags

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 :

$ cp -Rf .git/refs/remotes/* .git/refs/heads/


$ rm -Rf .git/refs/remotes

215

Chapitre 8 Git et les autres systmes

Sco Chacon Pro Git

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 :

$ git push origin --all

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 :

$ git clone git://git.kernel.org/pub/scm/git/git.git


$ cd git/contrib/fast-import

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 :

$ git-p4 clone //public/jam/src@all /opt/p4import


Importing from //public/jam/src@all into /opt/p4import
Reinitialized existing Git repository in /opt/p4import/.git/
Import destination: refs/remotes/p4/master
Importing revision 4409 (100%)

Si vous vous rendez dans le rpertoire /opt/p4import et lancez la commande git log,
vous pouvez examiner votre projet import :

216

Sco Chacon Pro Git

Section 8.2 Migrer sur Git

$ git log -2
commit 1fd4ec126171790efd2db83548b85b1bbbc07dc2
Author: Perforce staff <support@perforce.com>
Date:

Thu Aug 19 10:18:45 2004 -0800

Drop 'rc3' moniker of jam-2.5.

Folded rc2 and rc3 RELNOTES into

the main part of the document.

Built new tar/zip balls.

Only 16 months later.


[git-p4: depot-paths = "//public/jam/src/": change = 4409]
commit ca8870db541a23ed867f38847eda65bf4363371d
Author: Richard Geiger <rmg@perforce.com>
Date:

Tue Apr 22 20:51:34 2003 -0800

Update derived jamgram.c


[git-p4: depot-paths = "//public/jam/src/": change = 3108]

Vous pouvez visualiser lidentiant git-p4 de chaque commit. Il ny a pas de problme


garder cet identiant ici, au cas o vous auriez besoin de rfrencer dans lavenir le numro de modication Perforce. Cependant, si vous souhaitez supprimer lidentiant, cest le bon moment, avant
de commencer travailler avec le nouveau dpt. Vous pouvez utiliser git filter-branch
pour faire une retrait en masse des chanes didentiant :

$ git filter-branch --msg-filter '


sed -e "/^\[git-p4:/d"
'
Rewrite 1fd4ec126171790efd2db83548b85b1bbbc07dc2 (123/123)
Ref 'refs/heads/master' was rewritten

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:

Thu Aug 19 10:18:45 2004 -0800

Drop 'rc3' moniker of jam-2.5.

Folded rc2 and rc3 RELNOTES into

the main part of the document.

Built new tar/zip balls.

Only 16 months later.


commit 2b6c6db311dd76c34c66ec1c40a49405e6b527b2
Author: Richard Geiger <rmg@perforce.com>
Date:

Tue Apr 22 20:51:34 2003 -0800

217

Chapitre 8 Git et les autres systmes

Sco Chacon Pro Git

Update derived jamgram.c

Votre import est n prt pour tre pouss sur un nouveau serveur Git.

8.2.4 Un outil dimport personnalis


Si votre systme nest ni Subversion, ni Perforce, vous devriez rechercher sur Internet un outil
dimport spcique il en existe de bonne qualit pour CVS, Clear Case, Visual Source Safe ou
mme pour un rpertoire darchives. Si aucun de ses outils ne fonctionne pour votre cas, que vous
ayez un outil plus rare ou que vous ayez besoin dun mode dimport personnalis, git fastimport peut tre la solution. Cee commande lit de simples instructions sur stdin pour crire les
donnes spciques Git. Cest tout de mme plus simple pour crer les objets Git que de devoir
utiliser les commandes Git brutes ou dessayer dcrire directement les objets (voir Chapitre 9 pour
plus dinformation). De cee faon, vous crivez un script dimport qui lit les informations ncessaires depuis le systme dorigine et ache des instructions directes sur stdout. Vous pouvez alors
simplement lancer ce programme et rediriger sa sortie dans git fast-import.
Pour dmontrer rapidement cee fonctionnalit, nous allons crire un script simple dimport.
Supposons que vous travailliez dans en_cours et que vous fassiez des sauvegardes de temps en
temps dans des rpertoires nomms avec la date back_AAAA_MM_JJ et que vous souhaitiez importer ceci dans Git. Votre structure de rpertoire ressemble ceci :

$ 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

Sco Chacon Pro Git

Section 8.2 Migrer sur Git

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)

o convert_dir_to_date est dni comme

219

Chapitre 8 Git et les autres systmes

Sco Chacon Pro Git

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 :

$author = 'Scott Chacon <schacon@example.com>'

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 :

# print the import information


puts 'commit refs/heads/master'
puts 'mark :' + mark
puts "committer #{$author} #{date} -0700"
export_data('imported from ' + dir)
puts 'from :' + last_mark if last_mark

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

Sco Chacon Pro Git

Section 8.2 Migrer sur Git

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 :

M 644 inline chemin/du/fichier


data (taille)
(contenu du fichier)

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 :

def inline_data(file, code = 'M', mode = '644')


content = File.read(file)
puts "#{code} #{mode} inline #{file}"
export_data(content)
end

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

Chapitre 8 Git et les autres systmes

Sco Chacon Pro Git

$stdout.binmode

Et voil. Si vous lancez ce script, vous obtiendrez un contenu qui ressemble ceci :

$ ruby import.rb /opt/import_from


commit refs/heads/master
mark :1
committer Scott Chacon <schacon@geemail.com> 1230883200 -0700
data 29
imported from back_2009_01_02deleteall
M 644 inline file.rb
data 12
version two
commit refs/heads/master
mark :2
committer Scott Chacon <schacon@geemail.com> 1231056000 -0700
data 29
imported from back_2009_01_04from :1
deleteall
M 644 inline file.rb
data 14
version three
M 644 inline new.rb
data 16
new version one
(...)

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

Sco Chacon Pro Git

Section 8.3 Rsum

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:

Sun May 3 12:57:39 2009 -0700

imported from en_cours


commit 7e519590de754d079dd73b44d695a42c9d2df452
Author: Scott Chacon <schacon@example.com>
Date:

Tue Feb 3 01:00:00 2009 -0700

imported from back_2009_02_03

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

Les trippes de Git


Vous tes peut-tre arriv ce chapitre en en sautant certains ou aprs avoir parcouru tout
le reste du livre. Dans tous les cas, cest ici que lon parle du fonctionnement interne et de la mise
en uvre de Git. Pour moi, leur apprentissage a t fondamental pour comprendre quel point Git
est utile et puissant, mais dautres soutiennent que cela peut tre source de confusion et tre trop
complexe pour les dbutants. Jen ai donc fait le dernier chapitre de ce livre pour que vous puissiez
le lire tt ou tard lors de votre apprentissage. Je vous laisse le choix.
Maintenant que vous tes ici, commenons. Tout dabord, et mme si ce nest pas clair tout de
suite, Git est fondamentalement un systme de chiers adressables par contenu (content-addressable
lesystem) avec linterface utilisateur dun VCS au-dessus. Vous en apprendrez plus ce sujet dans
quelques instants.
Aux premiers jours de Git (surtout avant la version 1.5), linterface utilisateur tait beaucoup
plus complexe, car elle tait centre sur le systme de chier plutt que sur laspect VCS. Ces
dernires annes, linterface utilisateur a t peaune jusqu devenir aussi cohrente et facile
utiliser que nimporte quel autre systme. Pour beaucoup, limage du Git des dbut avec son interface utilisateur complexe et dicile apprendre est toujours prsente. La couche systme de
chiers adressables par contenu est vraiment gniale et jen parlerai dans ce chapitre. Ensuite, vous
apprendrez les mcanismes de transport/transmission/communication ainsi que les tches que vous
serez amenes faire pour maintenir un dpt.

9.1 Plomberie et porcelaine


Ce livre couvre lutilisation de Git avec une trentaine de verbes comme checkout, branch,
remote Mais, puisque Git tait initialement une bote outils (N.d.T : Toolkit) pour VCS, plutt
dun VCS complet et conviviale, il dispose de tout un ensemble daction pour les tches bas niveau
qui taient conues pour tre lies la UNIX ou appeles depuis de scripts. Ces commandes sont
dites commandes de plomberie (N.d.T plumbing ), et les autres, plus conviviales sont appeles
porcelaines (N.d.T : porcelain ).
Les huit premiers chapitres du livre concernent presque exclusivement les commandes porcelaine. Par contre, dans ce chapitre, vous serez principalement confronts aux commandes de plomberie
bas niveaux, car elles vous donnent accs au fonctionnement interne de Git et aident montrer
comment et pourquoi Git fonctionne comme il le fait. Ces commandes ne sont pas faites pour tre
utilises la main sur ligne de commandes, mais sont plutt utilises comme briques de bases pour
crire de nouveaux outils et scripts personnaliss.
225

Chapitre 9 Les trippes de Git

Sco Chacon Pro Git

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.

9.2 Les objets Git


Git est un systme de chier adressables par contenu. Super! Mais quest-ce que a veut dire?
a veut dire que le cur de Git est une simple base de paire clef/valeur. Vous pouvez y insrer
nimporte quelle sorte de donnes, et il vous retournera une cl que vous pourrez utiliser nimporte
quel moment pour rcuprer ces donnes nouveau. Pour illustrer cela, vous pouvez utiliser la
commande de plomberie hash-object, qui prend des donnes, les stocke dans votre rpertoire
.git, puis retourne la cl sous laquelle les donnes sont stockes. Tout dabord, crez un nouveau
dpt Git et vrier que rien ne se trouve dans le rpertoire object :

$ mkdir test
$ cd test
$ git init
Initialized empty Git repository in /tmp/test/.git/
$ find .git/objects

226

Sco Chacon Pro Git

Section 9.2 Les objets Git

.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
:

$ echo 'test content' | git hash-object -w --stdin


d670460b4b4aece5915caf5c68d12f560a9fe3e4

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 :

$ find .git/objects -type f


.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4

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 :

$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4


test content

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 :

$ echo 'version 1' > test.txt


$ git hash-object -w test.txt
83baae61804e65cc73a7201a7252750c76066a30

227

Chapitre 9 Les trippes de Git

Sco Chacon Pro Git

Puis, modiez le contenu du chier, et enregistrez le nouveau :

$ echo 'version 2' > test.txt


$ git hash-object -w test.txt
1f7a7a472abf3dd9643fd615f6da379c4acb3e3a

Votre base de donnes contient les 2 versions du chier, ainsi que le premier contenu que vous
avez stock ici :

$ find .git/objects -type f


.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4

Vous pouvez restaurer le chier sa premire version :

$ git cat-file -p 83baae61804e65cc73a7201a7252750c76066a30 > test.txt


$ cat test.txt
version 1

ou sa seconde version :

$ git cat-file -p 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a > test.txt


$ cat test.txt
version 2

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 :

$ git cat-file -t 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a


blob

9.2.1 Objets Arbre


Le prochain type que vous allez tudier est lobjet arbre (N.d.t tree), il est une solution au
problme de stockage dun groupe de chiers. Git stocke du contenu de la mme manire, mais plus
simplement, quun systme de chier UNIX. Tout le contenu est stock comme des objets de type
arbre ou blob : un arbre correspondant un rpertoire UNIX et un blob correspond peu prs un
i-noeud ou au contenu dun chier. Un unique arbre contient un ou plusieurs entres de type arbre,
chacune incluant un pointeur SHA-1 vers un blob, un sous-arbre (N.d.T sub-tree), ainsi que les droits
228

Sco Chacon Pro Git

Section 9.2 Les objets Git

daccs (N.d.t mode), le type et le nom de chier. Larbre le plus rcent du projet simplegit pourrai
ressembler, par exemple ceci :

$ git cat-file -p master^{tree}


100644 blob a906cb2a4a904a152e80877d4088654daad0c859

README

100644 blob 8f94139338f9404f26296befa88755fc2598c289

Rakefile

040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0

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 :

$ git cat-file -p 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0


100644 blob 47c6340d6459e05787f644c2447d2595f5d3a54b

simplegit.rb

Conceptuellement, les donnes que Git stocke ressemblent la Figure 9.1.

Figure 9.1: Une version simple du modle de donnes Git.

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 :

$ git update-index --add --cacheinfo 100644 \


83baae61804e65cc73a7201a7252750c76066a30 test.txt

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

Chapitre 9 Les trippes de Git

Sco Chacon Pro Git

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 pouvez galement vrier que cest un objet arbre :

$ git cat-file -t d8329fc1cc938780ffdd9f94e0d364e0ea74f579


tree

Vous allez crer maintenant un nouvel arbre avec la seconde version de test.txt et un nouveau
chier :

$ echo 'new file' > new.txt


$ git update-index test.txt
$ git update-index --add new.txt

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

100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a

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

Sco Chacon Pro Git

Section 9.2 Les objets Git

$ git read-tree --prefix=bak d8329fc1cc938780ffdd9f94e0d364e0ea74f579


$ git write-tree
3c4e9cd789d88d8d89c1073707c3585e41b0e614
$ git cat-file -p 3c4e9cd789d88d8d89c1073707c3585e41b0e614
040000 tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579

bak

100644 blob fa49b077972391ad58037050f2a75f74e3671e92

new.txt

100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a

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.

Figure 9.2: Structure des donnes actuelles de Git?.

9.2.2 Objets Commit


Vous avez trois arbres qui dnissent dirents instantans du projet que vous suivez, mais
certains problmes persistent : vous devez vous souvenir des valeurs des trois empreintes SHA1 pour accder aux instantans. Vous navez pas non plus dinformation sur qui a enregistr les
instantans, quand et pourquoi. Ce sont les informations lmentaires quun objet commit stocke
pour vous.
Pour crer un objet commit, il sut dexcuter commit-tree, de prciser lempreinte SHA-1
et quel objet commit, sil y en a, le prcde directement. Commencez avec le premier arbre que vous
avez cr :

$ echo 'first commit' | git commit-tree d8329f


fdf4fc3344e67ab068f836878b6c4951e3b15f3d

Vous pouvez voir votre nouvel objet commit avec cat-file :

$ git cat-file -p fdf4fc3


tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579

231

Chapitre 9 Les trippes de Git

Sco Chacon Pro Git

author Scott Chacon <schacon@gmail.com> 1243040974 -0700


committer Scott Chacon <schacon@gmail.com> 1243040974 -0700
first commit

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 :

$ echo 'second commit' | git commit-tree 0155eb -p fdf4fc3


cac0cab538b970a37ea1e769cbbde608743bc96d
$ echo 'third commit'

| git commit-tree 3c4e9c -p cac0cab

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 :

$ git log --stat 1a410e


commit 1a410efbd13591db07496601ebc7a059dd55cfe9
Author: Scott Chacon <schacon@gmail.com>
Date:

Fri May 22 18:15:24 2009 -0700

third commit
bak/test.txt |

1 +

1 files changed, 1 insertions(+), 0 deletions(-)


commit cac0cab538b970a37ea1e769cbbde608743bc96d
Author: Scott Chacon <schacon@gmail.com>
Date:

Fri May 22 18:14:29 2009 -0700

second commit
new.txt

test.txt |

1 +
2 +-

2 files changed, 2 insertions(+), 1 deletions(-)


commit fdf4fc3344e67ab068f836878b6c4951e3b15f3d
Author: Scott Chacon <schacon@gmail.com>
Date:

Fri May 22 18:09:34 2009 -0700

first commit
test.txt |

1 +

1 files changed, 1 insertions(+), 0 deletions(-)

232

Sco Chacon Pro Git

Section 9.2 Les objets Git

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 :

$ find .git/objects -type f


.git/objects/01/55eb4229851634a0f03eb265b69f5a2d56f341 # tree 2
.git/objects/1a/410efbd13591db07496601ebc7a059dd55cfe9 # commit 3
.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a # test.txt v2
.git/objects/3c/4e9cd789d88d8d89c1073707c3585e41b0e614 # tree 3
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txt v1
.git/objects/ca/c0cab538b970a37ea1e769cbbde608743bc96d # commit 2
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 # 'test content'
.git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579 # tree 1
.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 # new.txt
.git/objects/fd/f4fc3344e67ab068f836878b6c4951e3b15f3d # commit 1

Si vous suivez les pointeurs internes de ces objets, vous obtenez un graphe comme celui de la
Figure 9.3.

Figure 9.3: Tous les objets de votre rpertoire Git.

9.2.3 Stoage des objets


On a parl plus tt de len-tte prsent avec le contenu. Prenons un moment pour tudier la
faon dont Git stocke les objets. On verra comment stocker interactivement un objet Blob (ici, la
chane what is up, doc? ) avec le langage Ruby. Vous pouvez dmarrer Ruby en mode interactif
avec la commande irb :
$ irb
>> content = "what is up, doc?"
=> "what is up, doc?"

233

Chapitre 9 Les trippes de Git

Sco Chacon Pro Git

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 :

>> header = "blob #{content.length}\0"


=> "blob 16\000"

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 :

>> store = header + content


=> "blob 16\000what is up, doc?"
>> require 'digest/sha1'
=> true
>> sha1 = Digest::SHA1.hexdigest(store)
=> "bd9dbf5aae1a3862dd1526723246b20206e5fc37"

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 :

>> require 'zlib'


=> true
>> zlib_content = Zlib::Deflate.deflate(store)
=> "x\234K\312\311OR04c(\317H,Q\310,V(-\320QH\311O\266\a\000_\034\a\235"

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 :

>> path = '.git/objects/' + sha1[0,2] + '/' + sha1[2,38]


=> ".git/objects/bd/9dbf5aae1a3862dd1526723246b20206e5fc37"
>> require 'fileutils'
=> true
>> FileUtils.mkdir_p(File.dirname(path))
=> ".git/objects/bd"
>> File.open(path, 'w') { |f| f.write zlib_content }
=> 32

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

Sco Chacon Pro Git

Section 9.3 Rfrences Git

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.

9.3 Rfrences Git


On peut excuter quelque chose comme git log 1a410e pour visualiser tout lhistorique,
mais il faut se souvenir que 1a410e est le dernier commit an de parcourir lhistorique et trouver
tous ces objets. Vous avez besoin dun chier ayant un nom simple qui contient lempreinte SHA-1
an dutiliser ce pointeur plutt que lempreinte SHA-1 elle-mme.
Git appelle ces pointeur des rfrences , ou refs . On trouve les chiers contenant des
empreintes SHA-1 dans le rpertoire git/refs. Dans le projet actuel, ce rpertoire ne contient
aucun chier, mais possde une structure simple :

$ 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 :

$ echo "1a410efbd13591db07496601ebc7a059dd55cfe9" > .git/refs/heads/master

Vous pouvez maintenant utiliser la rfrence principale que vous venez de crer la place de
lempreinte SHA-1 dans vos commandes Git :

$ git log --pretty=oneline

master

1a410efbd13591db07496601ebc7a059dd55cfe9 third commit


cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit

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 :

$ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9

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

Chapitre 9 Les trippes de Git

Sco Chacon Pro Git

$ git update-ref refs/heads/test cac0ca

Cee branche contiendra seulement le travail eectu jusqu ce commit :

$ git log --pretty=oneline test


cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit

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.

and on excute un commande comme git branch (nomdebranche), Git excute


simplement la commande update-ref pour ajouter lempreinte SHA-1 du dernier commit dans
la rfrence que lon veut crer.

9.3.1 La brane HEAD


On peut se poser la question : Comment Git peut avoir connaissance de lempreinte SHA-1 du
dernier commit quand on excute git branch (branchname) ? La rponse est dans le chier
HEAD (qui veut dire tte en franais, soit, ici, ltat courant). Le chier HEAD est une rfrence
symbolique la branche courante. Par rfrence symbolique, jentends que contrairement une
rfrence normale, elle ne contient pas une empreinte SHA-1, mais plutt un pointeur vers une
autre rfrence. Si vous regardez ce chier, vous devriez voir quelque chose comme ceci :

$ 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

Sco Chacon Pro Git

Section 9.3 Rfrences Git

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 :

$ git symbolic-ref HEAD


refs/heads/master

Vous pouvez aussi initialiser la valeur de HEAD :

$ git symbolic-ref HEAD refs/heads/test


$ cat .git/HEAD
ref: refs/heads/test

Vous ne pouvez pas initialiser une rfrence symbolique une valeur non contenu dans refs :

$ git symbolic-ref HEAD test


fatal: Refusing to point HEAD outside of 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 :

$ git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d

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) :

$ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 m 'test tag'

Voici lempreinte SHA-1 de lobjet cr :


237

Chapitre 9 Les trippes de Git

Sco Chacon Pro Git

$ cat .git/refs/tags/v1.1
9585191f37f7b0fb9444f35a9bf50de191beadc2

Excutez ensuite, la commande cat-file sur lempreinte SHA-1 :

$ git cat-file -p 9585191f37f7b0fb9444f35a9bf50de191beadc2


object 1a410efbd13591db07496601ebc7a059dd55cfe9
type commit
tag v1.1
tagger Scott Chacon <schacon@gmail.com> Sat May 23 16:48:58 2009 -0700
test tag

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 :

$ git cat-file blob junio-gpg-pub

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.

9.3.3 Rfrences distantes


Le troisime type de rfrences que lon tudiera sont les rfrences distantes (N.d.T remotes).
Si lon ajoute une rfrence distante et que lon pousse des objets vers elle, Git stocke la valeur que
vous avez pouss en dernire vers cee rfrence pour chaque branche dans le rpertoire refs/
remotes. Vous pouvez par exemple, ajouter une rfrence distante nomme origin et y pousser
votre branche master :

$ git remote add origin git@github.com:schacon/simplegit-progit.git


$ git push origin master
Counting objects: 11, done.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (7/7), 716 bytes, done.
Total 7 (delta 2), reused 4 (delta 1)
To git@github.com:schacon/simplegit-progit.git
a11bef0..ca82a6d

master -> master

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

Sco Chacon Pro Git

Section 9.4 Fichiers groups

$ 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.

9.4 Fiiers groups


Revenons la base de donne dobjet de notre dpt Git de test. Pour linstant, il contient 11
objets : 4 blobs, 3 arbres, 3 commits, et 1 tag :

$ find .git/objects -type f


.git/objects/01/55eb4229851634a0f03eb265b69f5a2d56f341 # arbre 2
.git/objects/1a/410efbd13591db07496601ebc7a059dd55cfe9 # commit 3
.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a # test.txt v2
.git/objects/3c/4e9cd789d88d8d89c1073707c3585e41b0e614 # arbre 3
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txt v1
.git/objects/95/85191f37f7b0fb9444f35a9bf50de191beadc2 # tag
.git/objects/ca/c0cab538b970a37ea1e769cbbde608743bc96d # commit 2
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 # 'test content'
.git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579 # arbre 1
.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 # new.txt
.git/objects/fd/f4fc3344e67ab068f836878b6c4951e3b15f3d # commit 1

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 :

$ curl http://github.com/mojombo/grit/raw/master/lib/grit/repo.rb > repo.rb


$ git add repo.rb
$ git commit -m 'added repo.rb'
[master 484a592] added repo.rb
3 files changed, 459 insertions(+), 2 deletions(-)
delete mode 100644 bak/test.txt
create mode 100644 repo.rb
rewrite test.txt (100%)

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

100644 blob 9bc1dc421dcd51b4ac296e3e5b6e2a99cf44391e

repo.rb

100644 blob e3f094f522629ae358806b17daf78246c27c007b

test.txt

239

Chapitre 9 Les trippes de Git

Sco Chacon Pro Git

Vous pouvez utilisez git cat-file pour connaitre la taille de lobjet :

$ git cat-file -s 9bc1dc421dcd51b4ac296e3e5b6e2a99cf44391e


12898

Maintenant, modiez le chier un peu, et voyez ce qui arrive :

$ echo '# testing' >> repo.rb


$ git commit -am 'modified repo a bit'
[master ab1afef] modified repo a bit
1 files changed, 1 insertions(+), 0 deletions(-)

Regardez larbre cr par ce commit, et vous verrez quelque chose dintressant :

$ git cat-file -p master^{tree}


100644 blob fa49b077972391ad58037050f2a75f74e3671e92

new.txt

100644 blob 05408d195263d853f09dca71d55116663690c27c

repo.rb

100644 blob e3f094f522629ae358806b17daf78246c27c007b

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 :

$ git cat-file -s 05408d195263d853f09dca71d55116663690c27c


12908

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

Sco Chacon Pro Git

Section 9.4 Fichiers groups

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 :

$ find .git/objects -type f


.git/objects/71/08f7ecb345ee9d0084193f147cdad4d2998293
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
.git/objects/info/packs
.git/objects/pack/pack-7a16e4488ae40c7d2bc56ea2bd43e25212a66c45.idx
.git/objects/pack/pack-7a16e4488ae40c7d2bc56ea2bd43e25212a66c45.pack

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

12908 3478 874

09f01cea547666f58d6a8d809583841a7c6f0130 tree

106 107 5086

1a410efbd13591db07496601ebc7a059dd55cfe9 commit 225 151 322


1f7a7a472abf3dd9643fd615f6da379c4acb3e3a blob

10 19 5381

3c4e9cd789d88d8d89c1073707c3585e41b0e614 tree

101 105 5211

484a59275031909e19aadb7c92262719cfcdf19a commit 226 153 169


83baae61804e65cc73a7201a7252750c76066a30 blob

10 19 5362

9585191f37f7b0fb9444f35a9bf50de191beadc2 tag

136 127 5476

9bc1dc421dcd51b4ac296e3e5b6e2a99cf44391e blob

7 18 5193 1

05408d195263d853f09dca71d55116663690c27c \
ab1afef80fac8e34258ff41fc1b867c702daa24b commit 232 157 12
cac0cab538b970a37ea1e769cbbde608743bc96d commit 226 154 473
d8329fc1cc938780ffdd9f94e0d364e0ea74f579 tree

36 46 5316

e3f094f522629ae358806b17daf78246c27c007b blob

1486 734 4352

f8f51d7d8a1760462eca26eebafde32087499533 tree

106 107 749

fa49b077972391ad58037050f2a75f74e3671e92 blob

9 18 856

fdf4fc3344e67ab068f836878b6c4951e3b15f3d commit 177 122 627


chain length = 1: 1 object
pack-7a16e4488ae40c7d2bc56ea2bd43e25212a66c45.pack: ok

Si on se souvient bien, le blob 9bc1d, qui est la premire version de chier repo.rb le,
241

Chapitre 9 Les trippes de Git

Sco Chacon Pro Git

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.

9.5 Les rfrences spciques


Dans tout le livre, nous avons utilis des associations simples entre les branches distantes et les
rfrences locales. Elles peuvent tre plus complexes. Supposons que vous ajoutiez un dpt distant
comme ceci :

$ git remote add origin git@github.com:schacon/simplegit-progit.git

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/*

Le format dune spcication de rfrence est un + facultatif, suivi de <src>:<dst>, o


<src> est le motif des rfrences du ct distant, et <dst> est lemplacement local o les rfrences
seront enregistres. Le + prcise Git de mere jour la rfrence mme si ce nest pas un avance
rapide.
Dans le cas par dfaut, qui est celui dun enregistrement automatique par la commande git
remote add, Git rcupre toutes les rfrences de refs/heads/ sur le serveur et les enregistre
localement dans refs/remotes/origin/. Ainsi, sil y a une branche master sur le serveur,
vous pouvez accder localement lhistorique de cee branche via :

$ git log origin/master


$ git log remotes/origin/master
$ git log refs/remotes/origin/master

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

Sco Chacon Pro Git

Section 9.5 Les rfrences spciques

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 :

$ git fetch origin master:refs/remotes/origin/mymaster

Vous pouvez indiquer des spcications pour plusieurs rfrences. En ligne de commande, vous
pouvez tirer plusieurs branches de cee faon :

$ git fetch origin master:refs/remotes/origin/mymaster \


topic:refs/remotes/origin/topic
From git@github.com:schacon/simplegit
! [rejected]

master

-> origin/mymaster

* [new branch]

topic

-> origin/topic

(non fast forward)

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

Chapitre 9 Les trippes de Git

Sco Chacon Pro Git

[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.

9.5.1 Publier une rfrence spcique


Il est pratique de pouvoir rcuprer des rfrences issues despace de nom de cee faon, mais
comment lquipe qualit insre-t-elle ces branches dans lespace de nom qa/ en premier lieu ? On
peut accomplir cela en utilisant les spcication de rfrences pour la publication.
Si lquipe qualit veut publier sa branche master vers qa/master sur le serveur distant,
elle peut excuter :

$ git push origin master:refs/heads/qa/master

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.

9.5.2 Supprimer des rfrences


Vous pouvez aussi utiliser les spcications de rfrences pour supprimer des rfrences sur le
serveur distant en excutant une commande comme :

$ git push origin :topic

La spcication de rfrence ressemble <src>:<dst>, mais en laissant vide la partie <src>,


cela signie de crer la branche partir de rien, et donc la supprime.

9.6 Protocoles de transfert


Git peut transfrer des donnes entre deux dpts, de deux faons principales : via HTTP et
via un protocole dit intelligent utilis par les transports /trouver mieux/ file://, ssh:// et
244

Sco Chacon Pro Git

Section 9.6 Protocoles de transfert

git://. Cee section fait un tour dhorizon du fonctionnement de ces deux protocoles.

9.6.1 Le protocole stupide


On parle souvent du transfert Git sur HTTP comme tant un protocole stupide, car il ne ncessite aucun code spcique Git ct serveur durant le transfert. Le processus de rcupration
est une srie de requte GET, o le client devine la structure du dpt Git prsent sur le serveur.
Suivons le processus http-fetch pour la bibliothque simplegit :

$ git clone http://github.com/schacon/simplegit-progit.git

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 :

=> GET info/refs


ca82a6dff817ec66f44342007202690a93763949

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 :

=> GET HEAD


ref: refs/heads/master

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 :

=> GET objects/ca/82a6dff817ec66f44342007202690a93763949


(179 bytes of binary data)

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 :

$ git cat-file -p ca82a6dff817ec66f44342007202690a93763949


tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf
parent 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
author Scott Chacon <schacon@gmail.com> 1205815931 -0700
committer Scott Chacon <schacon@gmail.com> 1240030591 -0700
changed the version number

245

Chapitre 9 Les trippes de Git

Sco Chacon Pro Git

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 :

=> GET objects/08/5bb3bcb608e1e8451d4b2432f8ecbe6306e7e7


(179 bytes of data)

Cela vous donne lobjet du prochain commit. Rcuprez lobjet arbre :

=> GET objects/cf/da3bf379e4f8dba8717dee55aab78aef7f4daf


(404 - Not Found)

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 :

=> GET objects/info/http-alternates


(empty file)

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) :

=> GET objects/info/packs


P pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack

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 :

=> GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.idx


(4k of binary data)

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

Sco Chacon Pro Git

Section 9.6 Protocoles de transfert

=> GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack


(13k of binary data)

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 :

$ git clone http://github.com/schacon/simplegit-progit.git


Initialized empty Git repository in /private/tmp/simplegit-progit/.git/
got ca82a6dff817ec66f44342007202690a93763949
walk ca82a6dff817ec66f44342007202690a93763949
got 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Getting alternates list for http://github.com/schacon/simplegit-progit.git
Getting pack list for http://github.com/schacon/simplegit-progit.git
Getting index for pack 816a9b2334da9953e530f27bcac22082a9f5b835
Getting pack 816a9b2334da9953e530f27bcac22082a9f5b835
which contains cfda3bf379e4f8dba8717dee55aab78aef7f4daf
walk 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
walk a11bef06a3f659402fe7563abf99ad00de2209e6

9.6.2 Le Protocole Intelligent


La mthode HTTP est simple mais un peu inecace. Utiliser des protocoles intelligents est
une mhode plus habituelles pour transfrer des donnes. Ces protocoles ont un excutable du ct
distant qui connait Git, il peut lire les donnes locales et deviner ce que le client a ou ce quil a
besoin pour gnrer des donnes personnalises pour lui. Il y a deux ensembles dexcutables pour
transfrer les donnes : une paire pour tlverser des donnes et une paire pour en tlcharger.
Tlverser des donnes
Pour tlverser des donnes vers un excutable distant, Git utilise les excutables send-pack
et receive-pack. Lexcutable send-pack tourne sur le client et se connecte lexcutable
receive-pack du ct serveur.
Par exemple, disons que vous excutez git push origin master dans votre projet, et
origin est dni comme une URL qui utilise le protocole SSH. Git appelle lexcutable sendpack, qui initialise une connexion travers SSH vers votre serveur. Il essaye dexcuter une commande sur le serveur distant via un appel SSH qui ressemble :

$ ssh -x git@github.com "git-receive-pack 'schacon/simplegit-progit.git'"


005bca82a6dff817ec66f4437202690a93763949 refs/heads/master report-status delete-refs
003e085bb3bcb608e1e84b2432f8ecbe6306e7e7 refs/heads/topic
0000

247

Chapitre 9 Les trippes de Git

Sco Chacon Pro Git

La commande git-receive-pack rpond immdiatement avec une ligne pour chaque


rfrence quelle connait actuellement, dans ce cas, uniquement la branche master et ses empreintes SHA. La premire ligne contient galement une liste des comptences du serveur (ici :
report-status et delete-refs).
Chaque ligne commence avec une valeur hexadcimale sur 4 octets, spciant le reste de la
longueur de la ligne. La premire ligne, ici, commence avec 005b, soit 91 en hexadcimal, ce qui
signie quil y a 91 octets restants sur cee ligne La ligne suivante commence avec 003e, soit 62,
vous lisez donc les 62 octets restants. La ligne daprs est 0000, signiant que le serveur a ni de
lister ses rfrences.
Maintenant que vous connaissez ltat du serveur, votre excutable send-pack dtermine
quels commits il a que le serveur na pas. Lexcutable send-pack envoit alors lexcutable
receive-pack, les informations concernant chaque rfrence que cee commande push va
mere jour. Par exemple, si vous meez jour la branche master et ajoutez la branche experiment, la rponse de send-pack ressemblera quelque chose comme :

0085ca82a6dff817ec66f44342007202690a93763949 15027957951b64cf874c3557a0f3547bd83b3ff6 refs/


heads/master report-status
00670000000000000000000000000000000000000000 cdfdb42577e2506715f8cfeacdbabc092bf63e8d refs/
heads/experiment
0000

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

Tlarger des Donnes


Lorsque vous tlcharger des donnes, les excutables fetch-pack et upload-pack entrent en jeu. Le client initialise un excutable fetch-pack qui se connecte un excutable uploadpack du ct serveur pour ngocier quelles donnes seront remontes.
Il y a plusieurs manires dinitialiser lexcutable upload-pack sur le dpt distant. Vous
pouvez passer par SSH de la mme manire quavec lexcutable receive-pack. Vous pouvez
galement initialiser lexcutable travers le dmon Git, qui coute sur le port 9418 du serveur par
dfaut. Lexcutable fetch-pack envoit des donnes qui ressemble cela juste aprs la connexion
:

003fgit-upload-pack schacon/simplegit-progit.git\0host=myserver.com\0

248

Sco Chacon Pro Git

Section 9.7 Maintenance et Rcupration de Donnes

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 :

$ ssh -x git@github.com "git-upload-pack 'schacon/simplegit-progit.git'"

Dans tous les cas, aprs que fetch-pack se connecte, upload-pack lui rpond quelque
chose du style :

0088ca82a6dff817ec66f44342007202690a93763949 HEAD\0multi_ack thin-pack \


side-band side-band-64k ofs-delta shallow no-progress include-tag
003fca82a6dff817ec66f44342007202690a93763949 refs/heads/master
003e085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 refs/heads/topic
0000

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 :

0054want ca82a6dff817ec66f44342007202690a93763949 ofs-delta


0032have 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
0000
0009done

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 Maintenance et Rcupration de Donnes


Parfois, vous aurez besoin de faire un peu de mnage : faire un dpt plus compact, neoyer
les dpts imports, ou rcuprer du travail perdu. Cee section couvrira certains de ces scenarii.

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

Chapitre 9 Les trippes de Git

Sco Chacon Pro Git

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 :

$ find .git/refs -type f


.git/refs/heads/experiment
.git/refs/heads/master
.git/refs/tags/v1.0
.git/refs/tags/v1.1

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.

9.7.2 Rcupration de donnes


un moment quelconque de votre vie avec Git, vous pouvez accentillement perdre un commit.
Gnralement, cela arrive parce que vous avez forc la suppression dune branche contenant du tra250

Sco Chacon Pro Git

Section 9.7 Maintenance et Rcupration de Donnes

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 :

$ git log --pretty=oneline


ab1afef80fac8e34258ff41fc1b867c702daa24b modified repo a bit
484a59275031909e19aadb7c92262719cfcdf19a added repo.rb
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit

Maintenant, dplaons la branche master vers le commit du milieu :

$ git reset --hard 1a410efbd13591db07496601ebc7a059dd55cfe9


HEAD is now at 1a410ef third commit
$ git log --pretty=oneline
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit

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

Chapitre 9 Les trippes de Git

Sco Chacon Pro Git

$ git log -g
commit 1a410efbd13591db07496601ebc7a059dd55cfe9
Reflog: HEAD@{0} (Scott Chacon <schacon@gmail.com>)
Reflog message: updating HEAD
Author: Scott Chacon <schacon@gmail.com>
Date:

Fri May 22 18:22:37 2009 -0700

third commit
commit ab1afef80fac8e34258ff41fc1b867c702daa24b
Reflog: HEAD@{1} (Scott Chacon <schacon@gmail.com>)
Reflog message: updating HEAD
Author: Scott Chacon <schacon@gmail.com>
Date:

Fri May 22 18:15:24 2009 -0700


modified repo a bit

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):

$ git branch recover-branch ab1afef


$ git log --pretty=oneline recover-branch
ab1afef80fac8e34258ff41fc1b867c702daa24b modified repo a bit
484a59275031909e19aadb7c92262719cfcdf19a added repo.rb
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit

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) :

$ git branch D recover-branch


$ rm -Rf .git/logs/

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

Sco Chacon Pro Git

Section 9.7 Maintenance et Rcupration de Donnes

$ git fsck --full


dangling blob d670460b4b4aece5915caf5c68d12f560a9fe3e4
dangling commit ab1afef80fac8e34258ff41fc1b867c702daa24b
dangling tree aea790b9a58f6cf6f2804eeac9f0abbe9631e4c9
dangling blob 7108f7ecb345ee9d0084193f147cdad4d2998293

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.

9.7.3 Supprimer des objets


Il y a beaucoup de choses dans Git qui sont gniales, mais une fonctionnalit qui peut poser
problme est le fait que git clone tlcharge lhistorique entier du projet, incluant chaque version de chaque chier. Cest trs bien lorsque le tout est du code source, parce Git est hautement
optimis pour compresser les donnes ecacement. Cependant, si quelquun un moment donn
de lhistorique de votre projet a ajout un nome chier, chaque clone sera forc de tlcharger cet
norme chier, mme si il a t supprim du projet dans le commit suivant. Puisquil est accessible
depuis lhistorique, il sera toujours l.
Cela peut tre un norme problme, lorsque vous convertissez un dpt Subversion ou Perfoce en un dpt Git. Car, comme vous ne tlchargez pas lhistorique entier dans ces syst-mes, ce
genre dajout na que peu de consquences. Si vous avez import depuis un autre systme ou que
votre dpt est beaucoup plus gros que ce quil devrait tre, voici comment vous pouvez trouver et
supprimer des gros objets.
Soyez prvenu : cee technique dtruit votre historique de commit. Elle rcrit chaque objet
commit depuis le premier objet arbre que vous modiez pour supprimer une rfrence dun gros
chier. Si vous faites cela immdiatement aprs un import, avant que quiconque nait eu le temps de
commencer travailler sur ce commit, tout va bien. Sinon, vous devez alerter tous les contributeurs
quils doivent recommencer (ou au moins faire un rebase) sur votre nouveau commit.
Pour la dmonstration, nous allons ajouter un gros chier dans votre dpt de test, le supprimer
dans le commit suivant, le trouver, et le supprimer de manire permanente du dpt. Premirement,
ajoutons un gros objet votre historique :

$ curl http://kernel.org/pub/software/scm/git/git-1.6.3.1.tar.bz2 > git.tbz2


$ git add git.tbz2
$ git commit -am 'added git tarball'
[master 6df7640] added git tarball
1 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 git.tbz2

Oups, vous ne vouliez pas rajouter une norme archive votre projet. Il vaut mieux sen dbarrasser :

253

Chapitre 9 Les trippes de Git

Sco Chacon Pro Git

$ 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 :

$ git verify-pack -v .git/objects/pack/pack-3f8c0...bb.idx | sort -k 3 -n | tail -3


e3f094f522629ae358806b17daf78246c27c007b blob

1486 734 4667

05408d195263d853f09dca71d55116663690c27c blob

12908 3478 1189

7a9eb2fba2b1811321254ac360970fc169ba2330 blob

2056716 2056872 5401

254

Sco Chacon Pro Git

Section 9.7 Maintenance et Rcupration de Donnes

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 :

$ git rev-list --objects --all | grep 7a9eb2fb


7a9eb2fba2b1811321254ac360970fc169ba2330 git.tbz2

Maintenant, vous voulez supprimer ce chier de toutes les arborescences passes. Vous pouvez
facilement voir quels commits ont modi ce chier :

$ git log --pretty=oneline -- git.tbz2


da3f30d019005479c99eb4c3406225613985a1db oops - removed large tarball
6df764092f3e7c8f5f94cbe08ee5cf42e92a0289 added git tarball

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 :

$ git filter-branch --index-filter \


'git rm --cached --ignore-unmatch git.tbz2' -- 6df7640^..
Rewrite 6df764092f3e7c8f5f94cbe08ee5cf42e92a0289 (1/2)rm 'git.tbz2'
Rewrite da3f30d019005479c99eb4c3406225613985a1db (2/2)
Ref 'refs/heads/master' was rewritten

Loption --index-filter est similaire loption --tree-filter utilis dans le Chapitre


6, sauf quau lieu de modier les chiers sur le disk, vous modiez votre zone daente et votre index.
Plutt que de supprimer un chier spcique avec une commande comme rm file, vous devez le
supprimez avec git rm --cached; vous devez le supprimer de lindex, pas du disque. La raison
de faire cela de cee manire est la rapidit, car Git nayant pas besoin de rcuprer chaque rvision
sur disque avant votre ltre, la procdure peut tre beaucoup beaucoup plus rapide. Vous pouvez
faire la mme chose avec --tree-filter si vous voulez. Loption --ignore-unmatch de
git rm lui dit que ce nest pas une erreur si le motif que vous voulez supprimez nexiste pas.
Finalement, vous demandez filter-branch de rcrire votre historique seulement depuis le
parent du commit 6df7640, car vous savez que cest de l que le problme a commenc. Sinon, il
aurait dmarr du dbut, et serait plus long sans ncessit.
Votre historique ne contient plus de rfrence ce chier. Cependant, votre journal de rvision
et un nouvel ensemble de rfrence que Git a ajout lors de votre filter-branch dans .git/
refs/original en contiennent encore, vous devez donc les supprimer puis regrouper votre base
de donnes. Vous devez vous dbarrasser de tout ce qui se rfrence ces vieux commits avant de
regrouper :

255

Chapitre 9 Les trippes de Git

Sco Chacon Pro Git

$ 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)

Voyons combien despace vous avez rcupr :

$ 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

You might also like